Flask-RESTX
Flask-RESTX is a powerful extension for Flask that adds support for quickly building REST APIs. It encourages best practices with minimal setup and provides automatic documentation via Swagger UI. As a community-driven fork of Flask-RESTPlus, it is actively maintained, currently at version 1.3.2, with a consistent release cadence addressing compatibility with newer Flask, Werkzeug, and Python versions.
Warnings
- breaking Breaking changes related to Flask and Werkzeug versions. Prior to `flask-restx` 0.4.0, versions were incompatible with Flask/Werkzeug 2.0.0+. Version 0.4.0 pinned dependencies to `<2.0.0`. Versions 0.5.0 to <1.3.0 provided compatibility with Flask <3.0.0 by wrapping imports. `flask-restx` >=1.3.0 adds support for Flask >=3.0.0 and Flask >=2.0.0.
- breaking Python version compatibility has changed. Support for Python <3.7 was dropped in versions 1.0.1 and 1.2.0. The current minimum Python version required is 3.9.
- deprecated The `reqparse` module is considered deprecated and is slated for removal in Flask-RESTX 2.0. While still functional, it is recommended to transition to `api.model()` for request validation and serialization, or integrate with other input/output validation libraries like Marshmallow.
- gotcha When migrating from `Flask-RESTPlus`, all imports from `flask_restplus` must be changed to `flask_restx`. Additionally, configuration options (e.g., `RESTPLUS_SWAGGER_UI_DOC_EXPANSION`) should be updated from `RESTPLUS_` prefixes to `RESTX_`.
- gotcha Deploying Flask-RESTX applications behind a reverse proxy (like Nginx) with `werkzeug.middleware.proxy_fix.ProxyFix` can lead to issues where the Swagger UI interface incorrectly assumes its base paths (e.g., `/swaggerui`, `/api/swagger.json`), even if the API itself functions correctly under the proxy. This often requires complex Nginx configurations or serving Swagger UI assets statically.
Install
-
pip install flask-restx
Imports
- Api
from flask_restx import Api
- Resource
from flask_restx import Resource
- fields
from flask_restx import fields
- Namespace
from flask_restx import Namespace
- reqparse
from flask_restx import reqparse
- Api
from flask_restx import Api
Quickstart
from flask import Flask
from flask_restx import Api, Resource, fields
app = Flask(__name__)
api = Api(app, version='1.0', title='Example API', description='A simple API example')
# Define a namespace
ns = api.namespace('todos', description='TODO operations')
# Define a model for request/response serialization
todo_model = ns.model('Todo', {
'id': fields.Integer(readonly=True, description='The task unique identifier'),
'task': fields.String(required=True, description='The task details')
})
# A simple in-memory data store
class TodoDAO:
def __init__(self):
self.counter = 0
self.todos = []
def get(self, id):
for todo in self.todos:
if todo['id'] == id:
return todo
ns.abort(404, "Todo {} doesn't exist".format(id))
def create(self, data):
todo = data
self.counter += 1
todo['id'] = self.counter
self.todos.append(todo)
return todo
def update(self, id, data):
todo = self.get(id)
todo.update(data)
return todo
def delete(self, id):
todo = self.get(id)
self.todos.remove(todo)
DAO = TodoDAO()
DAO.create({'task': 'Build an API'})
DAO.create({'task': '?????'})
DAO.create({'task': 'profit!'})
@ns.route('/<int:id>')
@ns.param('id', 'The task identifier')
class Todo(Resource):
@ns.doc('get_todo')
@ns.marshal_with(todo_model)
def get(self, id):
'''Fetch a single todo item'''
return DAO.get(id)
@ns.doc('update_todo')
@ns.expect(todo_model)
@ns.marshal_with(todo_model)
def put(self, id):
'''Update a todo item given its identifier'''
return DAO.update(id, api.payload)
@ns.doc('delete_todo')
@ns.response(204, 'Todo deleted')
def delete(self, id):
'''Delete a todo item given its identifier'''
DAO.delete(id)
return '', 204
@ns.route('/')
class TodoList(Resource):
@ns.doc('list_todos')
@ns.marshal_list_with(todo_model)
def get(self):
'''List all todo items'''
return DAO.todos
@ns.doc('create_todo')
@ns.expect(todo_model)
@ns.marshal_with(todo_model, code=201)
def post(self):
'''Create a new todo item'''
return DAO.create(api.payload), 201
if __name__ == '__main__':
app.run(debug=True)