Example #1
0
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)
Example #2
0
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
Example #3
0
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
Example #4
0
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)
Example #5
0
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
Example #6
0
def _dereference(value, ref):
    keys = value.strip('#/').split('/')
    node = ref
    for key in keys:
        node = _get_dict(node, key)
    return node