def _parse_document(data, base_url=None): schema_url = base_url base_url = _get_document_base_url(data, base_url) info = _get_dict(data, 'info') title = _get_string(info, 'title') paths = _get_dict(data, 'paths') content = {} for path in paths.keys(): url = urlparse.urljoin(base_url, path.lstrip('/')) spec = _get_dict(paths, path) default_parameters = get_dicts(_get_list(spec, 'parameters')) for action in spec.keys(): action = action.lower() if action not in ('get', 'put', 'post', 'delete', 'options', 'head', 'patch'): continue operation = _get_dict(spec, action) # Determine any fields on the link. fields = [] parameters = get_dicts(_get_list(operation, 'parameters', default_parameters), dereference_using=data) for parameter in parameters: name = _get_string(parameter, 'name') location = _get_string(parameter, 'in') required = _get_bool(parameter, 'required', default=(location == 'path')) if location == 'body': schema = _get_dict(parameter, 'schema', dereference_using=data) expanded = _expand_schema(schema) if expanded is not None: expanded_fields = [ Field(name=field_name, location='form', required=is_required) for field_name, is_required in expanded if not any([field.name == name for field in fields]) ] fields += expanded_fields else: field = Field(name=name, location='body', required=True) fields.append(field) else: field = Field(name=name, location=location, required=required) fields.append(field) link = Link(url=url, action=action, fields=fields) # Add the link to the document content. tags = get_strings(_get_list(operation, 'tags')) operation_id = _get_string(operation, 'operationId') if tags: for tag in tags: if tag not in content: content[tag] = {} content[tag][operation_id] = link else: content[operation_id] = link return Document(url=schema_url, title=title, content=content)
def _get_content(data, base_url, ref): content = {} links = _get_list(data, 'links') properties = _get_dict(data, 'properties') if properties: for key, value in properties.items(): if not isinstance(value, dict): continue if list(value.keys()) == ['$ref']: value = _dereference(value['$ref'], ref) sub_content = _get_content(value, base_url, ref) if sub_content: content[key] = sub_content if links: for link in get_dicts(links): rel = _get_string(link, 'rel') if rel: href = _get_string(link, 'href') method = _get_string(link, 'method') schema = _get_dict(link, 'schema') schema_type = _get_list(schema, 'type') schema_properties = _get_dict(schema, 'properties') schema_required = _get_list(schema, 'required') fields = [] url = urlparse.urljoin(base_url, href) templated = uritemplate.variables(url) for item in templated: orig = item if item.startswith('(') and item.endswith(')'): item = urllib.unquote(item.strip('(').rstrip(')')) if item.startswith('#/'): components = [ component for component in item.strip('#/').split('/') if component != 'definitions' ] item = '_'.join(components).replace('-', '_') url = url.replace(orig, item) fields.append(Field(name=item, location='path', required=True)) if schema_type == ['object'] and schema_properties: fields += [ Field(name=key, required=key in schema_required) for key in schema_properties.keys() ] if rel == 'self': rel = 'read' content[rel] = Link(url=url, action=method, fields=fields) return content
def _primative_to_document(data, base_url=None): """ Take Python primatives as returned from parsing JSON content, and return a Core API document. """ if isinstance(data, dict) and data.get('_type') == 'document': # Document meta = _get_dict(data, '_meta') url = _get_string(meta, 'url') url = urlparse.urljoin(base_url, url) title = _get_string(meta, 'title') content = _get_content(data, base_url=url) return Document(url=url, title=title, content=content) if isinstance(data, dict) and data.get('_type') == 'error': # Error meta = _get_dict(data, '_meta') title = _get_string(meta, 'title') content = _get_content(data, base_url=base_url) return Error(title=title, content=content) elif isinstance(data, dict) and data.get('_type') == 'link': # Link url = _get_string(data, 'url') url = urlparse.urljoin(base_url, url) action = _get_string(data, 'action') inplace = _get_bool(data, 'inplace', default=None) fields = _get_list(data, 'fields') fields = [ Field( name=_get_string(item, 'name'), required=_get_bool(item, 'required'), location=_get_string(item, 'location') ) for item in fields if isinstance(item, dict) ] return Link(url=url, action=action, inplace=inplace, fields=fields) elif isinstance(data, dict): # Map content = _get_content(data, base_url=base_url) return Object(content) elif isinstance(data, list): # Array content = [_primative_to_document(item, base_url) for item in data] return Array(content) # String, Integer, Number, Boolean, null. return data
def _parse_document(data, base_url=None): links = _get_dict(data, '_links') embedded = _get_dict(data, '_embedded') self = _get_dict(links, 'self') url = _get_string(self, 'href') url = urlparse.urljoin(base_url, url) title = _get_string(self, 'title') content = {} for key, value in links.items(): if key in ('self', 'curies'): continue key = _map_to_coreapi_key(key) if isinstance(value, list): if value and 'name' in value[0]: # Lists of named links should be represented inside a map. content[key] = { item['name']: _parse_link(item, base_url) for item in value if 'name' in item } else: # Lists of named links should be represented inside a list. content[key] = [ _parse_link(item, base_url) for item in value ] elif isinstance(value, dict): # Single link instance. content[key] = _parse_link(value, base_url) # Embedded resources. for key, value in embedded.items(): key = _map_to_coreapi_key(key) if isinstance(value, list): content[key] = [_parse_document(item, base_url=url) for item in value] elif isinstance(value, dict): content[key] = _parse_document(value, base_url=url) # Data. for key, value in data.items(): if key not in ('_embedded', '_links'): content[key] = value return Document(url, title, content)
def _expand_schema(schema): """ When an OpenAPI parameter uses `in="body"`, and the schema type is "object", then we expand out the parameters of the object into individual fields. """ schema_type = schema.get('type') schema_properties = _get_dict(schema, 'properties') schema_required = _get_list(schema, 'required') if ((schema_type == ['object']) or (schema_type == 'object')) and schema_properties: return [ (key, key in schema_required) for key in schema_properties.keys() ] return None
def _dereference(value, ref): keys = value.strip('#/').split('/') node = ref for key in keys: node = _get_dict(node, key) return node