Example #1
0
def fields2parameters(fields, schema_cls=None, spec=None, use_refs=True, dump=True,
                      default_in='body', name='body', required=False):
    """Return an array of Swagger parameters given a mapping between field names and
    :class:`Field <marshmallow.Field>` objects. If `default_in` is "body", then return an array
    of a single parameter; else return an array of a parameter for each included field in
    the :class:`Schema <marshmallow.Schema>`.

    https://github.com/wordnik/swagger-spec/blob/master/versions/2.0.md#parameterObject
    """
    Meta = getattr(schema_cls, 'Meta', None)
    if default_in == 'body':
        if schema_cls is not None:
            # Prevent circular import
            from apispec.ext.marshmallow import resolve_schema_dict
            prop = resolve_schema_dict(spec, schema_cls, dump=dump)
        else:
            prop = fields2jsonschema(
                fields, schema_cls=schema_cls, spec=spec, use_refs=use_refs, dump=dump
            )
        return [{
            'in': default_in,
            'required': required,
            'name': name,
            'schema': prop,
        }]
    return [
        field2parameter(field_obj, name=_observed_name(field_obj, field_name), spec=spec,
            use_refs=use_refs, dump=dump, default_in=default_in)
        for field_name, field_obj in iteritems(fields)
        if (
            (field_name not in getattr(Meta, 'exclude', [])) and
            not (field_obj.dump_only and not dump)
        )
    ]
Example #2
0
def fields2parameters(fields, schema=None, spec=None, use_refs=True,
                      default_in='body', name='body', required=False,
                      use_instances=False, description=None, **kwargs):
    """Return an array of OpenAPI parameters given a mapping between field names and
    :class:`Field <marshmallow.Field>` objects. If `default_in` is "body", then return an array
    of a single parameter; else return an array of a parameter for each included field in
    the :class:`Schema <marshmallow.Schema>`.

    https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameterObject
    """
    swagger_default_in = __location_map__.get(default_in, default_in)
    if swagger_default_in == 'body':
        if schema is not None:
            # Prevent circular import
            from apispec.ext.marshmallow import resolve_schema_dict
            prop = resolve_schema_dict(spec, schema, dump=False, use_instances=use_instances)
        else:
            prop = fields2jsonschema(fields, spec=spec, use_refs=use_refs, dump=False)

        param = {
            'in': swagger_default_in,
            'required': required,
            'name': name,
            'schema': prop,
        }

        if description:
            param['description'] = description

        return [param]

    assert not getattr(schema, 'many', False), \
        "Schemas with many=True are only supported for 'json' location (aka 'in: body')"

    exclude_fields = getattr(getattr(schema, 'Meta', None), 'exclude', [])
    dump_only_fields = getattr(getattr(schema, 'Meta', None), 'dump_only', [])

    parameters = []
    body_param = None
    for field_name, field_obj in iteritems(fields):
        if (field_name in exclude_fields
            or field_obj.dump_only
            or field_name in dump_only_fields):
            continue
        param = field2parameter(field_obj,
                                name=_observed_name(field_obj, field_name),
                                spec=spec,
                                use_refs=use_refs,
                                default_in=default_in)
        if param['in'] == 'body' and body_param is not None:
            body_param['schema']['properties'].update(param['schema']['properties'])
            required_fields = param['schema'].get('required', [])
            if required_fields:
                body_param['schema'].setdefault('required', []).extend(required_fields)
        else:
            if param['in'] == 'body':
                body_param = param
            parameters.append(param)
    return parameters
Example #3
0
def flask_path_helper(spec, app, rule, operations=None, **kwargs):

    path = flaskpath2swagger(rule.rule)
    app_root = app.config['APPLICATION_ROOT'] or '/'
    path = urljoin(app_root.rstrip('/') + '/', path.lstrip('/'))

    if operations:
        # Get path parameters
        path_parameters = rule_to_params(rule)
        if path_parameters:
            for operation in operations.values():
                parameters = operation.setdefault('parameters', list())
                # Add path parameters to documentation
                # If a parameter is already in the doc (because it appears in
                # the parameters schema), merge properties rather than
                # duplicate or replace
                for path_p in path_parameters:
                    op_p = next((x for x in parameters
                                 if x['name'] == path_p['name']),
                                None)
                    if op_p is not None:
                        op_p.update(path_p)
                    else:
                        parameters.append(path_p)
        # Translate Marshmallow Schema
        for operation in operations.values():
            for response in operation.get('responses', {}).values():
                if 'schema' in response:
                    # If the API returns a list,
                    # the schema is specfied as [schema]
                    if isinstance(response['schema'], list):
                        response['schema'] = [
                            resolve_schema_dict(spec, response['schema'][0])
                        ]
                    else:
                        response['schema'] = resolve_schema_dict(
                            spec, response['schema'])

            for parameter in operation.get('parameters', []):
                if 'schema' in parameter:
                    parameter['schema'] = resolve_schema_dict(
                        spec, parameter['schema'])

    return Path(path=path, operations=operations)
