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) ) ]
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
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)
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) ]
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']
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
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