Flask-RESTful¶
Flask-RESTful是Flask的扩展,增加了对快速构建REST API的支持。 它是一个轻量级的抽象,可与现有的ORM /库一起使用。 Flask-RESTful以最少的设置鼓励最佳实践。 如果你熟悉Flask,Flask-RESTful应该很容易学会。
用户指南¶
这部分文档将向您展示如何开始在Flask中使用Flask-RESTful。
安装¶
用pip
安装Flask-RESTful
pip install flask-restful
开发版本可以从的GitHub下载。
git clone https://github.com/flask-restful/flask-restful.git
cd flask-restful
python setup.py develop
Flask-RESTful具有以下依赖关系(如果使用pip
,它将自动安装):
- Flask版本0.8或更高
Flask-RESTful需要Python版本2.6,2.7,3.3,3.4,3.5或3.6。
快速开始¶
现在是编写您的第一个REST API的时候了。 本指南假设您对Flask有一定的理解,并且您已经安装了Flask和Flask-RESTful。 如果不是,请按照安装部分中的步骤进行操作。
最小的API ¶
最小的Flask-RESTful API如下所示:
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
return {'hello': 'world'}
api.add_resource(HelloWorld, '/')
if __name__ == '__main__':
app.run(debug=True)
将其另存为api.py并使用Python解释器运行它。 请注意,我们已启用Flask调试模式来提供代码重新加载和更好的错误消息。
$ python api.py
* Running on http://127.0.0.1:5000/
* Restarting with reloader
警告
调试模式不应该在生产环境中使用!
现在打开一个新的提示窗口,用curl测试你的API
$ curl http://127.0.0.1:5000/
{"hello": "world"}
资源路由¶
Flask-RESTful提供的主要构建块是资源。 资源建立在Flask可插入视图之上,只需通过定义资源上的方法,便可轻松访问多个HTTP方法。 一个 todo 应用程序的基本 CRUD资源 (当然)如下所示:
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
todos = {}
class TodoSimple(Resource):
def get(self, todo_id):
return {todo_id: todos[todo_id]}
def put(self, todo_id):
todos[todo_id] = request.form['data']
return {todo_id: todos[todo_id]}
api.add_resource(TodoSimple, '/<string:todo_id>')
if __name__ == '__main__':
app.run(debug=True)
你可以这样尝试:
$ curl http://localhost:5000/todo1 -d "data=Remember the milk" -X PUT
{"todo1": "Remember the milk"}
$ curl http://localhost:5000/todo1
{"todo1": "Remember the milk"}
$ curl http://localhost:5000/todo2 -d "data=Change my brakepads" -X PUT
{"todo2": "Change my brakepads"}
$ curl http://localhost:5000/todo2
{"todo2": "Change my brakepads"}
如果您安装了requests
库,则可以从python测试:
>>> from requests import put, get
>>> put('http://localhost:5000/todo1', data={'data': 'Remember the milk'}).json()
{u'todo1': u'Remember the milk'}
>>> get('http://localhost:5000/todo1').json()
{u'todo1': u'Remember the milk'}
>>> put('http://localhost:5000/todo2', data={'data': 'Change my brakepads'}).json()
{u'todo2': u'Change my brakepads'}
>>> get('http://localhost:5000/todo2').json()
{u'todo2': u'Change my brakepads'}
Flask-RESTful可以理解来自视图方法的多种返回值。 与Flask类似,您可以返回任何可迭代,并将其转换为响应,包括原始Flask响应对象。 Flask-RESTful还支持使用多个返回值设置响应代码和响应头,如下所示:
class Todo1(Resource):
def get(self):
# Default to 200 OK
return {'task': 'Hello world'}
class Todo2(Resource):
def get(self):
# Set the response code to 201
return {'task': 'Hello world'}, 201
class Todo3(Resource):
def get(self):
# Set the response code to 201 and return custom headers
return {'task': 'Hello world'}, 201, {'Etag': 'some-opaque-string'}
端点¶
很多时候在API中,你的资源将有多个URL。 您可以将多个URL传递给Api对象上的add_resource()
方法。
每一个将被路由到您的资源
api.add_resource(HelloWorld,
'/',
'/hello')
您也可以将部分路径作为变量与您的资源方法进行匹配。
api.add_resource(Todo,
'/todo/<int:todo_id>', endpoint='todo_ep')
注意
如果请求与任何应用程序的端点不匹配,Flask-RESTful将返回一个404错误消息,其中包含与请求端点密切匹配的其他端点的建议。 这可以通过在您的应用程序配置中将ERROR_404_HELP
设置为False
来禁用。
参数解析¶
虽然Flask可以方便地访问请求数据(即查询字符串或POST表单编码数据),但验证表单数据仍然很痛苦。 Flask-RESTful内置了对使用类似于argparse的库的请求数据验证的支持。
from flask_restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('rate', type=int, help='Rate to charge for this resource')
args = parser.parse_args()
注意
与argparse模块不同,reqparse.RequestParser.parse_args()
返回一个Python字典而不是自定义数据结构。
使用reqparse
模块还可自由提供完整的错误消息。 如果参数未能通过验证,Flask-RESTful将以400错误请求和突出显示错误的响应进行响应。
$ curl -d 'rate=foo' http://127.0.0.1:5000/todos
{'status': 400, 'message': 'foo cannot be converted to int'}
inputs
模块提供了一些常用的转换函数,如inputs.date()
和inputs.url()
。
使用strict = True
调用parse_args
可确保在请求包含解析器未定义的参数时引发错误。
args = parser.parse_args(strict=True)
数据格式化¶
默认情况下,返回迭代器中的所有字段将按原样呈现。 虽然这在你处理Python数据结构时效果很好,但在处理对象时会变得非常令人沮丧。 为了解决这个问题,Flask-RESTful提供了fields
模块和marshal_with()
装饰器。 与Django ORM和WTForm类似,您可以使用fields
模块来描述响应的结构。
from flask_restful import fields, marshal_with
resource_fields = {
'task': fields.String,
'uri': fields.Url('todo_ep')
}
class TodoDao(object):
def __init__(self, todo_id, task):
self.todo_id = todo_id
self.task = task
# This field will not be sent in the response
self.status = 'active'
class Todo(Resource):
@marshal_with(resource_fields)
def get(self, **kwargs):
return TodoDao(todo_id='my_todo', task='Remember the milk')
上面的例子使用一个python对象并且准备将其序列化。 marshal_with()
修饰器将应用resource_fields
描述的转换。 从对象中提取的唯一字段是task
。 fields.Url
字段是一个特殊字段,它接收端点名称并在响应中为该端点生成一个URL。 您需要的许多字段类型都已包含在内。 有关完整列表,请参阅fields
指南。
完整示例¶
将这个例子保存在api.py中
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
app = Flask(__name__)
api = Api(app)
TODOS = {
'todo1': {'task': 'build an API'},
'todo2': {'task': '?????'},
'todo3': {'task': 'profit!'},
}
def abort_if_todo_doesnt_exist(todo_id):
if todo_id not in TODOS:
abort(404, message="Todo {} doesn't exist".format(todo_id))
parser = reqparse.RequestParser()
parser.add_argument('task')
# Todo
# shows a single todo item and lets you delete a todo item
class Todo(Resource):
def get(self, todo_id):
abort_if_todo_doesnt_exist(todo_id)
return TODOS[todo_id]
def delete(self, todo_id):
abort_if_todo_doesnt_exist(todo_id)
del TODOS[todo_id]
return '', 204
def put(self, todo_id):
args = parser.parse_args()
task = {'task': args['task']}
TODOS[todo_id] = task
return task, 201
# TodoList
# shows a list of all todos, and lets you POST to add new tasks
class TodoList(Resource):
def get(self):
return TODOS
def post(self):
args = parser.parse_args()
todo_id = int(max(TODOS.keys()).lstrip('todo')) + 1
todo_id = 'todo%i' % todo_id
TODOS[todo_id] = {'task': args['task']}
return TODOS[todo_id], 201
##
## Actually setup the Api resource routing here
##
api.add_resource(TodoList, '/todos')
api.add_resource(Todo, '/todos/<todo_id>')
if __name__ == '__main__':
app.run(debug=True)
用法示例
$ python api.py
* Running on http://127.0.0.1:5000/
* Restarting with reloader
GET列表
$ curl http://localhost:5000/todos
{"todo1": {"task": "build an API"}, "todo3": {"task": "profit!"}, "todo2": {"task": "?????"}}
GET 单个任务
$ curl http://localhost:5000/todos/todo3
{"task": "profit!"}
DELETE 一个任务
$ curl http://localhost:5000/todos/todo2 -X DELETE -v
> DELETE /todos/todo2 HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8l zlib/1.2.3
> Host: localhost:5000
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 204 NO CONTENT
< Content-Type: application/json
< Content-Length: 0
< Server: Werkzeug/0.8.3 Python/2.7.2
< Date: Mon, 01 Oct 2012 22:10:32 GMT
添加一个新任务
$ curl http://localhost:5000/todos -d "task=something new" -X POST -v
> POST /todos HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8l zlib/1.2.3
> Host: localhost:5000
> Accept: */*
> Content-Length: 18
> Content-Type: application/x-www-form-urlencoded
>
* HTTP 1.0, assume close after body
< HTTP/1.0 201 CREATED
< Content-Type: application/json
< Content-Length: 25
< Server: Werkzeug/0.8.3 Python/2.7.2
< Date: Mon, 01 Oct 2012 22:12:58 GMT
<
* Closing connection #0
{"task": "something new"}
更新任务
$ curl http://localhost:5000/todos/todo3 -d "task=something different" -X PUT -v
> PUT /todos/todo3 HTTP/1.1
> Host: localhost:5000
> Accept: */*
> Content-Length: 20
> Content-Type: application/x-www-form-urlencoded
>
* HTTP 1.0, assume close after body
< HTTP/1.0 201 CREATED
< Content-Type: application/json
< Content-Length: 27
< Server: Werkzeug/0.8.3 Python/2.7.3
< Date: Mon, 01 Oct 2012 22:13:00 GMT
<
* Closing connection #0
{"task": "something different"}
请求解析¶
警告
Flask-RESTful的整个请求解析器部分将被移除,并且将被关于如何与更好地执行输入/输出内容的其他包(如marshmallow)集成的文档所取代。 这意味着它将保持到2.0,但认为它已被弃用。 不要担心,如果您现在有代码使用该代码并希望继续这样做,则不会过早消失。
Flask-RESTful的请求解析接口reqparse
在argparse接口之后建模。
它旨在为Flask中的flask.request
对象上的任何变量提供简单且一致的访问。
基本参数¶
以下是请求解析器的一个简单示例。 它在flask.Request.values
字典中寻找两个参数:一个整数和一个字符串
from flask_restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('rate', type=int, help='Rate cannot be converted')
parser.add_argument('name')
args = parser.parse_args()
注意
默认参数类型是一个unicode字符串。 这将在python3中为str
且python2中为unicode
。
If you specify the help
value, it will be rendered as the error message
when a type error is raised while parsing it. If you do not specify a help
message, the default behavior is to return the message from the type error
itself. See error-messages for more details.
By default, arguments are not required. Also, arguments supplied in the request that are not part of the RequestParser will be ignored.
Also note: Arguments declared in your request parser but not set in
the request itself will default to None
.
Required Arguments¶
To require a value be passed for an argument, just add required=True
to
the call to add_argument()
.
parser.add_argument('name', required=True,
help="Name cannot be blank!")
Multiple Values & Lists¶
If you want to accept multiple values for a key as a list, you can pass
action='append'
parser.add_argument('name', action='append')
This will let you make queries like
curl http://api.example.com -d "name=bob" -d "name=sue" -d "name=joe"
And your args will look like this
args = parser.parse_args()
args['name'] # ['bob', 'sue', 'joe']
Other Destinations¶
If for some reason you’d like your argument stored under a different name once
it’s parsed, you can use the dest
keyword argument.
parser.add_argument('name', dest='public_name')
args = parser.parse_args()
args['public_name']
Argument Locations¶
By default, the RequestParser
tries to parse values from
flask.Request.values
, and flask.Request.json
.
Use the location
argument to add_argument()
to specify alternate locations to pull the values from. Any variable on the
flask.Request
can be used. For example:
# Look only in the POST body
parser.add_argument('name', type=int, location='form')
# Look only in the querystring
parser.add_argument('PageSize', type=int, location='args')
# From the request headers
parser.add_argument('User-Agent', location='headers')
# From http cookies
parser.add_argument('session_id', location='cookies')
# From file uploads
parser.add_argument('picture', type=werkzeug.datastructures.FileStorage, location='files')
Note
Only use type=list
when location='json'
. See this issue for more
details
Multiple Locations¶
Multiple argument locations can be specified by passing a list to location
:
parser.add_argument('text', location=['headers', 'values'])
When multiple locations are specified, the arguments from all locations
specified are combined into a single MultiDict
.
The last location
listed takes precedence in the result set.
If the argument location list includes the headers
location the argument names will no longer be case insensitive and must match
their title case names (see str.title()
). Specifying
location='headers'
(not as a list) will retain case insensitivity.
Parser Inheritance¶
Often you will make a different parser for each resource you write. The problem
with this is if parsers have arguments in common. Instead of rewriting
arguments you can write a parent parser containing all the shared arguments and
then extend the parser with copy()
. You can
also overwrite any argument in the parent with
replace_argument()
, or remove it completely
with remove_argument()
. For example:
from flask_restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('foo', type=int)
parser_copy = parser.copy()
parser_copy.add_argument('bar', type=int)
# parser_copy has both 'foo' and 'bar'
parser_copy.replace_argument('foo', required=True, location='json')
# 'foo' is now a required str located in json, not an int as defined
# by original parser
parser_copy.remove_argument('foo')
# parser_copy no longer has 'foo' argument
Error Handling¶
The default way errors are handled by the RequestParser is to abort on the
first error that occurred. This can be beneficial when you have arguments that
might take some time to process. However, often it is nice to have the errors
bundled together and sent back to the client all at once. This behavior can be
specified either at the Flask application level or on the specific
RequestParser instance. To invoke a RequestParser with the bundling errors
option, pass in the argument bundle_errors
. For example
from flask_restful import reqparse
parser = reqparse.RequestParser(bundle_errors=True)
parser.add_argument('foo', type=int, required=True)
parser.add_argument('bar', type=int, required=True)
# If a request comes in not containing both 'foo' and 'bar', the error that
# will come back will look something like this.
{
"message": {
"foo": "foo error message",
"bar": "bar error message"
}
}
# The default behavior would only return the first error
parser = RequestParser()
parser.add_argument('foo', type=int, required=True)
parser.add_argument('bar', type=int, required=True)
{
"message": {
"foo": "foo error message"
}
}
The application configuration key is “BUNDLE_ERRORS”. For example
from flask import Flask
app = Flask(__name__)
app.config['BUNDLE_ERRORS'] = True
Warning
BUNDLE_ERRORS
is a global setting that overrides the bundle_errors
option in individual RequestParser
instances.
Error Messages¶
Error messages for each field may be customized using the help
parameter
to Argument
(and also RequestParser.add_argument
).
If no help parameter is provided, the error message for the field will be
the string representation of the type error itself. If help
is provided,
then the error message will be the value of help
.
help
may include an interpolation token, {error_msg}
, that will be
replaced with the string representation of the type error. This allows the
message to be customized while preserving the original error
from flask_restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument(
'foo',
choices=('one', 'two'),
help='Bad choice: {error_msg}'
)
# If a request comes in with a value of "three" for `foo`:
{
"message": {
"foo": "Bad choice: three is not a valid choice",
}
}
Output Fields¶
Flask-RESTful provides an easy way to control what data you actually render in
your response. With the fields
module, you can use whatever objects (ORM
models/custom classes/etc.) you want in your resource. fields
also lets you
format and filter the response so you don’t have to worry about exposing
internal data structures.
It’s also very clear when looking at your code what data will be rendered and how it will be formatted.
Basic Usage¶
You can define a dict or OrderedDict of fields whose keys are names of
attributes or keys on the object to render, and whose values are a class that
will format & return the value for that field. This example has three fields:
two are String
and one is a DateTime
,
formatted as an RFC 822 date string (ISO 8601 is supported as well)
from flask_restful import Resource, fields, marshal_with
resource_fields = {
'name': fields.String,
'address': fields.String,
'date_updated': fields.DateTime(dt_format='rfc822'),
}
class Todo(Resource):
@marshal_with(resource_fields, envelope='resource')
def get(self, **kwargs):
return db_get_todo() # Some function that queries the db
This example assumes that you have a custom database object (todo
) that
has attributes name
, address
, and date_updated
. Any additional
attributes on the object are considered private and won’t be rendered in the
output. An optional envelope
keyword argument is specified to wrap the
resulting output.
The decorator marshal_with
is what actually takes your data object and
applies the field filtering. The marshalling can work on single objects,
dicts, or lists of objects.
Note
marshal_with
is a convenience decorator, that is functionally
equivalent to
class Todo(Resource):
def get(self, **kwargs):
return marshal(db_get_todo(), resource_fields), 200
This explicit expression can be used to return HTTP status codes other than 200
along with a successful response (see abort()
for errors).
Renaming Attributes¶
Often times your public facing field name is different from your internal field
name. To configure this mapping, use the attribute
keyword argument.
fields = {
'name': fields.String(attribute='private_name'),
'address': fields.String,
}
A lambda (or any callable) can also be specified as the attribute
fields = {
'name': fields.String(attribute=lambda x: x._private_name),
'address': fields.String,
}
Nested properties can also be accessed with attribute
fields = {
'name': fields.String(attribute='people_list.0.person_dictionary.name'),
'address': fields.String,
}
Default Values¶
If for some reason your data object doesn’t have an attribute in your fields
list, you can specify a default value to return instead of None
.
fields = {
'name': fields.String(default='Anonymous User'),
'address': fields.String,
}
Custom Fields & Multiple Values¶
Sometimes you have your own custom formatting needs. You can subclass the
fields.Raw
class and implement the format
function. This is especially
useful when an attribute stores multiple pieces of information. e.g. a
bit-field whose individual bits represent distinct values. You can use fields
to multiplex a single attribute to multiple output values.
This example assumes that bit 1 in the flags
attribute signifies a
“Normal” or “Urgent” item, and bit 2 signifies “Read” or “Unread”. These
items might be easy to store in a bitfield, but for a human readable output
it’s nice to convert them to seperate string fields.
class UrgentItem(fields.Raw):
def format(self, value):
return "Urgent" if value & 0x01 else "Normal"
class UnreadItem(fields.Raw):
def format(self, value):
return "Unread" if value & 0x02 else "Read"
fields = {
'name': fields.String,
'priority': UrgentItem(attribute='flags'),
'status': UnreadItem(attribute='flags'),
}
Url & Other Concrete Fields¶
Flask-RESTful includes a special field, fields.Url
, that synthesizes a
uri for the resource that’s being requested. This is also a good example of how
to add data to your response that’s not actually present on your data object.:
class RandomNumber(fields.Raw):
def output(self, key, obj):
return random.random()
fields = {
'name': fields.String,
# todo_resource is the endpoint name when you called api.add_resource()
'uri': fields.Url('todo_resource'),
'random': RandomNumber,
}
By default fields.Url
returns a relative uri. To generate an absolute uri
that includes the scheme, hostname and port, pass the keyword argument
absolute=True
in the field declaration. To override the default scheme,
pass the scheme
keyword argument:
fields = {
'uri': fields.Url('todo_resource', absolute=True)
'https_uri': fields.Url('todo_resource', absolute=True, scheme='https')
}
Complex Structures¶
You can have a flat structure that marshal()
will
transform to a nested structure
>>> from flask_restful import fields, marshal
>>> import json
>>>
>>> resource_fields = {'name': fields.String}
>>> resource_fields['address'] = {}
>>> resource_fields['address']['line 1'] = fields.String(attribute='addr1')
>>> resource_fields['address']['line 2'] = fields.String(attribute='addr2')
>>> resource_fields['address']['city'] = fields.String
>>> resource_fields['address']['state'] = fields.String
>>> resource_fields['address']['zip'] = fields.String
>>> data = {'name': 'bob', 'addr1': '123 fake street', 'addr2': '', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> json.dumps(marshal(data, resource_fields))
'{"name": "bob", "address": {"line 1": "123 fake street", "line 2": "", "state": "NY", "zip": "10468", "city": "New York"}}'
Note
The address field doesn’t actually exist on the data object, but any of the sub-fields can access attributes directly from the object as if they were not nested.
List Field¶
You can also unmarshal fields as lists
>>> from flask_restful import fields, marshal
>>> import json
>>>
>>> resource_fields = {'name': fields.String, 'first_names': fields.List(fields.String)}
>>> data = {'name': 'Bougnazal', 'first_names' : ['Emile', 'Raoul']}
>>> json.dumps(marshal(data, resource_fields))
>>> '{"first_names": ["Emile", "Raoul"], "name": "Bougnazal"}'
Advanced : Nested Field¶
While nesting fields using dicts can turn a flat data object into a nested
response, you can use Nested
to unmarshal nested data
structures and render them appropriately.
>>> from flask_restful import fields, marshal
>>> import json
>>>
>>> address_fields = {}
>>> address_fields['line 1'] = fields.String(attribute='addr1')
>>> address_fields['line 2'] = fields.String(attribute='addr2')
>>> address_fields['city'] = fields.String(attribute='city')
>>> address_fields['state'] = fields.String(attribute='state')
>>> address_fields['zip'] = fields.String(attribute='zip')
>>>
>>> resource_fields = {}
>>> resource_fields['name'] = fields.String
>>> resource_fields['billing_address'] = fields.Nested(address_fields)
>>> resource_fields['shipping_address'] = fields.Nested(address_fields)
>>> address1 = {'addr1': '123 fake street', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> address2 = {'addr1': '555 nowhere', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> data = { 'name': 'bob', 'billing_address': address1, 'shipping_address': address2}
>>>
>>> json.dumps(marshal_with(data, resource_fields))
'{"billing_address": {"line 1": "123 fake street", "line 2": null, "state": "NY", "zip": "10468", "city": "New York"}, "name": "bob", "shipping_address": {"line 1": "555 nowhere", "line 2": null, "state": "NY", "zip": "10468", "city": "New York"}}'
This example uses two Nested
fields. The Nested
constructor takes a
dict of fields to render as sub-fields. The important difference between
the Nested
constructor and nested dicts (previous example), is the context
for attributes. In this example, billing_address
is a complex object that
has its own fields and the context passed to the nested field is the sub-object
instead of the original data
object. In other words:
data.billing_address.addr1
is in scope here, whereas in the previous
example data.addr1
was the location attribute. Remember: Nested
and
List
objects create a new scope for attributes.
Use Nested
with List
to marshal lists of more
complex objects:
user_fields = {
'id': fields.Integer,
'name': fields.String,
}
user_list_fields = {
fields.List(fields.Nested(user_fields)),
}
Extending Flask-RESTful¶
We realize that everyone has different needs in a REST framework. Flask-RESTful tries to be as flexible as possible, but sometimes you might find that the builtin functionality is not enough to meet your needs. Flask-RESTful has a few different extension points that can help in that case.
Content Negotiation¶
Out of the box, Flask-RESTful is only configured to support JSON. We made this
decision to give API maintainers full control of over API format support; so a
year down the road you don’t have to support people using the CSV
representation of your API you didn’t even know existed. To add additional
mediatypes to your API, you’ll need to declare your supported representations
on the Api
object.
app = Flask(__name__)
api = Api(app)
@api.representation('application/json')
def output_json(data, code, headers=None):
resp = make_response(json.dumps(data), code)
resp.headers.extend(headers or {})
return resp
These representation functions must return a Flask Response
object.
Note
Flask-RESTful uses the json
module from the Python standard library
instead of flask.json
because the Flask JSON serializer includes
serialization capabilities which are not in the JSON spec. If your
application needs these customizations, you can replace the default JSON
representation with one using the Flask JSON module as described above.
It is possible to configure how the default Flask-RESTful JSON representation
will format JSON by providing a RESTFUL_JSON
attribute on the application
configuration. This setting is a dictionary with keys that correspond to the
keyword arguments of json.dumps()
.
class MyConfig(object):
RESTFUL_JSON = {'separators': (', ', ': '),
'indent': 2,
'cls': MyCustomEncoder}
Note
If the application is running in debug mode (app.debug = True
) and
either sort_keys
or indent
are not declared in the RESTFUL_JSON
configuration setting, Flask-RESTful will provide defaults of True
and
4
respectively.
Custom Fields & Inputs¶
One of the most common additions to Flask-RESTful is to define custom types or fields based on your own data types.
Fields¶
Custom output fields let you perform your own output formatting without having
to modify your internal objects directly. All you have to do is subclass
Raw
and implement the format()
method:
class AllCapsString(fields.Raw):
def format(self, value):
return value.upper()
# example usage
fields = {
'name': fields.String,
'all_caps_name': AllCapsString(attribute=name),
}
Inputs¶
For parsing arguments, you might want to perform custom validation. Creating your own input types lets you extend request parsing with ease.
def odd_number(value):
if value % 2 == 0:
raise ValueError("Value is not odd")
return value
The request parser will also give you access to the name of the argument for cases where you want to reference the name in the error message.
def odd_number(value, name):
if value % 2 == 0:
raise ValueError("The parameter '{}' is not odd. You gave us the value: {}".format(name, value))
return value
You can also convert public parameter values to internal representations:
# maps the strings to their internal integer representation
# 'init' => 0
# 'in-progress' => 1
# 'completed' => 2
def task_status(value):
statuses = [u"init", u"in-progress", u"completed"]
return statuses.index(value)
Then you can use these custom input types in your
RequestParser
:
parser = reqparse.RequestParser()
parser.add_argument('OddNumber', type=odd_number)
parser.add_argument('Status', type=task_status)
args = parser.parse_args()
Response Formats¶
To support other representations (xml, csv, html), you can use the
representation()
decorator. You need to have a reference to your
API.
api = Api(app)
@api.representation('text/csv')
def output_csv(data, code, headers=None):
pass
# implement csv output!
These output functions take three parameters, data
, code
, and
headers
data
is the object you return from your resource method, code is the HTTP
status code that it expects, and headers are any HTTP headers to set in the
response. Your output function should return a flask.Response
object.
def output_json(data, code, headers=None):
"""Makes a Flask response with a JSON encoded body"""
resp = make_response(json.dumps(data), code)
resp.headers.extend(headers or {})
return resp
Another way to accomplish this is to subclass the Api
class and
provide your own output functions.
class Api(restful.Api):
def __init__(self, *args, **kwargs):
super(Api, self).__init__(*args, **kwargs)
self.representations = {
'application/xml': output_xml,
'text/html': output_html,
'text/csv': output_csv,
'application/json': output_json,
}
Resource Method Decorators¶
There is a property on the Resource
class called
method_decorators
. You can subclass the Resource and add your own
decorators that will be added to all method
functions in resource. For
instance, if you want to build custom authentication into every request.
def authenticate(func):
@wraps(func)
def wrapper(*args, **kwargs):
if not getattr(func, 'authenticated', True):
return func(*args, **kwargs)
acct = basic_authentication() # custom account lookup function
if acct:
return func(*args, **kwargs)
flask_restful.abort(401)
return wrapper
class Resource(flask_restful.Resource):
method_decorators = [authenticate] # applies to all inherited resources
Alternatively, you can specify a dictionary of iterables that map to HTTP methods and the decorators will only apply to matching requests.
def cache(f):
@wraps(f)
def cacher(*args, **kwargs):
# caching stuff
return cacher
class MyResource(restful.Resource):
method_decorators = {'get': [cache]}
def get(self, *args, **kwargs):
return something_interesting(*args, **kwargs)
def post(self, *args, **kwargs):
return create_something(*args, **kwargs)
In this case, the caching decorator would only apply to the GET request and not the POST request.
Since Flask-RESTful Resources are actually Flask view objects, you can also use standard flask view decorators.
Custom Error Handlers¶
Error handling is a tricky problem. Your Flask application may be wearing multiple hats, yet you want to handle all Flask-RESTful errors with the correct content type and error syntax as your 200-level requests.
Flask-RESTful will call the handle_error()
function on any 400 or 500 error that happens on a Flask-RESTful route, and
leave other routes alone. You may want your app to return an error message with
the correct media type on 404 Not Found errors; in which case, use the
catch_all_404s parameter of the Api
constructor.
app = Flask(__name__)
api = flask_restful.Api(app, catch_all_404s=True)
Then Flask-RESTful will handle 404s in addition to errors on its own routes.
Sometimes you want to do something special when an error occurs - log to a
file, send an email, etc. Use the got_request_exception()
method
to attach custom error handlers to an exception.
def log_exception(sender, exception, **extra):
""" Log an exception to our logging framework """
sender.logger.debug('Got exception during processing: %s', exception)
from flask import got_request_exception
got_request_exception.connect(log_exception, app)
Define Custom Error Messages¶
You may want to return a specific message and/or status code when certain errors are encountered during a request. You can tell Flask-RESTful how you want to handle each error/exception so you won’t have to fill your API code with try/except blocks.
errors = {
'UserAlreadyExistsError': {
'message': "A user with that username already exists.",
'status': 409,
},
'ResourceDoesNotExist': {
'message': "A resource with that ID no longer exists.",
'status': 410,
'extra': "Any extra information you want.",
},
}
Including the ‘status’ key will set the Response’s status code. If not specified it will default to 500.
Once your errors
dictionary is defined, simply pass it to the
Api
constructor.
app = Flask(__name__)
api = flask_restful.Api(app, errors=errors)
Intermediate Usage¶
This page covers building a slightly more complex Flask-RESTful app that will cover out some best practices when setting up a real-world Flask-RESTful-based API. The Quickstart section is great for getting started with your first Flask-RESTful app, so if you’re new to Flask-RESTful you’d be better off checking that out first.
Project Structure¶
There are many different ways to organize your Flask-RESTful app, but here we’ll describe one that scales pretty well with larger apps and maintains a nice level organization.
The basic idea is to split your app into three main parts: the routes, the resources, and any common infrastructure.
Here’s an example directory structure:
myapi/
__init__.py
app.py # this file contains your app and routes
resources/
__init__.py
foo.py # contains logic for /Foo
bar.py # contains logic for /Bar
common/
__init__.py
util.py # just some common infrastructure
The common directory would probably just contain a set of helper functions to fulfill common needs across your application. It could also contain, for example, any custom input/output types your resources need to get the job done.
In the resource files, you just have your resource objects. So here’s what
foo.py
might look like:
from flask_restful import Resource
class Foo(Resource):
def get(self):
pass
def post(self):
pass
The key to this setup lies in app.py
:
from flask import Flask
from flask_restful import Api
from myapi.resources.foo import Foo
from myapi.resources.bar import Bar
from myapi.resources.baz import Baz
app = Flask(__name__)
api = Api(app)
api.add_resource(Foo, '/Foo', '/Foo/<str:id>')
api.add_resource(Bar, '/Bar', '/Bar/<str:id>')
api.add_resource(Baz, '/Baz', '/Baz/<str:id>')
As you can imagine with a particularly large or complex API, this file ends up
being very valuable as a comprehensive list of all the routes and resources in
your API. You would also use this file to set up any config values
(before_request()
, after_request()
).
Basically, this file configures your entire API.
The things in the common directory are just things you’d want to support your resource modules.
Use With Blueprints¶
See Modular Applications with Blueprints in the Flask documentation for what blueprints are and
why you should use them. Here’s an example of how to link an Api
up to a Blueprint
.
from flask import Flask, Blueprint
from flask_restful import Api, Resource, url_for
app = Flask(__name__)
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
app.register_blueprint(api_bp)
Note
Calling Api.init_app()
is not required here because registering the
blueprint with the app takes care of setting up the routing for the
application.
Full Parameter Parsing Example¶
Elsewhere in the documentation, we’ve described how to use the reqparse example in detail. Here we’ll set up a resource with multiple input parameters that exercise a larger amount of options. We’ll define a resource named “User”.
from flask_restful import fields, marshal_with, reqparse, Resource
def email(email_str):
"""Return email_str if valid, raise an exception in other case."""
if valid_email(email_str):
return email_str
else:
raise ValueError('{} is not a valid email'.format(email_str))
post_parser = reqparse.RequestParser()
post_parser.add_argument(
'username', dest='username',
location='form', required=True,
help='The user\'s username',
)
post_parser.add_argument(
'email', dest='email',
type=email, location='form',
required=True, help='The user\'s email',
)
post_parser.add_argument(
'user_priority', dest='user_priority',
type=int, location='form',
default=1, choices=range(5), help='The user\'s priority',
)
user_fields = {
'id': fields.Integer,
'username': fields.String,
'email': fields.String,
'user_priority': fields.Integer,
'custom_greeting': fields.FormattedString('Hey there {username}!'),
'date_created': fields.DateTime,
'date_updated': fields.DateTime,
'links': fields.Nested({
'friends': fields.Url('user_friends'),
'posts': fields.Url('user_posts'),
}),
}
class User(Resource):
@marshal_with(user_fields)
def post(self):
args = post_parser.parse_args()
user = create_user(args.username, args.email, args.user_priority)
return user
@marshal_with(user_fields)
def get(self, id):
args = post_parser.parse_args()
user = fetch_user(id)
return user
As you can see, we create a post_parser
specifically to handle the parsing
of arguments provided on POST. Let’s step through the definition of each
argument.
post_parser.add_argument(
'username', dest='username',
location='form', required=True,
help='The user\'s username',
)
The username
field is the most normal out of all of them. It takes
a string from the POST body and converts it to a string type. This argument
is required (required=True
), which means that if it isn’t provided,
Flask-RESTful will automatically return a 400 with a message along the lines
of ‘the username field is required’.
post_parser.add_argument(
'email', dest='email',
type=email, location='form',
required=True, help='The user\'s email',
)
The email
field has a custom type of email
. A few lines earlier we
defined an email
function that takes a string and returns it if the type is
valid, else it raises an exception, exclaiming that the email type was
invalid.
post_parser.add_argument(
'user_priority', dest='user_priority',
type=int, location='form',
default=1, choices=range(5), help='The user\'s priority',
)
The user_priority
type takes advantage of the choices
argument. This
means that if the provided user_priority value doesn’t fall in the range
specified by the choices
argument (in this case [0, 1, 2, 3, 4]
),
Flask-RESTful will automatically respond with a 400 and a descriptive error
message.
That covers the inputs. We also defined some interesting field types in the
user_fields
dictionary to showcase a couple of the more exotic types.
user_fields = {
'id': fields.Integer,
'username': fields.String,
'email': fields.String,
'user_priority': fields.Integer,
'custom_greeting': fields.FormattedString('Hey there {username}!'),
'date_created': fields.DateTime,
'date_updated': fields.DateTime,
'links': fields.Nested({
'friends': fields.Url('user_friends', absolute=True),
'posts': fields.Url('user_friends', absolute=True),
}),
}
First up, there’s fields.FormattedString
.
'custom_greeting': fields.FormattedString('Hey there {username}!'),
This field is primarily used to interpolate values from the response into
other values. In this instance, custom_greeting
will always contain the
value returned from the username
field.
Next up, check out fields.Nested
.
'links': fields.Nested({
'friends': fields.Url('user_friends', absolute=True),
'posts': fields.Url('user_posts', absolute=True),
}),
This field is used to create a sub-object in the response. In this case,
we want to create a links
sub-object to contain urls of related objects.
Note that we passed fields.Nested another dict which is built in such a
way that it would be an acceptable argument to marshal()
by itself.
Finally, we used the fields.Url
field type.
'friends': fields.Url('user_friends', absolute=True),
'posts': fields.Url('user_friends', absolute=True),
It takes as its first parameter the name of the endpoint associated with the
urls of the objects in the links
sub-object. Passing absolute=True
ensures that the generated urls will have the hostname included.
Passing Constructor Parameters Into Resources¶
Your Resource
implementation may require outside dependencies. Those
dependencies are best passed-in through the constructor to loosely couple each
other. The Api.add_resource()
method has two keyword arguments:
resource_class_args
and resource_class_kwargs
. Their values will be forwarded
and passed into your Resource implementation’s constructor.
So you could have a Resource
:
from flask_restful import Resource
class TodoNext(Resource):
def __init__(self, **kwargs):
# smart_engine is a black box dependency
self.smart_engine = kwargs['smart_engine']
def get(self):
return self.smart_engine.next_todo()
You can inject the required dependency into TodoNext like so:
smart_engine = SmartEngine()
api.add_resource(TodoNext, '/next',
resource_class_kwargs={ 'smart_engine': smart_engine })
Same idea applies for forwarding args.
API Reference¶
If you are looking for information on a specific function, class or method, this part of the documentation is for you.
API Docs¶
-
flask_restful.
marshal
(data, fields, envelope=None)¶ Takes raw data (in the form of a dict, list, object) and a dict of fields to output and filters the data based on those fields.
Parameters: - data – the actual object(s) from which the fields are taken from
- fields – a dict of whose keys will make up the final serialized response output
- envelope – optional key that will be used to envelop the serialized response
>>> from flask_restful import fields, marshal >>> data = { 'a': 100, 'b': 'foo' } >>> mfields = { 'a': fields.Raw }
>>> marshal(data, mfields) OrderedDict([('a', 100)])
>>> marshal(data, mfields, envelope='data') OrderedDict([('data', OrderedDict([('a', 100)]))])
-
flask_restful.
marshal_with
(fields, envelope=None)¶ A decorator that apply marshalling to the return values of your methods.
>>> from flask_restful import fields, marshal_with >>> mfields = { 'a': fields.Raw } >>> @marshal_with(mfields) ... def get(): ... return { 'a': 100, 'b': 'foo' } ... ... >>> get() OrderedDict([('a', 100)])
>>> @marshal_with(mfields, envelope='data') ... def get(): ... return { 'a': 100, 'b': 'foo' } ... ... >>> get() OrderedDict([('data', OrderedDict([('a', 100)]))])
-
flask_restful.
marshal_with_field
(field)¶ A decorator that formats the return values of your methods with a single field.
>>> from flask_restful import marshal_with_field, fields >>> @marshal_with_field(fields.List(fields.Integer)) ... def get(): ... return ['1', 2, 3.0] ... >>> get() [1, 2, 3]
-
flask_restful.
abort
(http_status_code, **kwargs)¶ Raise a HTTPException for the given http_status_code. Attach any keyword arguments to the exception for later processing.
Api¶
-
class
flask_restful.
Api
(app=None, prefix='', default_mediatype='application/json', decorators=None, catch_all_404s=False, serve_challenge_on_401=False, url_part_order='bae', errors=None)¶ 应用程序的主要入口点。 您需要使用Flask应用程序对其进行初始化:
>>> app = Flask(__name__) >>> api = restful.Api(app)
或者,您可以使用
init_app()
在构建Flask应用程序之后设置Flask应用程序。Parameters: - app (flask.Flask or flask.Blueprint) - Flask应用程序对象
- prefix(str) - 将一个值设为所有路由的前缀,例如v1或2010-04-01
- default_mediatype(str) - 要返回的默认媒体类型
- decorators(list) - 附加到每个资源的装饰器
- catch_all_404s (bool) – Use
handle_error()
to handle 404 errors throughout your app - serve_challenge_on_401 – Whether to serve a challenge response to clients on receiving 401. This usually leads to a username/password popup in web browers.
- url_part_order – A string that controls the order that the pieces of the url are concatenated when the full url is constructed. ‘b’ is the blueprint (or blueprint registration) prefix, ‘a’ is the api prefix, and ‘e’ is the path component the endpoint is added with
- errors () – A dictionary to define a custom response for each exception or error raised during a request
-
add_resource
(resource, *urls, **kwargs)¶ 向api添加资源。
参数: 以上未指定的其他关键字参数将按原样传递给
flask.Flask.add_url_rule()
。例子:
api.add_resource(HelloWorld, '/', '/hello') api.add_resource(Foo, '/foo', endpoint="foo") api.add_resource(FooSpecial, '/special/foo', endpoint="foo")
-
error_router
(original_handler, e)¶ This function decides whether the error occured in a flask-restful endpoint or not. If it happened in a flask-restful endpoint, our handler will be dispatched. If it happened in an unrelated view, the app’s original error handler will be dispatched. In the event that the error occurred in a flask-restful endpoint but the local handler can’t resolve the situation, the router will fall back onto the original_handler as last resort.
Parameters: - original_handler (function) – the original Flask error handler for the app
- e (Exception) – the exception raised while handling the request
-
handle_error
(e)¶ API的错误处理程序将引发的异常转换为Flask响应,并带有适当的HTTP状态码和正文。
Parameters: e(Exception) - 引发的Exception对象
-
init_app
(app)¶ 使用给定的
flask.Flask
应用程序或flask.Blueprint
对象初始化此类。参数: app(flask.Blueprint) - Flask应用程序或蓝图对象 例子:
api = Api() api.add_resource(...) api.init_app(app)
-
make_response
(data, *args, **kwargs)¶ 为请求的媒体类型查找表示变换器,调用变换器创建响应对象。 如果找不到所请求的媒体类型的变换器,则此缺省值为default_mediatype。 如果default_mediatype为None,则按照RFC 2616第14.1节的规定发送406 Not Acceptable响应
Parameters: data - 包含要转换的响应数据的Python对象
-
mediatypes
()¶ 返回Accept标头中发送的请求介体类型列表
-
mediatypes_method
()¶ Return a method that returns a list of mediatypes
-
output
(resource)¶ Wraps a resource (as a flask view function), for cases where the resource does not directly return a response object
Parameters: resource – The resource as a flask view function
-
owns_endpoint
(endpoint)¶ Tests if an endpoint name (not path) belongs to this Api. Takes in to account the Blueprint name part of the endpoint name.
Parameters: endpoint – The name of the endpoint being checked Returns: bool
-
representation
(mediatype)¶ Allows additional representation transformers to be declared for the api. Transformers are functions that must be decorated with this method, passing the mediatype the transformer represents. Three arguments are passed to the transformer:
- The data to be represented in the response body
- The http status code
- A dictionary of headers
The transformer should convert the data appropriately for the mediatype and return a Flask response object.
Ex:
@api.representation('application/xml') def xml(data, code, headers): resp = make_response(convert_data_to_xml(data), code) resp.headers.extend(headers) return resp
-
resource
(*urls, **kwargs)¶ Wraps a
Resource
class, adding it to the api. Parameters are the same asadd_resource()
.Example:
app = Flask(__name__) api = restful.Api(app) @api.resource('/foo') class Foo(Resource): def get(self): return 'Hello, World!'
-
unauthorized
(response) Given a response, change it to ask for credentials
-
url_for
(resource, **values)¶ Generates a URL to the given resource.
Works like
flask.url_for()
.
-
class
flask_restful.
Resource
¶ Represents an abstract RESTful resource. Concrete resources should extend from this class and expose methods for each supported HTTP method. If a resource is invoked with an unsupported HTTP method, the API will return a response with status 405 Method Not Allowed. Otherwise the appropriate method is called and passed all arguments from the url rule used when adding the resource to an Api instance. See
add_resource()
for details.
ReqParse¶
-
class
reqparse.
RequestParser
(argument_class=<class 'reqparse.Argument'>, namespace_class=<class 'reqparse.Namespace'>, trim=False, bundle_errors=False)¶ Enables adding and parsing of multiple arguments in the context of a single request. Ex:
from flask_restful import reqparse parser = reqparse.RequestParser() parser.add_argument('foo') parser.add_argument('int_bar', type=int) args = parser.parse_args()
Parameters: -
add_argument
(*args, **kwargs)¶ Adds an argument to be parsed.
Accepts either a single instance of Argument or arguments to be passed into
Argument
’s constructor.See
Argument
’s constructor for documentation on the available options.
-
copy
()¶ Creates a copy of this RequestParser with the same set of arguments
-
parse_args
(req=None, strict=False, http_error_code=400)¶ Parse all arguments from the provided request and return the results as a Namespace
Parameters: - strict – if req includes args not in parser, throw 400 BadRequest exception
- http_error_code – use custom error code for flask_restful.abort()
-
remove_argument
(name)¶ Remove the argument matching the given name.
-
replace_argument
(name, *args, **kwargs)¶ Replace the argument matching the given name with a new version.
-
-
class
reqparse.
Argument
(name, default=None, dest=None, required=False, ignore=False, type=<function <lambda>>, location=('json', 'values'), choices=(), action='store', help=None, operators=('=', ), case_sensitive=True, store_missing=True, trim=False, nullable=True)¶ Parameters: - name – Either a name or a list of option strings, e.g. foo or -f, –foo.
- default – The value produced if the argument is absent from the request.
- dest – The name of the attribute to be added to the object
returned by
parse_args()
. - required (bool) – Whether or not the argument may be omitted (optionals only).
- action – The basic type of action to be taken when this argument is encountered in the request. Valid options are “store” and “append”.
- ignore – Whether to ignore cases where the argument fails type conversion
- type – The type to which the request argument should be
converted. If a type raises an exception, the message in the
error will be returned in the response. Defaults to
unicode
in python2 andstr
in python3. - location – The attributes of the
flask.Request
object to source the arguments from (ex: headers, args, etc.), can be an iterator. The last item listed takes precedence in the result set. - choices – A container of the allowable values for the argument.
- help – A brief description of the argument, returned in the response when the argument is invalid. May optionally contain an “{error_msg}” interpolation token, which will be replaced with the text of the error raised by the type converter.
- case_sensitive (bool) – Whether argument values in the request are case sensitive or not (this will convert all values to lowercase)
- store_missing (bool) – Whether the arguments default value should be stored if the argument is missing from the request.
- trim (bool) – If enabled, trims whitespace around the argument.
- nullable (bool) – If enabled, allows null value in argument.
-
__init__
(name, default=None, dest=None, required=False, ignore=False, type=<function <lambda>>, location=('json', 'values'), choices=(), action='store', help=None, operators=('=', ), case_sensitive=True, store_missing=True, trim=False, nullable=True)¶
-
handle_validation_error
(error, bundle_errors)¶ Called when an error is raised while parsing. Aborts the request with a 400 status and an error message
Parameters: - error – the error that was raised
- bundle_errors – do not abort when first error occurs, return a dict with the name of the argument and the error message to be bundled
-
parse
(request, bundle_errors=False)¶ Parses argument value(s) from the request, converting according to the argument’s type.
Parameters: request – The flask request object to parse arguments from - :param do not abort when first error occurs, return a
- dict with the name of the argument and the error message to be bundled
-
source
(request)¶ Pulls values off the request in the provided location :param request: The flask request object to parse arguments from
Fields¶
-
class
fields.
String
(default=None, attribute=None)¶ Marshal a value as a string. Uses
six.text_type
so values will be converted tounicode
in python2 andstr
in python3.-
format
(value)¶
-
-
class
fields.
FormattedString
(src_str)¶ FormattedString is used to interpolate other values from the response into this field. The syntax for the source string is the same as the string
format()
method from the python stdlib.Ex:
fields = { 'name': fields.String, 'greeting': fields.FormattedString("Hello {name}") } data = { 'name': 'Doug', } marshal(data, fields)
-
output
(key, obj)¶
-
-
class
fields.
Url
(endpoint=None, absolute=False, scheme=None, **kwargs)¶ A string representation of a Url
Parameters: -
output
(key, obj)¶
-
-
class
fields.
DateTime
(dt_format='rfc822', **kwargs)¶ Return a formatted datetime string in UTC. Supported formats are RFC 822 and ISO 8601.
See
email.utils.formatdate()
for more info on the RFC 822 format.See
datetime.datetime.isoformat()
for more info on the ISO 8601 format.Parameters: dt_format (str) – 'rfc822'
or'iso8601'
-
format
(value)¶
-
-
class
fields.
Float
(default=None, attribute=None)¶ A double as IEEE-754 double precision. ex : 3.141592653589793 3.1415926535897933e-06 3.141592653589793e+24 nan inf -inf
-
format
(value)¶
-
-
class
fields.
Integer
(default=0, **kwargs)¶ Field for outputting an integer value.
Parameters: default (int) – The default value for the field, if no value is specified. -
format
(value)¶
-
-
class
fields.
Arbitrary
(default=None, attribute=None)¶ - A floating point number with an arbitrary precision
- ex: 634271127864378216478362784632784678324.23432
-
format
(value)¶
-
class
fields.
Nested
(nested, allow_null=False, **kwargs)¶ Allows you to nest one set of fields inside another. See Advanced : Nested Field for more information
Parameters: - nested (dict) – The dictionary to nest
- allow_null (bool) – Whether to return None instead of a dictionary with null keys, if a nested dictionary has all-null keys
- kwargs – If
default
keyword argument is present, a nested dictionary will be marshaled as its value if nested dictionary is all-null keys (e.g. lets you return an empty JSON object instead of null)
-
output
(key, obj)¶
-
class
fields.
List
(cls_or_instance, **kwargs)¶ Field for marshalling lists of other fields.
See List Field for more information.
Parameters: cls_or_instance – The field type the list will contain. -
format
(value)¶
-
output
(key, data)¶
-
-
class
fields.
Raw
(default=None, attribute=None)¶ Raw provides a base field class from which others should extend. It applies no formatting by default, and should only be used in cases where data does not need to be formatted before being serialized. Fields should throw a
MarshallingException
in case of parsing problem.Parameters: - default – The default value for the field, if no value is specified.
- attribute – If the public facing value differs from the internal value, use this to retrieve a different attribute from the response than the publicly named value.
-
format
(value)¶ Formats a field’s value. No-op by default - field classes that modify how the value of existing object keys should be presented should override this and apply the appropriate formatting.
Parameters: value – The value to format Raises: MarshallingException – In case of formatting problem Ex:
class TitleCase(Raw): def format(self, value): return unicode(value).title()
-
output
(key, obj)¶ Pulls the value for the given key from the object, applies the field’s formatting and returns the result. If the key is not found in the object, returns the default value. Field classes that create values which do not require the existence of the key in the object should override this and return the desired value.
Raises: MarshallingException – In case of formatting problem
Inputs¶
-
inputs.
boolean
(value)¶ 将字符串
“true”
或“false”
解析为布尔型(不区分大小写)。 也分别接受“1”
和“0”
作为True
False
(单独的)。 如果输入来自请求JSON正文,则该类型已经是本机python布尔值,并且将不经进一步解析而通过。
-
inputs.
date
(value)¶ 以YYYY-mm-dd的格式解析有效的日期
-
inputs.
datetime_from_iso8601
(datetime_str)¶ 将ISO8601格式的日期转换为日期时间对象。
例:
inputs.datetime_from_iso8601("2012-01-01T23:30:00+02:00")
Parameters: datetime_str(str) - 要转换的符合ISO8601的字符串 Returns: 日期时间
-
inputs.
datetime_from_rfc822
(datetime_str)¶ 将RFC822格式的日期转换为日期时间对象。
例:
inputs.datetime_from_rfc822("Wed, 02 Oct 2002 08:00:00 EST")
Parameters: datetime_str(str) - 要转换的符合RFC822的字符串 Returns: 日期时间
-
class
inputs.
int_range
(low, high, argument='argument')¶ 将输入限制为一个范围内的整数(包含)
-
inputs.
iso8601interval
(value, argument='argument')¶ 将ISO 8601格式的日期时间间隔分析为日期时间的元组。
使用开始/结束或开始/持续时间表示法接受单个日期(时间)或完整时间间隔,并具有以下行为:
- 间隔定义为包含开始,独占结束
- 单日期时间被转换为跨越输入值中未指定的最大分辨率的时间间隔,直至当天。
- The smallest accepted resolution is 1 second.
- All timezones are accepted as values; returned datetimes are localized to UTC. Naive inputs and date inputs will are assumed UTC.
例子:
"2013-01-01" -> datetime(2013, 1, 1), datetime(2013, 1, 2) "2013-01-01T12" -> datetime(2013, 1, 1, 12), datetime(2013, 1, 1, 13) "2013-01-01/2013-02-28" -> datetime(2013, 1, 1), datetime(2013, 2, 28) "2013-01-01/P3D" -> datetime(2013, 1, 1), datetime(2013, 1, 4) "2013-01-01T12:00/PT30M" -> datetime(2013, 1, 1, 12), datetime(2013, 1, 1, 12, 30) "2013-01-01T06:00/2013-01-01T12:00" -> datetime(2013, 1, 1, 6), datetime(2013, 1, 1, 12)
Parameters: 值(str) - ISO8601日期时间为字符串 Returns: 两个UTC日期时间,指定时间间隔的开始和结束 Return type: 元组(datetime,datetime) Raises: ValueError,如果间隔无效。
-
inputs.
natural
(value, argument='argument')¶ 将输入类型限制为自然数(0,1,2,3 ...)
-
inputs.
positive
(value, argument='argument')¶ 将输入类型限制为正整数(1,2,3 ...)
-
class
inputs.
regex
(pattern, flags=0)¶ 基于正则表达式验证字符串。
例:
parser = reqparse.RequestParser() parser.add_argument('example', type=inputs.regex('^[0-9]+$'))
如果
example
参数包含除数字之外的任何内容,则它将被拒绝。参数:
其他注意事项¶
查看Flask的许可证以获取有关该项目的法律信息。
运行测试¶
包含Makefile
用于设置运行测试的virtualenv中。 你所需要做的就是运行:
$ make test
要更改用于运行测试的Python版本(默认为Python 2.7),请更改Makefile
顶部的PYTHON_MAJOR
和PYTHON_MINOR
。
您可以在所有支持的版本上运行:
$ make test-all
单独的测试可以使用以下格式的命令来运行:
nosetests <filename>:ClassName.func_name
例:
$ source env/bin/activate
$ nosetests tests/test_reqparse.py:ReqParseTestCase.test_parse_choices_insensitive
或者,如果您在Github上将更改推送到您的分支,Travis会自动为您的分支运行测试。
还提供了一个Tox配置文件,因此您可以在本地测试多个Python版本(2.6,2.7,3.3和3.4)
$ tox