Example #4
0
def fields2parameters(fields,
                      schema=None,
                      spec=None,
                      use_refs=True,
                      default_in='body',
                      name='body',
                      required=False,
                      use_instances=False):
    """Return an array of OpenAPI parameters given a mapping between field names and
    :class:`Field <marshmallow.Field>` objects. If `default_in` is "body", then return an array
    of a single parameter; else return an array of a parameter for each included field in
    the :class:`Schema <marshmallow.Schema>`.

    https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameterObject
    """
    if default_in == 'body':
        if schema is not None:
            # Prevent circular import
            from apispec.ext.marshmallow import resolve_schema_dict
            prop = resolve_schema_dict(spec,
                                       schema,
                                       dump=False,
                                       use_instances=use_instances)
        else:
            prop = fields2jsonschema(fields,
                                     spec=spec,
                                     use_refs=use_refs,
                                     dump=False)

        return [{
            'in': default_in,
            'required': required,
            'name': name,
            'schema': prop,
        }]

    assert not getattr(schema, 'many', False), \
        "Schemas with many=True are only supported for 'json' location (aka 'in: body')"

    exclude_fields = getattr(getattr(schema, 'Meta', None), 'exclude', [])
    dump_only_fields = getattr(getattr(schema, 'Meta', None), 'dump_only', [])

    return [
        field2parameter(field_obj,
                        name=_observed_name(field_obj, field_name),
                        spec=spec,
                        use_refs=use_refs,
                        default_in=default_in)
        for field_name, field_obj in iteritems(fields)
        if not (field_name in exclude_fields or field_obj.dump_only
                or field_name in dump_only_fields)
    ]
Example #5
0
    def test_schema_in_docstring_expand_parameters_v3(self, spec_3):
        def pet_view():
            """Not much to see here.

            ---
            get:
                parameters:
                    - in: query
                      schema: tests.schemas.PetSchema
                responses:
                    201:
                        description: successful operation
            post:
                requestBody:
                    description: "a pet schema"
                    required: true
                    content:
                        application/json:
                            schema: tests.schemas.PetSchema
                responses:
                    201:
                        description: successful operation
            """
            return '...'

        spec_3.add_path(path='/pet', view=pet_view)
        p = spec_3._paths['/pet']

        assert 'get' in p
        get = p['get']
        assert 'parameters' in get
        assert get['parameters'] == swagger.schema2parameters(
            PetSchema, default_in='query', spec=spec_3)
        for parameter in get['parameters']:
            description = parameter.get('description', False)
            assert description
            name = parameter['name']
            assert description == PetSchema.description[name]

        assert 'post' in p
        post = p['post']
        assert 'requestBody' in post
        post_schema = resolve_schema_dict(spec_3, PetSchema)
        assert post['requestBody']['content']['application/json'][
            'schema'] == post_schema
        assert post['requestBody']['description'] == 'a pet schema'
        assert post['requestBody']['required']
