Arguments¶
To inject arguments into a view function, use the Blueprint.arguments
decorator. It allows to specify a Schema
to deserialize and validate the parameters.
When processing a request, the input data is deserialized, validated, and injected in the view function.
@blp.route('/')
class Pets(MethodView):
@blp.arguments(PetQueryArgsSchema, location='query')
@blp.response(200, PetSchema(many=True))
def get(self, args):
return Pet.get(filters=args)
@blp.arguments(PetSchema)
@blp.response(201, PetSchema)
def post(self, pet_data):
return Pet.create(**pet_data)
Arguments Location¶
The following locations are allowed:
"json"
"query"
(or"querystring"
)"path"
"form"
"headers"
"cookies"
"files"
The location defaults to "json"
, which means body parameter.
Arguments Injection¶
By default, arguments are passed as a single positional dict
argument.
If as_kwargs=True
is passed, the decorator passes deserialized input data
as keyword arguments instead.
@blp.route('/')
class Pets(MethodView):
@blp.arguments(PetQueryArgsSchema, location='query', as_kwargs=True)
@blp.response(200, PetSchema(many=True))
def get(self, **kwargs):
return Pet.get(filters=**kwargs)
This decorator can be called several times on a resource function, for instance to accept both body and query parameters. The order of the decorator calls matters as it determines the order in which the parameters are passed to the view function.
@blp.route('/')
class Pets(MethodView):
@blp.arguments(PetSchema)
@blp.arguments(QueryArgsSchema, location='query')
def post(pet_data, query_args):
return Pet.create(pet_data, **query_args)
Dealing With Unknown Arguments¶
When input data contains unknown fields, a marshmallow Schema
may raise a
ValidationError
(default), exclude those fields, or include them without
validation. This can be controlled by the unknown
Meta attribute of the
Schema
, which can be set to RAISE
, EXCLUDE
or INCLUDE
.
Webargs, used internally by the arguments
decorator, sets this parameter
depending on the location of the argument. EXCLUDE
is used for all
locations except json
, form
, json_or_form
, or path
, where
RAISE
is used.
This can be customized in the FlaskParser
imported from webargs. The
easiest way is to mutate DEFAULT_UNKNOWN_BY_LOCATION
in the parser class:
import marshmallow as ma
from webargs.flaskparser import FlaskParser
FlaskParser.DEFAULT_UNKNOWN_BY_LOCATION["json"] = ma.EXCLUDE
It can also be achieved by subclassing the parser and setting
ARGUMENTS_PARSER
in a base Blueprint
class:
import marshmallow as ma
from webargs.flaskparser import FlaskParser
from flask_smorest import Blueprint
class MyFlaskParser(FlaskParser):
DEFAULT_UNKNOWN_BY_LOCATION = {
"query": ma.RAISE,
"json": ma.RAISE,
# ...
}
class MyBlueprint(Blueprint):
ARGUMENTS_PARSER = MyFlaskParser()
This latter method is recommended if several parsers are instantiated with
different unknown
values, for instance to get a different behaviour in
different Blueprint
s.
Setting None
as DEFAULT_UNKNOWN_BY_LOCATION
instead of a location/value
mapping disables the feature to fall back to the Schema
’s unknown
value
and marshmallow default (RAISE
).
Note
The pagination feature in flask-smorest uses its own FlaskParser
instance to parse pagination parameters from query arguments. It is affected
by mutations of FlaskParser.DEFAULT_UNKNOWN_BY_LOCATION
setting a value
other than EXCLUDE
for query
.
Note
More default about customizing unknown
can be found in webargs
documentation.
Note
The unknown value passed by webargs only applies to first level
fields, not to nested fields. To set EXCLUDE
for json
locations
using Schema``s with ``Nested
fields, one must set EXCLUDE
in the
parser but also set unkown=EXCLUDE
as Meta attribute in nested schemas.
In practice, this is easily achieved using a base schema class. This should
be improved in the future, as discussed in webargs issue #580.
Multiple Arguments Schemas¶
Calls to arguments
decorator can be stacked, for instance to define
arguments from multiple locations:
@blp.route('/')
class Pets(MethodView):
@blp.arguments(PetSchema)
@blp.arguments(QueryArgsSchema, location="query")
@blp.response(201, PetSchema)
def post(self, pet_data, query_args):
pet = Pet.create(**pet_data)
# Use query args
...
return pet
It can also be done to define multiple arguments for the same location. Of
course, this only makes sense for locations where unknown
is set to
EXCLUDE
.
Content Type¶
When using body arguments, a default content type is assumed depending on the
location. The location / content type mapping can be customized by modifying
Blueprint.DEFAULT_LOCATION_CONTENT_TYPE_MAPPING
.
DEFAULT_LOCATION_CONTENT_TYPE_MAPPING = {
"json": "application/json",
"form": "application/x-www-form-urlencoded",
"files": "multipart/form-data",
It is also possible to override those defaults in a single resource by passing
a string as content_type
argument to Blueprint.arguments
.
Note
The content type is only used for documentation purpose and has no impact on request parsing.
Note
Multipart requests with mixed types (file, form, etc.) are not
supported. They can be achieved but the documentation is not correctly
generated. arguments
decorator can be called multiple times on the same
view function but it should not be called with more that one request body
location. This limitation is discussed in #46.
File Upload¶
File uploads as multipart/form-data are supported for both OpenAPI 3 and OpenAPI 2.
The arguments Schema
should contain Upload
fields. The files are injected in the view function as a dict
of werkzeug
FileStorage
instances.
import os.path
from werkzeug.utils import secure_filename
from flask_smorest.fields import Upload
class MultipartFileSchema(ma.Schema):
file_1 = Upload()
@blp.route('/', methods=['POST'])
@blp.arguments(MultipartFileSchema, location='files')
@blp.response(201)
def func(files):
base_dir = '/path/to/storage/dir/'
file_1 = files['file_1']
file_1.save(os.path.join(base_dir, secure_filename(file_1.filename)))