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!