Específico validates incoming requests for conformance with the schemas described in swagger specification.
Request parameters will be provided to the handler functions as keyword
arguments if they are included in the function's signature, otherwise body
parameters can be accessed from especifico.request.json
and query parameters
can be accessed from especifico.request.args
.
Both the request body and parameters are validated against the specification, using jsonschema.
If the request doesn't match the specification especifico will return a 400 error.
Específico automatically maps the parameters defined in your endpoint specification to arguments of your Python views as named parameters and with value casting whenever possible. All you need to do is define the endpoint's parameters with matching names with your views arguments.
As example you have an endpoint specified as:
paths:
/foo:
get:
operationId: api.foo_get
parameters:
- name: message
description: Some message.
in: query
type: string
required: true
And the view function:
# api.py file
def foo_get(message):
# do something
return 'You send the message: {}'.format(message), 200
In this example Específico will automatically identify that your view function expects an argument named message and will assign the value of the endpoint parameter message to your view function.
Específico will also use default values if they are provided.
If you want to use a parameter name that collides with a Python built-in, you can enable the pythonic_params option:
app = especifico.FlaskApp(__name__)
app.add_api('api.yaml', ..., pythonic_params=True)
With this option enabled, Específico firstly converts CamelCase names to snake_case. Secondly it looks to see if the name matches a known built-in and if it does it appends an underscore to the name.
As example you have an endpoint specified as:
paths:
/foo:
get:
operationId: api.foo_get
parameters:
- name: filter
description: Some filter.
in: query
type: string
required: true
And the view function:
# api.py file
def foo_get(filter_):
# do something
return 'You send the filter: {}'.format(filter_), 200
Note
In the OpenAPI 3.x.x spec, the requestBody does not have a name. By default it will be passed in as 'body'. You can optionally provide the x-body-name parameter in your operation (or legacy position within the requestBody schema) to override the name of the parameter that will be passed to your handler function.
/path
post:
requestBody:
x-body-name: body
content:
application/json:
schema:
# legacy location here should be ignored because the preferred location for x-body-name is at the requestBody level above
x-body-name: this_should_be_ignored
Warning
Please note that when you have a parameter defined as not required at your endpoint and your Python view have a non-named argument, when you call this endpoint WITHOUT the parameter you will get an exception of missing positional argument.
Whenever possible Específico will try to parse your argument values and do type casting to related Python natives values. The current available type castings are:
OpenAPI Type | Python Type |
---|---|
integer | int |
string | str |
number | float |
boolean | bool |
array | list |
null | None |
object | dict |
Note
For more details about collectionFormats please check the official OpenAPI 2.0 Specification.
In the OpenAPI 2.0 Specification if you use the array
type,
you can define the collectionFormat
to set the deserialization behavior.
Específico currently supports "pipes" and "csv" as collection formats.
The default format is "csv".
Específico is opinionated about how the URI is parsed for array
types.
The default behavior for query parameters that have been defined multiple
times is to join them all together. For example, if you provide a URI with
the the query string ?letters=a,b,c&letters=d,e,f
, especifico will set
letters = ['a', 'b', 'c', 'd', 'e', 'f']
.
You can override this behavior by specifying the URI parser in the app or api options.
from especifico.decorators.uri_parsing import Swagger2URIParser
options = {'uri_parser_class': Swagger2URIParser}
app = especifico.App(__name__, specification_dir='swagger/', options=options)
You can implement your own URI parsing behavior by inheriting from
especifico.decorators.uri_parsing.AbstractURIParser
.
There are a handful of URI parsers included with connection.
Específico can apply strict parameter validation for query and form data parameters. When this is enabled, requests that include parameters not defined in the swagger spec return a 400 error. You can enable it when adding the API to your application:
app.add_api('my_apy.yaml', strict_validation=True)
Sometimes your API should explicitly accept nullable parameters. However OpenAPI specification currently does not support officially a way to serve this use case, Específico adds the x-nullable vendor extension to parameter definitions. Its usage would be:
/countries/cities:
parameters:
- name: name
in: query
type: string
x-nullable: true
required: true
It is supported by Específico in all parameter types: body, query, formData, and path. Nullable values are the strings null and None.
Warning
Be careful on nullable parameters for sensitive data where the strings "null" or "None" can be valid values.
Note
This extension will be removed as soon as OpenAPI/Swagger Specification provide an official way of supporting nullable values.
Currently, header parameters are not passed to the handler functions as parameters. But they can be accessed through the underlying
especifico.request.headers
object which aliases the flask.request.headers
object.
def index():
page_number = especifico.request.headers['Page-Number']
By default, body and parameters contents are validated against OpenAPI schema
via especifico.decorators.validation.RequestBodyValidator
or especifico.decorators.validation.ParameterValidator
, if you want to
change the validation, you can override the defaults with:
validator_map = {
'body': CustomRequestBodyValidator,
'parameter': CustomParameterValidator
}
app = especifico.FlaskApp(__name__)
app.add_api('api.yaml', ..., validator_map=validator_map)
See custom validator example in examples/enforcedefaults
.