Customizing the ReSTful interface¶
This section describes how to use the keyword arguments to the
create_api()
method to customize the interface created by
Flask-Restless.
HTTP methods¶
By default, the APIManager.create_api()
method creates a read-only
interface; requests with HTTP methods other than GET will cause
a response with 405 Method Not Allowed. To explicitly specify which methods
should be allowed for the endpoint, pass a list as the value of keyword
argument methods
:
apimanager.create_api(Person, methods=['GET', 'POST', 'DELETE'])
This creates an endpoint at /api/person
which responds to
GET, POST, and DELETE methods, but
not to PATCH.
If you allow GET requests, you will have access to endpoints of the following forms.
-
GET
/api/person
¶
-
GET
/api/person/1
¶
-
GET
/api/person/1/comments
¶
-
GET
/api/person/1/relationships/comments
¶
-
GET
/api/person/1/comments/2
¶
The first four are described explicitly in the JSON API specification. The last is particular to Flask-Restless; it allows you to access a particular related resource via a relationship on another resource.
If you allow DELETE requests, you will have access to endpoints of the form
-
DELETE
/api/person/1
¶
If you allow POST requests, you will have access to endpoints of the form
-
POST
/api/person
¶
Finally, if you allow PATCH requests, you will have access to endpoints of the following forms.
-
PATCH
/api/person/1
¶
-
POST
/api/person/1/relationships/comments
¶
-
PATCH
/api/person/1/relationships/comments
¶
-
DELETE
/api/person/1/relationships/comments
¶
The last three allow the client to interact with the relationships of a
particular resource. The last two must be enabled explicitly by setting the
allow_to_many_replacement
and allow_delete_from_to_many_relationships
,
respectively, to True
when creating an API using the
APIManager.create_api()
method.
API prefix¶
To create an API at a prefix other than the default /api
, use the
url_prefix
keyword argument:
apimanager.create_api(Person, url_prefix='/api/v2')
Then your API for Person
will be available at /api/v2/person
.
Collection name¶
By default, the name of the collection that appears in the URLs of the API will
be the name of the table that backs your model. If your model is a SQLAlchemy
model, this will be the value of its __table__.name
attribute. If your
model is a Flask-SQLAlchemy model, this will be the lowercase name of the model
with camel case changed to all-lowercase with underscore separators. For
example, a class named MyModel
implies a collection name of
'my_model'
. Furthermore, the URL at which this collection is accessible by
default is /api/my_model
.
To provide a different name for the model, provide a string to the
collection_name keyword argument of the APIManager.create_api()
method:
apimanager.create_api(Person, collection_name='people')
Then the API will be exposed at /api/people
instead of /api/person
.
Note
According to the JSON API specification,
Note: This spec is agnostic about inflection rules, so the value of type can be either plural or singular. However, the same value should be used consistently throughout an implementation.
It’s up to you to make sure your collection names are either all plural or all singular!
Specifying one of many primary keys¶
If your model has more than one primary key (one called id
and one called
username
, for example), you should specify the one to use:
manager.create_api(User, primary_key='username')
If you do this, Flask-Restless will create URLs like /api/user/myusername
instead of /api/user/123
.
Capturing validation errors¶
By default, no validation is performed by Flask-Restless; if you want validation, implement it yourself in your database models. However, by specifying a list of exceptions raised by your backend on validation errors, Flask-Restless will forward messages from raised exceptions to the client in an error response.
For example, if your validation framework includes an exception called
ValidationError
, then call the APIManager.create_api()
method with
the validation_exceptions
keyword argument:
from cool_validation_framework import ValidationError
apimanager.create_api(Person, validation_exceptions=[ValidationError],
methods=['PATCH', 'POST'])
Note
Currently, Flask-Restless expects that an instance of a specified validation
error will have a errors
attribute, which is a dictionary mapping field
name to error description (note: one error per field). If you have a better,
more general solution to this problem, please visit our issue tracker.
Now when you make POST and PATCH requests with invalid fields, the JSON response will look like this:
HTTP/1.1 400 Bad Request
{
"errors": [
{
"status": 400,
"title": "Validation error",
"detail": "age: must be an integer"
}
]
}
Custom queries¶
In cases where it is not possible to use preprocessors or postprocessors
(Request preprocessors and postprocessors) efficiently, you can provide a custom query
attribute
to your model instead. The attribute can either be a SQLAlchemy query
expression or a class method that returns a SQLAlchemy query
expression. Flask-Restless will use this query
attribute internally,
however it is defined, instead of the default session.query(Model)
(in the
pure SQLAlchemy case) or Model.query
(in the Flask-SQLAlchemy
case). Flask-Restless uses a query during most GET and
PATCH requests to find the model(s) being requested.
You may want to use a custom query attribute if you want to reveal only certain information to the client. For example, if you have a set of people and you only want to reveal information about people from the group named “students”, define a query class method this way:
class Group(Base):
__tablename__ = 'group'
id = Column(Integer, primary_key=True)
groupname = Column(Unicode)
people = relationship('Person')
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
group_id = Column(Integer, ForeignKey('group.id'))
group = relationship('Group')
@classmethod
def query(cls):
original_query = session.query(cls)
condition = (Group.groupname == 'students')
return original_query.join(Group).filter(condition)
Then GET requests to, for example, /api/person
will only
reveal instances of Person
who also are in the group named “students”.
Bulk operations¶
Bulk operations are not supported, though they may be in the future.
Custom serialization and deserialization¶
You can provide a custom serializer using the serializer_class
keyword
argument and a custom deserializer using the deserializer_class
keyword
argument. For a full description of how to use these arguments, see
Custom serialization.
Request preprocessors and postprocessors¶
You can have custom code executed before or after Flask-Restless handles the
incoming request by using the preprocessors
and postprocessors
keyword
arguments, respectively. For a full description of how to use these arguments,
see Request preprocessors and postprocessors.