Resource Representation
PostgREST uses proper HTTP content negotiation (RFC7231) to deliver a resource representation. That is to say the same API endpoint can respond in different formats like JSON or CSV depending on the request.
Response Format
Use the Accept request header to specify the acceptable format (or formats) for the response:
curl "http://localhost:3000/people" \
-H "Accept: application/json"
Builtin Media Type Handlers
Builtin handlers are offered for common standard media types.
text/csv
andapplication/json
, for all API endpoints. See Tables and Views and Functions as RPC.application/openapi+json
, for the root endpoint. See OpenAPI.application/geo+json
, see PostGIS.*/*
, resolves toapplication/json
for API endpoints and toapplication/openapi+json
for the root endpoint.
The following vendor media types handlers are also supported.
application/vnd.pgrst.plan
, see Execution plan.application/vnd.pgrst.object
andapplication/vnd.pgrst.array
, see Singular or Plural and Stripped Nulls.
Any unrecognized media type will throw an error.
curl "http://localhost:3000/people" \
-H "Accept: unknown/unknown"
HTTP/1.1 415 Unsupported Media Type
{"code":"PGRST107","details":null,"hint":null,"message":"None of these media types are available: unknown/unknown"}
To extend the accepted media types, you can use Media Type Handlers.
Singular or Plural
By default PostgREST returns all JSON results in an array, even when there is only one item. For example, requesting /items?id=eq.1
returns
[
{ "id": 1 }
]
This can be inconvenient for client code. To return the first result as an object unenclosed by an array, specify vnd.pgrst.object
as part of the Accept
header
curl "http://localhost:3000/items?id=eq.1" \
-H "Accept: application/vnd.pgrst.object+json"
This returns
{ "id": 1 }
with a Content-Type: application/vnd.pgrst.object+json
.
When a singular response is requested but no entries are found, the server responds with an error message and 406 Not Acceptable status code rather than the usual empty array and 200 status:
{
"message": "JSON object requested, multiple (or no) rows returned",
"details": "Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row",
"hint": null,
"code": "PGRST505"
}
Note
Many APIs distinguish plural and singular resources using a special nested URL convention e.g. /stories vs /stories/1. Why do we use /stories?id=eq.1? The answer is because a singular resource is (for us) a row determined by a primary key, and primary keys can be compound (meaning defined across more than one column). The more familiar nested urls consider only a degenerate case of simple and overwhelmingly numeric primary keys. These so-called artificial keys are often introduced automatically by Object Relational Mapping libraries.
Admittedly PostgREST could detect when there is an equality condition holding on all columns constituting the primary key and automatically convert to singular. However this could lead to a surprising change of format that breaks unwary client code just by filtering on an extra column. Instead we allow manually specifying singular vs plural to decouple that choice from the URL format.
Stripped Nulls
By default PostgREST returns all JSON null values. For example, requesting /projects?id=gt.10
returns
[
{ "id": 11, "name": "OSX", "client_id": 1, "another_col": "val" },
{ "id": 12, "name": "ProjectX", "client_id": null, "another_col": null },
{ "id": 13, "name": "Y", "client_id": null, "another_col": null }
]
On large result sets, the unused keys with null
values can waste bandwidth unnecessarily. To remove them, specify nulls=stripped
as a parameter of application/vnd.pgrst.array
:
curl "http://localhost:3000/projects?id=gt.10" \
-H "Accept: application/vnd.pgrst.array+json;nulls=stripped"
This returns
[
{ "id": 11, "name": "OSX", "client_id": 1, "another_col": "val" },
{ "id": 12, "name": "ProjectX" },
{ "id": 13, "name": "Y"}
]
Request Body
The server handles the following request body media types:
application/json
application/x-www-form-urlencoded
text/csv
For Tables and Views this works on POST
, PATCH
and PUT
methods. For Functions as RPC, it works on POST
methods.
For functions there are three additional types:
application/octet-stream
text/plain
text/xml