One more sample query which is probably one of most useful ones in real life (by default, DESC ordering leads to NULLS FIRST option, this is not so clear for beginners), showing how to combine ordering direction and NULLS *** for the same column.
312 lines
9.0 KiB
Markdown
312 lines
9.0 KiB
Markdown
## Requesting Information
|
|
|
|
### Tables and Views
|
|
|
|
* ✅ Cacheable, prefetchable
|
|
* ✅ Idempotent
|
|
|
|
The list of accessible tables and views is provided at
|
|
|
|
```HTTP
|
|
GET /
|
|
```
|
|
|
|
Every view and table accessible by the active db role is exposed
|
|
in a one-level deep route. For instance the full contents of a table
|
|
`people` is returned at
|
|
|
|
```HTTP
|
|
GET /people
|
|
```
|
|
|
|
There are no `deeply/nested/routes`. Each route provides `OPTIONS`,
|
|
`GET`, `POST`, `PATCH`, and `DELETE` verbs depending entirely
|
|
on database permissions.
|
|
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Design Consideration</p>
|
|
|
|
<p>Why not provide nested routes? Many APIs allow nesting to
|
|
retrieve related information, such as <code>/films/1/director</code>.
|
|
We offer a more flexible mechanism (inspired by GraphQL) to embed
|
|
related information. It can handle one-to-many and many-to-many
|
|
relationships. This is covered in the section about Embedding.</p>
|
|
</div>
|
|
|
|
### Stored Procedures
|
|
|
|
* ❌ Cannot necessarily be cached or prefetched
|
|
* ❌ Not necessarily idempotent
|
|
|
|
Every stored procedure is accessible under the `/rpc` prefix. The
|
|
API endpoint supports only POST which executes the function.
|
|
|
|
```HTTP
|
|
POST /rpc/proc_name
|
|
```
|
|
|
|
PostgREST supports calling procedures with [named
|
|
arguments](http://www.postgresql.org/docs/9.4/static/sql-syntax-calling-funcs.html#SQL-SYNTAX-CALLING-FUNCS-NAMED).
|
|
Include a JSON object in the request payload and each
|
|
key/value of the object will become an argument.
|
|
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Design Consideration</p>
|
|
|
|
<p>Why the /rpc prefix? One reason is to avoid name collisions
|
|
between views and procedures. It also helps emphasize to API
|
|
consumers that these functions are not normal restful things.
|
|
The functions can have arbitrary and surprising behavior, not
|
|
the standard "post creates a resource" thing that users expect
|
|
from the other routes.</p>
|
|
|
|
<p>We considered allowing GET requests for functions that are
|
|
marked non-volatile but could not reconcile how to pass in
|
|
parameters. Query string arguments are reserved for shaping/filtering
|
|
the output, not providing input.</p>
|
|
</div>
|
|
|
|
|
|
|
|
### Filtering
|
|
|
|
#### Filtering Rows
|
|
|
|
You can filter result rows by adding conditions on columns, each
|
|
condition a query string parameter. For instance, to return people
|
|
aged under 13 years old:
|
|
|
|
```HTTP
|
|
GET /people?age=lt.13
|
|
```
|
|
|
|
Adding multiple parameters conjoins the conditions:
|
|
|
|
```HTTP
|
|
GET /people?age=gte.18&student=is.true
|
|
```
|
|
|
|
These operators are available:
|
|
|
|
abbreviation | meaning
|
|
------------ | -------
|
|
eq | equals
|
|
gt | greater than
|
|
lt | less than
|
|
gte | greater than or equal
|
|
lte | less than or equal
|
|
like | LIKE operator (use * in place of %)
|
|
ilike | ILIKE operator (use * in place of %)
|
|
@@ | full-text search using to_tsquery
|
|
is | checking for exact equality (null,true,false)
|
|
in | one of a list of values e.g. `?a=in.1,2,3`
|
|
not | negates another operator, see below
|
|
|
|
To negate any operator, prefix it with `not` like `?a=not.eq.2`.
|
|
|
|
For more complicated filters (such as those involving condition 1
|
|
*OR* condition 2) you will have to create a new view in the database.
|
|
|
|
Filters may be applied to [computed
|
|
columns](http://www.postgresql.org/docs/current/interactive/xfunc-sql.html#XFUNC-SQL-COMPOSITE-FUNCTIONS)
|
|
as well as actual table/view columns, even though the computed
|
|
columns will not appear in the output.
|
|
|
|
#### Filtering Columns
|
|
|
|
You can customize which columns are returned by using the `select`
|
|
parameter:
|
|
|
|
```HTTP
|
|
GET /people?select=age,height,weight
|
|
```
|
|
|
|
To cast the column types, add a double colon
|
|
|
|
```HTTP
|
|
GET /people?select=age::text,height,weight
|
|
```
|
|
|
|
Not all type coercions are possible, and you will get an error
|
|
describing any problems from selection or type casting.
|
|
|
|
The `select` keyword is reserved. You thus cannot filter rows based
|
|
on a column named select. Then again it is a reserved SQL keyword
|
|
too, hence an unlikely column name.
|
|
|
|
#### Inside JSONB
|
|
|
|
PostgreSQL >=9.4.2 supports native JSON columns and can even index
|
|
them by internal keys using the `jsonb` column type. PostgREST
|
|
allows you to filter results by internal JSON object values. Use
|
|
the single- and double-arrows to path into and obtain values, e.g.
|
|
|
|
```HTTP
|
|
GET /stuff?json_col->a->>b=eq.2
|
|
```
|
|
|
|
This query finds rows in `stuff` where `json_col->'a'->>'b'` is
|
|
equal to 2 (or "2" -- it coerces as needed). The final arrow must
|
|
be the double kind, `->>`, or else PostgREST will not attempt to
|
|
look inside the JSON.
|
|
|
|
### Ordering
|
|
|
|
The reserved word `order` reorders the response rows. It uses a
|
|
comma-separated list of columns and directions:
|
|
|
|
```HTTP
|
|
GET /people?order=age.desc,height.asc
|
|
```
|
|
|
|
If no direction is specified it defaults to descending order:
|
|
|
|
```HTTP
|
|
GET /people?order=age
|
|
```
|
|
|
|
If you care where nulls are sorted, add `nullsfirst` or `nullslast`:
|
|
|
|
```HTTP
|
|
GET /people?order=age.nullsfirst
|
|
GET /people?order=age.desc.nullslast
|
|
```
|
|
|
|
You can also use [computed
|
|
columns](http://www.postgresql.org/docs/current/interactive/xfunc-sql.html#XFUNC-SQL-COMPOSITE-FUNCTIONS)
|
|
to order the results, even though the computed
|
|
columns will not appear in the output.
|
|
|
|
### Limiting and Pagination
|
|
|
|
#### Pagination by Limit-Offset
|
|
|
|
PostgREST uses HTTP range headers for limiting and describing the
|
|
size of results. Every response contains the current range and total
|
|
results:
|
|
|
|
```
|
|
Range-Unit: items
|
|
Content-Range → 0-14/15
|
|
```
|
|
|
|
This means items zero through fourteen are returned out of a total
|
|
of fifteen -- i.e. all of them. This information is available in
|
|
every response and can help you render pagination controls on the
|
|
client. This is a RFC7233-compliant solution that keeps the response
|
|
JSON cleaner.
|
|
|
|
The client can set the limit and offset of a request by setting the
|
|
`Range` header. Translate the limit and offset into a range. To
|
|
request the first five elements, include these request headers:
|
|
|
|
```
|
|
Range-Unit: items
|
|
Range: 0-4
|
|
```
|
|
|
|
You can also use open-ended ranges for an offset with no limit:
|
|
`Range: 10-`.
|
|
|
|
#### Suppressing Counts
|
|
|
|
Sometimes knowing the total row count of a query is unnecessary and
|
|
only adds extra cost to the database query. So you can skip the
|
|
count total using a ```Prefer``` header as:
|
|
|
|
```
|
|
Prefer: count=none
|
|
```
|
|
|
|
With count suppressed the PostgREST response will look like:
|
|
|
|
```
|
|
Range-Unit: items
|
|
Content-Range → 0-14/*
|
|
```
|
|
|
|
### Embedding Foreign Entities
|
|
|
|
Suppose you have a `projects` table which references `clients` through
|
|
a foreign key called `client_id`. When listing projects through the
|
|
API you can have it embed the client within each project response.
|
|
For example,
|
|
|
|
```HTTP
|
|
GET /projects?id=eq.1&select=id, name, clients{*}
|
|
```
|
|
|
|
Notice this is the same `select` keyword which is used to choose
|
|
which columns to include. When a column name is followed by parentheses
|
|
that means to fetch the entire record and nest it. You include a
|
|
list of columns inside the parens, or asterisk to request all
|
|
columns.
|
|
|
|
The embedding works for 1-N, N-1, and N-N relationships. That means
|
|
you could also ask for a client and all their projects:
|
|
|
|
```HTTP
|
|
GET /clients?id=eq.42&select=id, name, projects{*}
|
|
```
|
|
|
|
In the examples above we asked for all columns in the embedded resource
|
|
but the the select query is recursive. You could for instance specify
|
|
|
|
|
|
```HTTP
|
|
GET /foo?select=x, y, bar{z, w, baz{*}}
|
|
```
|
|
|
|
### Response Format
|
|
|
|
Query responses default to JSON but you can get them in CSV as well. Just make your request with the header
|
|
|
|
```HTTP
|
|
Accept: text/csv
|
|
```
|
|
|
|
### Singular vs Plural
|
|
|
|
Many APIs distinguish plural and singular resources, e.g.`/stories`
|
|
vs `/stories/1`. Why do we use `/stories?id=eq.1`? It is because a
|
|
single 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 common urls come from a degenerate case of simple
|
|
(and overwhelmingly numeric) primary keys often introduced automatically
|
|
be Object Relational Mapping.
|
|
|
|
For consistency's sake all these endpoints return a JSON array,
|
|
`/stories`, `/stories?genre=eq.mystery`, `/stories?id=eq.1`. They
|
|
are all filtering a bigger array. However you might want the
|
|
last one to return a single JSON object, not an array with one
|
|
element. To request a singular response send the header
|
|
`Prefer: plurality=singular`.
|
|
|
|
### Data Schema
|
|
|
|
As well as issuing a `GET /` to obtain a list of the tables, views,
|
|
and stored procedures available, you can get more information about
|
|
any particular endpoint.
|
|
|
|
```HTTP
|
|
OPTIONS /my_view
|
|
```
|
|
|
|
This will include the row names, their types, primary key
|
|
information, and foreign keys for the given table or view.
|
|
|
|
<div class="admonition danger">
|
|
<p class="admonition-title">Deprecation Warning</p>
|
|
|
|
<p>Although we currently use the OPTIONS verb for this, some
|
|
people <a
|
|
href="https://www.mnot.net/blog/2012/10/29/NO_OPTIONS">argue</a> that
|
|
this is inappropriate. We are considering a <code>describedby</code>
|
|
header link instead.</p>
|
|
</div>
|
|
|
|
### CORS
|
|
|
|
PostgREST sets highly permissive cross origin resource sharing. It
|
|
accepts Ajax requests from any domain.
|