Framework Support¶
This section includes notes for using webargs with specific web frameworks.
Flask¶
Flask support is available via the webargs.flaskparser
module.
Decorator Usage¶
When using the use_args
decorator, the arguments dictionary will be before any URL variable parameters.
from webargs import fields
from webargs.flaskparser import use_args
@app.route("/user/<int:uid>")
@use_args({"per_page": fields.Int()}, location="query")
def user_detail(args, uid):
return ("The user page for user {uid}, showing {per_page} posts.").format(
uid=uid, per_page=args["per_page"]
)
Error Handling¶
Webargs uses Flask’s abort
function to raise an HTTPException
when a validation error occurs.
If you use the Flask.errorhandler
method to handle errors, you can access validation messages from the messages
attribute of
the attached ValidationError
.
Here is an example error handler that returns validation messages to the client as JSON.
from flask import jsonify
# Return validation errors as JSON
@app.errorhandler(422)
@app.errorhandler(400)
def handle_error(err):
headers = err.data.get("headers", None)
messages = err.data.get("messages", ["Invalid request."])
if headers:
return jsonify({"errors": messages}), err.code, headers
else:
return jsonify({"errors": messages}), err.code
URL Matches¶
The FlaskParser
supports parsing values from a request’s view_args
.
from webargs.flaskparser import use_args
@app.route("/greeting/<name>/")
@use_args({"name": fields.Str()}, location="view_args")
def greeting(args, **kwargs):
return "Hello {}".format(args["name"])
Django¶
Django support is available via the webargs.djangoparser
module.
Webargs can parse Django request arguments in both function-based and class-based views.
Decorator Usage¶
When using the use_args
decorator, the arguments dictionary will positioned after the request
argument.
Function-based Views
from django.http import HttpResponse
from webargs import Arg
from webargs.djangoparser import use_args
account_args = {
"username": fields.Str(required=True),
"password": fields.Str(required=True),
}
@use_args(account_args, location="form")
def login_user(request, args):
if request.method == "POST":
login(args["username"], args["password"])
return HttpResponse("Login page")
Class-based Views
from django.views.generic import View
from django.shortcuts import render_to_response
from webargs import fields
from webargs.djangoparser import use_args
blog_args = {"title": fields.Str(), "author": fields.Str()}
class BlogPostView(View):
@use_args(blog_args, location="query")
def get(self, request, args):
blog_post = Post.objects.get(title__iexact=args["title"], author=args["author"])
return render_to_response("post_template.html", {"post": blog_post})
Error Handling¶
The DjangoParser
does not override handle_error
, so your Django views are responsible for catching any ValidationErrors
raised by the parser and returning the appropriate HTTPResponse
.
from django.http import JsonResponse
from webargs import fields, ValidationError, json
argmap = {"name": fields.Str(required=True)}
def index(request):
try:
args = parser.parse(argmap, request)
except ValidationError as err:
return JsonResponse(err.messages, status=422)
except json.JSONDecodeError:
return JsonResponse({"json": ["Invalid JSON body."]}, status=400)
return JsonResponse({"message": "Hello {name}".format(name=name)})
Tornado¶
Tornado argument parsing is available via the webargs.tornadoparser
module.
The webargs.tornadoparser.TornadoParser
parses arguments from a tornado.httpserver.HTTPRequest
object. The TornadoParser
can be used directly, or you can decorate handler methods with use_args
or use_kwargs
.
import tornado.ioloop
import tornado.web
from webargs import fields
from webargs.tornadoparser import parser
class HelloHandler(tornado.web.RequestHandler):
hello_args = {"name": fields.Str()}
def post(self, id):
reqargs = parser.parse(self.hello_args, self.request)
response = {"message": "Hello {}".format(reqargs["name"])}
self.write(response)
application = tornado.web.Application([(r"/hello/([0-9]+)", HelloHandler)], debug=True)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
Decorator Usage¶
When using the use_args
decorator, the decorated method will have the dictionary of parsed arguments passed as a positional argument after self
and any regex match groups from the URL spec.
from webargs import fields
from webargs.tornadoparser import use_args
class HelloHandler(tornado.web.RequestHandler):
@use_args({"name": fields.Str()})
def post(self, id, reqargs):
response = {"message": "Hello {}".format(reqargs["name"])}
self.write(response)
application = tornado.web.Application([(r"/hello/([0-9]+)", HelloHandler)], debug=True)
As with the other parser modules, use_kwargs
will add keyword arguments to the view callable.
Error Handling¶
A HTTPError
will be raised in the event of a validation error. Your RequestHandlers
are responsible for handling these errors.
Here is how you could write the error messages to a JSON response.
from tornado.web import RequestHandler
class MyRequestHandler(RequestHandler):
def write_error(self, status_code, **kwargs):
"""Write errors as JSON."""
self.set_header("Content-Type", "application/json")
if "exc_info" in kwargs:
etype, exc, traceback = kwargs["exc_info"]
if hasattr(exc, "messages"):
self.write({"errors": exc.messages})
if getattr(exc, "headers", None):
for name, val in exc.headers.items():
self.set_header(name, val)
self.finish()
Pyramid¶
Pyramid support is available via the webargs.pyramidparser
module.
Decorator Usage¶
When using the use_args
decorator on a view callable, the arguments dictionary will be positioned after the request
argument.
from pyramid.response import Response
from webargs import fields
from webargs.pyramidparser import use_args
@use_args({"uid": fields.Str(), "per_page": fields.Int()}, location="query")
def user_detail(request, args):
uid = args["uid"]
return Response(
"The user page for user {uid}, showing {per_page} posts.".format(
uid=uid, per_page=args["per_page"]
)
)
As with the other parser modules, use_kwargs
will add keyword arguments to the view callable.
URL Matches¶
The PyramidParser
supports parsing values from a request’s matchdict.
from pyramid.response import Response
from webargs.pyramidparser import use_args
@use_args({"mymatch": fields.Int()}, location="matchdict")
def matched(request, args):
return Response("The value for mymatch is {}".format(args["mymatch"]))
Falcon¶
Falcon support is available via the webargs.falconparser
module.
Decorator Usage¶
When using the use_args
decorator on a resource method, the arguments dictionary will be positioned directly after the request and response arguments.
import falcon
from webargs import fields
from webargs.falconparser import use_args
class BlogResource:
request_args = {"title": fields.Str(required=True)}
@use_args(request_args)
def on_post(self, req, resp, args, post_id):
content = args["title"]
# ...
api = application = falcon.API()
api.add_route("/blogs/{post_id}")
As with the other parser modules, use_kwargs
will add keyword arguments to your resource methods.
Hook Usage¶
You can easily implement hooks by using parser.parse
directly.
import falcon
from webargs import fields
from webargs.falconparser import parser
def add_args(argmap, **kwargs):
def hook(req, resp, resource, params):
parsed_args = parser.parse(argmap, req=req, **kwargs)
req.context["args"] = parsed_args
return hook
@falcon.before(add_args({"page": fields.Int()}, location="query"))
class AuthorResource:
def on_get(self, req, resp):
args = req.context["args"]
page = args.get("page")
# ...
aiohttp¶
aiohttp support is available via the webargs.aiohttpparser
module.
The parse
method of AIOHTTPParser
is a coroutine
.
import asyncio
from aiohttp import web
from webargs import fields
from webargs.aiohttpparser import parser
handler_args = {"name": fields.Str(load_default="World")}
async def handler(request):
args = await parser.parse(handler_args, request)
return web.Response(body="Hello, {}".format(args["name"]).encode("utf-8"))
Decorator Usage¶
When using the use_args
decorator on a handler, the parsed arguments dictionary will be the last positional argument.
import asyncio
from aiohttp import web
from webargs import fields
from webargs.aiohttpparser import use_args
@use_args({"content": fields.Str(required=True)})
async def create_comment(request, args):
content = args["content"]
# ...
app = web.Application()
app.router.add_route("POST", "/comments/", create_comment)
As with the other parser modules, use_kwargs
will add keyword arguments to your resource methods.
Usage with coroutines¶
The use_args
and use_kwargs
decorators will work with both async def
coroutines and generator-based coroutines decorated with asyncio.coroutine
.
import asyncio
from aiohttp import web
from webargs import fields
from webargs.aiohttpparser import use_kwargs
hello_args = {"name": fields.Str(load_default="World")}
# The following are equivalent
@asyncio.coroutine
@use_kwargs(hello_args)
def hello(request, name):
return web.Response(body="Hello, {}".format(name).encode("utf-8"))
@use_kwargs(hello_args)
async def hello(request, name):
return web.Response(body="Hello, {}".format(name).encode("utf-8"))
URL Matches¶
The AIOHTTPParser
supports parsing values from a request’s match_info
.
from aiohttp import web
from webargs.aiohttpparser import use_args
@parser.use_args({"slug": fields.Str()}, location="match_info")
def article_detail(request, args):
return web.Response(body="Slug: {}".format(args["slug"]).encode("utf-8"))
app = web.Application()
app.router.add_route("GET", "/articles/{slug}", article_detail)
Bottle¶
Bottle support is available via the webargs.bottleparser
module.
Decorator Usage¶
The preferred way to apply decorators to Bottle routes is using the
apply
argument.
from bottle import route
user_args = {"name": fields.Str(load_default="Friend")}
@route("/users/<_id:int>", method="GET", apply=use_args(user_args))
def users(args, _id):
"""A welcome page."""
return {"message": "Welcome, {}!".format(args["name"]), "_id": _id}