API Bundle¶
Integrates Marshmallow and APISpec with SQLAlchemy and Flask Unchained.
Installation¶
Install dependencies:
pip install "flask-unchained[api]"
And enable the API bundle in your unchained_config.py
:
# your_project_root/unchained_config.py
BUNDLES = [
# ...
'flask_unchained.bundles.api',
'app',
]
Usage¶
The API bundle includes two extensions, Api
and Marshmallow
. The Api
extension is used for generating OpenAPI documentation and the Marshmallow
extension is used for serialization. These should be imported like so:
from flask_unchained.bundles.api import api, ma
Model Serializers¶
ModelSerializer
is very similar to Flask Marshmallow’s ModelSchema
. There are two differences:
dependency injection is automatically set up, and
we automatically convert field names to/from camel case when dumping/loading (although this is customizable)
Let’s say you have the following model:
# your_bundle/models.py
from flask_unchained.bundles.sqlalchemy import db
class User(db.Model):
name = db.Column(db.String)
email = db.Column(db.String)
password = db.Column(db.String)
A simple serializer for it would look like this:
# your_bundle/serializers.py
from flask_unchained.bundles.api import ma
from .models import User
class UserSerializer(ma.ModelSerializer):
class Meta:
model = User
One gotchya here is that Marshmallow has no way to know that the email column should use an email field. Therefore, we need to help it out a bit:
# your_bundle/serializers.py
from flask_unchained.bundles.api import ma
from .models import User
class UserSerializer(ma.ModelSerializer):
class Meta:
model = User
load_only = ('password',)
email = ma.Email(required=True)
There are three separate contexts for (de)serialization:
standard: dumping/loading a single object
many: dumping/loading multiple objects
create: creating a new object
By default, any serializers you define will be used for all three. This can be customized:
# your_bundle/serializers.py
from flask_unchained.bundles.api import ma
@ma.serializer(many=True)
class UserSerializerMany(ma.ModelSerializer):
# ...
@ma.serializer(create=True)
class UserSerializerCreate(ma.ModelSerializer):
# ...
Let’s make a model resource so we’ll have API routes for it:
Model Resources¶
# your_bundle/views.py
from flask_unchained.bundles.api import ModelResource
from .models import User
class UserResource(ModelResource):
class Meta:
model = User
Add it to your routes:
# your_app_bundle/routes.py
routes = lambda: [
prefix('/api/v1', [
resource('/users', UserResource),
],
]
And that’s it, unless you need to customize any behavior.
Model Resource Meta Options
ModelResource
inherits all of the meta options from Controller
and Resource
, and it adds some options of its own:
meta option name |
description |
default value |
---|---|---|
model |
The model class to use for the resource. |
|
serializer |
The serializer instance to use for (de)serializing an individual model. |
Determined automatically by the model name. Can be set manually to override the automatic discovery. |
serializer_create |
The serializer instance to use for loading data for creation of a new model. |
Determined automatically by the model name. Can be set manually to override the automatic discovery. |
serializer_many |
The serializer instance to use for (de)serializing a list of models. |
Determined automatically by the model name. Can be set manually to override the automatic discovery. |
include_methods |
A list of resource methods to automatically include. |
|
exclude_methods |
A list of resource methods to exclude. |
|
include_decorators |
A list of resource methods for which to automatically apply the default decorators. |
|
exclude_decorators |
A list of resource methods for which to not automatically apply the default decorators. |
|
method_decorators |
This can either be a list of decorators to apply to all methods, or a dictionary of method names to a list of decorators to apply for each method. In both cases, decorators specified here are run before the default decorators. |
|
API Docs¶
See API Bundle API