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 _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 _primative_to_document(data, base_url): url = base_url # Determine if the document contains a self URL. links = _get_list(data, 'links') for link in get_dicts(links): href = _get_string(link, 'href') rel = _get_string(link, 'rel') if rel == 'self' and href: url = urlparse.urljoin(url, href) # Load the document content. title = _get_string(data, 'title') content = _get_content(data, url, ref=data) return Document(title=title, url=url, content=content)
def _get_document_base_url(data, base_url=None): """ Get the base url to use when constructing absolute paths from the relative ones provided in the schema defination. """ prefered_schemes = ['http', 'https'] if base_url: url_components = urlparse.urlparse(base_url) default_host = url_components.netloc default_scheme = url_components.scheme else: default_host = '' default_scheme = None host = _get_string(data, 'host', default=default_host) path = _get_string(data, 'basePath', default='/') if not host: # No host is provided, and we do not have an initial URL. return path.strip('/') + '/' schemes = _get_list(data, 'schemes') if not schemes: # No schemes provided, use the initial URL, or a fallback. scheme = default_scheme or prefered_schemes[0] elif default_scheme in schemes: # Schemes provided, the initial URL matches one of them. scheme = default_scheme else: # Schemes provided, the initial URL does not match, pick a fallback. for scheme in prefered_schemes: if scheme in schemes: break else: raise ParseError('Unsupported transport schemes "%s"' % schemes) return '%s://%s/%s/' % (scheme, host, path.strip('/'))