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:

GET /people HTTP/1.1
Accept: application/json

Builtin Media Type Handlers

Builtin handlers are offered for common standard media types.

  • text/csv and application/json, for all API endpoints. See Tables and Views and Stored Procedures.

  • application/openapi+json, for the root endpoint. See OpenAPI.

  • application/geo+json, see PostGIS.

  • */*, resolves to application/json for API endpoints and to application/openapi+json for the root endpoint.

The following vendor media types handlers are also supported.

Any unrecognized media type will throw an error.

GET /people HTTP/1.1
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

GET /items?id=eq.1 HTTP/1.1
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"


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 bandwith unnecessarily. To remove them, specify nulls=stripped as a parameter of application/vnd.pgrst.array:

GET /projects?id=gt.10 HTTP/1.1
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 Stored Procedures, it works on POST methods.

For stored procedures there are three additional types:

  • application/octet-stream

  • text/plain

  • text/xml

See Functions with a single unnamed parameter.