Example #6
0
def field2property(field, spec=None, use_refs=True):
    """Return the JSON Schema property definition given a marshmallow
    :class:`Field <marshmallow.fields.Field>`.

    https://github.com/wordnik/swagger-spec/blob/master/versions/2.0.md#schemaObject

    :param Field field: A marshmallow field.
    :param APISpec spec: Optional `APISpec` containing refs
    :param bool use_refs: Use JSONSchema ``refs``.
    :rtype: dict, a Property Object
    """
    from apispec.ext.marshmallow import resolve_schema_dict
    type_, fmt = _get_json_type_for_field(field)
    ret = {
        'type': type_,
    }
    if field.metadata.get('description'):
        ret['description'] = field.metadata['description']
    if fmt:
        ret['format'] = fmt
    if field.default:
        ret['default'] = field.default
    ret.update(field.metadata)
    choices = field2choices(field)
    if choices:
        ret['enum'] = list(choices)
    # Avoid validation error with "Additional properties not allowed"
    # Property "ref" is not valid in this context
    ret.pop('ref', None)
    if isinstance(field, fields.Nested):
        if use_refs and field.metadata.get('ref'):
            schema = {'$ref': field.metadata['ref']}
        elif spec:
            schema = resolve_schema_dict(spec, field.schema)
        else:
            schema = schema2jsonschema(field.schema.__class__)
        if field.many:
            ret['type'] = 'array'
            ret['items'] = schema
        else:
            ret = schema
    elif isinstance(field, fields.List):
        ret['items'] = field2property(field.container,
                                      spec=spec,
                                      use_refs=use_refs)
    return ret
Example #7
0
def field2property(field, spec=None, use_refs=True, dump=True, name=None):
    """Return the JSON Schema property definition given a marshmallow
    :class:`Field <marshmallow.fields.Field>`.

    Will include field metadata that are valid properties of OpenAPI schema objects
    (e.g. "description", "enum", "example").

    https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaObject

    :param Field field: A marshmallow field.
    :param APISpec spec: Optional `APISpec` containing refs.
    :param bool use_refs: Use JSONSchema ``refs``.
    :param bool dump: Introspect dump logic.
    :param str name: The definition name, if applicable, used to construct the $ref value.
    :rtype: dict, a Property Object
    """
    from apispec.ext.marshmallow import resolve_schema_dict
    type_, fmt = _get_json_type_for_field(field)

    ret = {
        'type': type_,
    }

    if fmt:
        ret['format'] = fmt

    default = field.default if dump else field.missing
    if default is not marshmallow.missing:
        if callable(default):
            ret['default'] = default()
        else:
            ret['default'] = default

    choices = field2choices(field)
    if choices:
        ret['enum'] = list(choices)

    if field.dump_only:
        ret['readOnly'] = True

    if field.allow_none:
        ret['x-nullable'] = True

    ret.update(field2range(field))
    ret.update(field2length(field))

    if isinstance(field, marshmallow.fields.Nested):
        del ret['type']
        # marshmallow>=2.7.0 compat
        field.metadata.pop('many', None)

        is_unbound_self_referencing = not getattr(
            field, 'parent', None) and field.nested == 'self'
        if (use_refs
                and 'ref' in field.metadata) or is_unbound_self_referencing:
            if 'ref' in field.metadata:
                ref_name = field.metadata['ref']
            else:
                if not name:
                    raise ValueError(
                        'Must pass `name` argument for self-referencing Nested fields.'
                    )
                # We need to use the `name` argument when the field is self-referencing and
                # unbound (doesn't have `parent` set) because we can't access field.schema
                ref_name = '#/definitions/{name}'.format(name=name)
            ref_schema = {'$ref': ref_name}
            if field.many:
                ret['type'] = 'array'
                ret['items'] = ref_schema
            else:
                if ret:
                    ret.update({'allOf': [ref_schema]})
                else:
                    ret.update(ref_schema)
        elif spec:
            schema_dict = resolve_schema_dict(spec, field.schema, dump=dump)
            if ret and '$ref' in schema_dict:
                ret.update({'allOf': [schema_dict]})
            else:
                ret.update(schema_dict)
        else:
            ret.update(schema2jsonschema(field.schema, dump=dump))
    elif isinstance(field, marshmallow.fields.List):
        ret['items'] = field2property(field.container,
                                      spec=spec,
                                      use_refs=use_refs,
                                      dump=dump)

    # Dasherize metadata that starts with x_
    metadata = {
        key.replace('_', '-') if key.startswith('x_') else key: value
        for key, value in iteritems(field.metadata)
    }
    for key, value in iteritems(metadata):
        if key in _VALID_PROPERTIES or key.startswith(_VALID_PREFIX):
            ret[key] = value
    # Avoid validation error with "Additional properties not allowed"
    # Property "ref" is not valid in this context
    ret.pop('ref', None)

    return ret