This section includes notes for using webargs with specific web frameworks.
Flask support is available via the webargs.flaskparser
module.
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()})
def user_detail(args, uid):
return ("The user page for user {uid}, " "showing {per_page} posts.").format(
uid=uid, per_page=args["per_page"]
)
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
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 support is available via the webargs.djangoparser
module.
Webargs can parse Django request arguments in both function-based and class-based views.
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)
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)
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})
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 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()
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.
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 support is available via the webargs.pyramidparser
module.
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()})
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.
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()}, locations=("matchdict",))
def matched(request, args):
return Response("The value for mymatch is {}".format(args["mymatch"]))
Falcon support is available via the webargs.falconparser
module.
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.
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, 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 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(missing="World")}
async def handler(request):
args = await parser.parse(handler_args, request)
return web.Response(body="Hello, {}".format(args["name"]).encode("utf-8"))
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.
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(missing="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"))
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 support is available via the webargs.bottleparser
module.
The preferred way to apply decorators to Bottle routes is using the
apply
argument.
from bottle import route
user_args = {"name": fields.Str(missing="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}