Format of requests and responses¶
Requests and responses are all in JSON format, so the mimetype is
application/json. Ensure that requests you make that require a body
(PATCH and POST requests) have the header
Content-Type: application/json
; if they do not, the server will respond
with a 415 Unsupported Media Type.
Suppose we have the following Flask-SQLAlchemy models (the example works with pure SQLALchemy just the same):
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode, unique=True)
birth_date = db.Column(db.Date)
computers = db.relationship('Computer',
backref=db.backref('owner',
lazy='dynamic'))
class Computer(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode, unique=True)
vendor = db.Column(db.Unicode)
owner_id = db.Column(db.Integer, db.ForeignKey('person.id'))
purchase_time = db.Column(db.DateTime)
Also suppose we have registered an API for these models at /api/person
and
/api/computer
, respectively.
Note
API endpoints do not have trailing slashes. A request to, for example,
/api/person/
will result in a 404 Not Found response.
Note
For all requests that would return a list of results, the top-level JSON
object is a mapping from "objects"
to the list. JSON lists are not sent
as top-level objects for security reasons. For more information, see this.
-
GET
/api/person
¶ Gets a list of all
Person
objects.Sample response:
HTTP/1.1 200 OK { "num_results": 8, "total_pages": 3, "page": 2, "objects": [{"id": 1, "name": "Jeffrey", "age": 24}, ...] }
-
GET
/api/person?q=<searchjson>
¶ Gets a list of all
Person
objects which meet the criteria of the specified search. For more information on the format of the value of theq
parameter, see Making search queries.Sample response:
HTTP/1.1 200 OK { "num_results": 8, "total_pages": 3, "page": 2, "objects": [{"id": 1, "name": "Jeffrey", "age": 24}, ...] }
-
GET
/api/person/
(int: id)¶ Gets a single instance of
Person
with the specified ID.Sample response:
HTTP/1.1 200 OK {"id": 1, "name": "Jeffrey", "age": 24}
-
GET
/api/person/
(int: id)/computers
¶ Gets a list of all
Computer
objects which are owned by thePerson
object with the specified ID.Sample response:
HTTP/1.1 200 OK { "num_results": 2, "total_pages": 1, "page": 1, "objects": [{"id": 1, "vendor": "Apple", "name": "MacBook", ...}, ...] }
-
DELETE
/api/person/
(int: id)¶ Deletes the instance of
Person
with the specified ID.Sample response:
HTTP/1.1 204 No Content
-
DELETE
/api/person/
(int: id)/computers/
(int: id)¶ Removes the instance of
Computer
with the specified ID from thecomputers
collection of the instance ofPerson
with the specified ID. This is essentially a shortcut to using aPATCH /api/person/(int:id)/computers
request with aremove
parameter in the body of the request.Sample response:
HTTP/1.1 204 No Content
-
POST
/api/person
¶ Creates a new person with initial attributes specified as a JSON string in the body of the request.
Sample request:
POST /api/person HTTP/1.1 Host: example.com {"name": "Jeffrey", "age": 24}
Sample response:
HTTP/1.1 201 Created { "id": 1, "name": "Jeffrey", "age" 24, "computers": [] }
The server will respond with 400 Bad Request if the request specifies a field which does not exist on the model.
To create a new person which includes a related list of new computer instances via a one-to-many relationship, a request must take the following form.
Sample request:
POST /api/person HTTP/1.1 Host: example.com { "name": "Jeffrey", "age": 24, "computers": [ {"manufacturer": "Dell", "model": "Inspiron"}, {"manufacturer": "Apple", "model": "MacBook"} ] }
Sample response:
HTTP/1.1 201 Created { "id": 1, "name": "Jeffrey", "age": 24, "computers": [ {"id": 1, "manufacturer": "Dell", "model": "Inspiron"}, {"id": 2, "manufacturer": "Apple", "model": "MacBook"} ] }
Warning
The response does not denote that new instances have been created for the
Computer
models.To create a new person which includes a single related new computer instance (via a one-to-one relationship), a request must take the following form.
Sample request:
POST /api/person HTTP/1.1 Host: example.com { "name": "Jeffrey", "age": 24, "computer": {"manufacturer": "Dell", "model": "Inspiron"} }
Sample response:
HTTP/1.1 201 Created { "name": "Jeffrey", "age": 24, "id": 1, "computer": {"id": 1, "manufacturer": "Dell", "model": "Inspiron"} }
Warning
The response does not denote that a new
Computer
instance has been created.To create a new person which includes a related list of existing computer instances via a one-to-many relationship, a request must take the following form.
Sample request:
POST /api/person HTTP/1.1 Host: example.com { "name": "Jeffrey", "age": 24, "computers": [ {"id": 1}, {"id": 2} ] }
Sample response:
HTTP/1.1 201 Created { "id": 1, "name": "Jeffrey", "age": 24, "computers": [ {"id": 1, "manufacturer": "Dell", "model": "Inspiron"}, {"id": 2, "manufacturer": "Apple", "model": "MacBook"} ] }
To create a new person which includes a single related existing computer instance (via a one-to-one relationship), a request must take the following form.
Sample request:
POST /api/person HTTP/1.1 Host: example.com { "name": "Jeffrey", "age": 24, "computer": {"id": 1} }
Sample response:
HTTP/1.1 201 Created { "name": "Jeffrey", "age": 24, "id": 1, "computer": {"id": 1, "manufacturer": "Dell", "model": "Inspiron"} }
-
PATCH
/api/person
¶
-
PUT
/api/person
¶ Sets specified attributes on every instance of
Person
which meets the search criteria described in theq
parameter.The JSON object specified in the body of a PATCH request to this endpoint may include a mapping from q to the parameters for a search, as described in Making search queries. If no q key exists, then all instances of the model will be patched.
PUT /api/person
is an alias forPATCH /api/person
, because the latter is more semantically correct but the former is part of the core HTTP standard.The response will return a JSON object which specifies the number of instances in the
Person
database which were modified.Sample request:
Suppose the database contains exactly three people with the letter “y” in his or her name.
PATCH /api/person HTTP/1.1 Host: example.com { "age": 1, "q": {"filters": [{"name": "name", "op": "like", "val": "%y%"}]} }
Sample response:
HTTP/1.1 200 OK {"num_modified": 3}
-
PATCH
/api/person/
(int: id)¶
-
PUT
/api/person/
(int: id)¶ Sets specified attributes on the instance of
Person
with the specified ID number.PUT /api/person/1
is an alias forPATCH /api/person/1
, because the latter is more semantically correct but the former is part of the core HTTP standard.Sample request:
PATCH /api/person/1 HTTP/1.1 Host: example.com {"name": "Foobar"}
Sample response:
HTTP/1.1 200 OK {"id": 1, "name": "Foobar", "age": 24}
The server will respond with 400 Bad Request if the request specifies a field which does not exist on the model.
To add a list of existing objects to a one-to-many relationship, a request must take the following form.
Sample request:
PATCH /api/person/1 HTTP/1.1 Host: example.com { "computers": { "add": [ {"id": 1} ] } }
Sample response:
HTTP/1.1 200 OK { "id": 1, "name": "Jeffrey", "age": 24, "computers": [ {"id": 1, "manufacturer": "Dell", "model": "Inspiron"} ] }
To add a list of new objects to a one-to-many relationship, a request must take the following form.
Sample request:
PATCH /api/person/1 HTTP/1.1 Host: example.com { "computers": { "add": [ {"manufacturer": "Dell", "model": "Inspiron"} ] } }
Warning
The response does not denote that a new instance has been created for the
Computer
model.Sample response:
HTTP/1.1 200 OK { "id": 1, "name": "Jeffrey", "age": 24, "computers": [ {"id": 1, "manufacturer": "Dell", "model": "Inspiron"} ] }
Similarly, to add a new or existing instance of a related model to a one-to-one relationship, a request must take the following form.
Sample request:
PATCH /api/person/1 HTTP/1.1 Host: example.com { "computers": { "add": {"id": 1} } }
Sample response:
HTTP/1.1 200 OK { "id": 1, "name": "Jeffrey", "age": 24, "computers": [ {"id": 1, "manufacturer": "Dell", "model": "Inspiron"} ] }
To remove an existing object (without deleting that object from its own database) from a one-to-many relationship, a request must take the following form.
Sample request:
PATCH /api/person/1 HTTP/1.1 Host: example.com { "computers": { "remove": [ {"id": 2} ] } }
Sample response:
HTTP/1.1 200 OK { "id": 1, "name": "Jeffrey", "age": 24, "computers": [ {"id": 1, "manufacturer": "Dell", "model": "Inspiron 9300"}, {"id": 3, "manufacturer": "Apple", "model": "MacBook"} ] }
To remove an existing object from a one-to-many relationship and additionally delete it from its own database, a request must take the following form.
Sample request:
PATCH /api/person/1 HTTP/1.1 Host: example.com { "computers": { "remove": [ {"id": 2, "__delete__": true} ] } }
Warning
The response does not denote that the instance was deleted from its own database.
Sample response:
HTTP/1.1 200 OK { "id": 1, "name": "Jeffrey", "age": 24, "computers": [ {"id": 1, "manufacturer": "Dell", "model": "Inspiron 9300"}, {"id": 3, "manufacturer": "Apple", "model": "MacBook"} ] }
To set the value of a one-to-many relationship to contain either existing or new instances of the related model, a request must take the following form.
Sample request:
PATCH /api/person/1 HTTP/1.1 Host: example.com { "computers": [ {"id": 1}, {"id": 3}, {"manufacturer": "Lenovo", "model": "ThinkPad"} ] }
Sample response:
HTTP/1.1 200 OK { "id": 1, "name": "Jeffrey", "age": 24, "computers": [ {"id": 1, "manufacturer": "Dell", "model": "Inspiron 9300"}, {"id": 3, "manufacturer": "Apple", "model": "MacBook"} {"id": 4, "manufacturer": "Lenovo", "model": "ThinkPad"} ] }
To set the value of a one-to-many relationship and update fields on existing instances of the related model, a request must take the following form.
Suppose the
Person
instance looked like this before the sample PATCH request below:HTTP/1.1 200 OK { "id": 1, "name": "Jeffrey", "age": 24, "computers": [ {"id": 1, "manufacturer": "Apple", "model": "MacBook"} ] }
Sample request:
PATCH /api/person/1 HTTP/1.1 Host: example.com { "computers": [ {"id": 1, "manufacturer": "Lenovo", "model": "ThinkPad"} ] }
Sample response:
HTTP/1.1 200 OK { "id": 1, "name": "Jeffrey", "age": 24, "computers": [ {"id": 1, "manufacturer": "Lenovo", "model": "ThinkPad"} ] }
The changes reflected in this response have been made to the
Computer
instance with ID 1.
Date and time fields¶
Flask-Restless will automatically parse and convert date and time strings into the corresponding Python objects. Flask-Restless also understands intervals (also known as durations), if you specify the interval as an integer representing the number of seconds that the interval spans.
If you want the server to set the value of a date or time field of a model as
the current time (as measured at the server), use one of the special strings
"CURRENT_TIMESTAMP"
, "CURRENT_DATE"
, or "LOCALTIMESTAMP"
. When the
server receives one of these strings in a request, it will use the
corresponding SQL function to set the date or time of the field in the model.
Errors and error messages¶
Most errors return 400 Bad Request. A bad request, for example, will receive a response like this:
HTTP/1.1 400 Bad Request
{"message": "Unable to decode data"}
If your request triggers a SQLAlchemy DataError
,
IntegrityError
, or
ProgrammingError
, the session will be rolled back.
Function evaluation¶
If the allow_functions
keyword argument is set to True
when creating an
API for a model using APIManager.create_api()
, then an endpoint will be
made available for GET /api/eval/person
which responds to requests for
evaluation of functions on all instances the model.
Sample request:
GET /api/eval/person?q={"functions": [{"name": "sum", "field": "age"}, {"name": "avg", "field": "height"}]} HTTP/1.1
The format of the response is
HTTP/1.1 200 OK
{"sum__age": 100, "avg_height": 68}
If no functions are specified in the request, the response will contain
the empty JSON object, {}
.
Note
The functions whose names are given in the request will be evaluated using SQLAlchemy’s func object.
Example
To get the total number of rows in the query (that is, the number of
instances of the requested model), use count
as the name of the function
to evaluate, and id
for the field on which to evaluate it:
Request:
GET /api/eval/person?q={"functions": [{"name": "count", "field": "id"}]} HTTP/1.1
Response:
HTTP/1.1 200 OK
{"count__id": 5}
JSONP callbacks¶
Add a callback=myfunc
query parameter to the request URL on any
GET requests (including endpoints for function evaluation) to
have the JSON data of the response wrapped in the Javascript function
myfunc
. This can be used to circumvent some cross domain scripting security
issues. For example, a request like this:
GET /api/person/1?callback=foo HTTP/1.1
will produce a response like this:
HTTP/1.1 200 OK
foo({"meta": ..., "data": ...})
Then in your Javascript code, write the function foo
like this:
function foo(response) {
var meta, data;
meta = response.meta;
data = response.data;
// Do something cool here...
}
The metadata includes the status code and the values of the HTTP headers, including the Link headers parsed in JSON format. For example, a link that looks like this:
Link: <url1>; rel="next", <url2>; rel="foo"; bar="baz"
will look like this in the JSON metadata:
[
{"url": "url1", "rel": "next"},
{"url": "url2", "rel": "foo", "bar": "baz"}
]
The mimetype of a JSONP response is application/javascript
instead of the
usual application/json
, because the payload of such a response is not valid
JSON.
Pagination¶
Responses to GET requests are paginated by default, with at most
ten objects per page. To request a specific page, add a page=N
query
parameter to the request URL, where N
is a positive integer (the first page
is page one). If no page
query parameter is specified, the first page will
be returned.
In order to specify the number of results per page, add the query parameter
results_per_page=N
where N
is a positive integer. If
results_per_page
is greater than the maximum number of results per page as
configured by the server (see Server-side pagination), then the query
parameter will be ignored.
In addition to the "objects"
list, the response JSON object will have a
"page"
key whose value is the current page, a "num_pages"
key whose
value is the total number of pages into which the set of matching instances is
divided, and a "num_results"
key whose value is the total number of
instances which match the requested search. For example, a request to
GET /api/person?page=2
will result in the following response:
HTTP/1.1 200 OK
{
"num_results": 8,
"page": 2,
"num_pages": 3,
"objects": [{"id": 1, "name": "Jeffrey", "age": 24}, ...]
}
If pagination is disabled (by setting results_per_page=None
in
APIManager.create_api()
, for example), any page
key in the query
parameters will be ignored, and the response JSON will include a "page"
key
which always has the value 1
.
Note
As specified in in Query format, clients can receive responses with
limit
(a maximum number of objects in the response) and offset
(the
number of initial objects to skip in the response) applied. It is possible,
though not recommended, to use pagination in addition to limit
and
offset
. For simple clients, pagination should be fine.