Skip to content

Migrating from Flask

Since APIFlask is a thin wrapper on top of Flask, you only need to change very little code to migrating your application to APIFlask (typically less than ten lines of code).

Flask class -> APIFlask class

It's how you create the Flask application:

from flask import Flask

app = Flask(__name__)

Now change to APIFlask:

from apiflask import APIFlask

app = APIFlask(__name__)

Blueprint class -> APIBlueprint class

It's how you create the Flask application:

from flask import Blueprint

bp = Blueprint('foo', __name__)

Now change to APIFlask:

from apiflask import APIBlueprint

bp = APIBlueprint('foo', __name__)

Tip

You can register a Blueprint object to an APIFlask instance, but you can't register an APIBlueprint object to a Flask instance.

Use route shortcuts (optional)

APIFlask provides some route shortcuts, you can update a view function:

@app.route('/pets', methods=['POST'])
def create_pet():
    return {'message': 'created'}

to:

@app.post('/pets')
def create_pet():
    return {'message': 'created'}

Tip

You can mix the use of app.route() with route shortcuts. Flask 2.0 will include these route shortcuts.

Class-based views (MethodView)

Version >= 0.5.0

This feature was added in the version 0.5.0.

APIFlask support to use the MethodView-based view class, for example:

from apiflask import APIFlask, Schema
from flask.views import MethodView

# ...

class Pet(MethodView):

    decorators = [doc(responses=[404])]

    @app.output(PetOut)
    def get(self, pet_id):
        pass

    @app.output({}, status_code=204)
    def delete(self, pet_id):
        pass

    @app.input(PetIn)
    @app.output(PetOut)
    def put(self, pet_id, json_data):
        pass

    @app.input(PetIn(partial=True))
    @app.output(PetOut)
    def patch(self, pet_id, json_data):
        pass

app.add_url_rule('/pets/<int:pet_id>', view_func=Pet.as_view('pet'))

The View-based view class is not supported, you can still use it but currently APIFlask can't generate OpenAPI spec (and API documentation) for it.

Other behavior changes and notes

Import statements

You only need to import APIFlask, APIBlueprint, and other utilities APIFlask provides from the apiflask package. For others, you still import them from the flask package:

from apiflask import APIFlask, APIBlueprint
from flask import request, render_template, g, session, url_for

APIFlask's abort() vs Flask's abort()

APIFlask's abort() function will return a JSON error response while Flask's abort() returns an HTML error page:

from apiflask import APIFlask, abort

app = APIFlask(__name__)

@app.get('/foo')
def foo():
    abort(404)

In the example above, when the user visits /foo, the response body will be:

{
    "detail": {},
    "message": "Not Found",
    "status_code": 404
}

You can use message and detail parameter to pass error message and detailed information in the abort() function.

Warning

The function abort_json() was renamed to abort() in the version 0.4.0.

JSON errors and mix the use of flask.abort() and apiflask.abort()

When you change the base application class to APIFlask, all the error responses will automatically convert to JSON format even if you use Flask's abort() function:

from apiflask import APIFlask
from flask import abort

app = APIFlask(__name__)

@app.get('/foo')
def foo():
    abort(404)

If you want to disable this behavior, just set json_errors parameter to False:

from apiflask import APIFlask

app = APIFlask(__name__, json_errors=False)

Now you can still use abort from apiflask package to return a JSON error response. To mix the use of flask.abort and apiflask.abort, you will need to import one of them with a different name:

from apiflask import abort as abort_json

Here is a full example:

from apiflask import APIFlask, abort as abort_json
from flask import abort

app = APIFlask(__name__, json_errors=False)


@app.get('/html-error')
def foo():
    abort(404)


@app.get('/json-error')
def bar():
    abort_json(404)

Pass positional arguments to view function

In APIFlask 1.x, to ensure the nature order of the arguments passed to the view function, it passes path arguments to view functions as positional arguments.

Assume a view like this:

@app.get('/<category>/articles/<int:article_id>')  # category, article_id
@app.input(ArticleQuery, location='query')  # query
@app.input(ArticleIn)  # data
def get_article(category, article_id, query, data):
    pass

With APIFlask, you can accept the arguments in the view function in a natural way (from left to right, from top to bottom):

def get_article(category, article_id, query, data)

This may causes issues when you use a custom decorator that access the arguments. So in the APIFlask 2.x, all the arguments passed to the view function will be keyword arguments.

The argument passed by the app.input() decorator will be named {location}_data, a custom argument name can be set with the arg_name argument. See more details in Basic Usage.

The return values of view function

For a simple view function without @app.output decorator, you can return a dict or a list as JSON response. The returned dict and list will be converted to a JSON response automatically (by calling jsonify() underlay).

Tip

Although list looks like tuple, only list return values will be serialized to JSON response. Tuple has special meaning.

Starting from Flask 2.2, the list return values are supported natively.

@app.get('/foo')
def foo():
    return {'message': 'foo'}


@app.get('/bar')
def bar():
    return ['foo', 'bar', 'baz']

When you added a @app.output decorator for your view function, APIFlask expects you to return an ORM/ODM model object or a dict/list that matches the schema you passed in the @app.output decorator. If you return a Response object, APIFlask will return it directly without any process.

Next step

Now your application is migrated to APIFlask. Check out the Basic Usage chapter to learn more about APIFlask. Enjoy!