Skip to main content
Examples

List & read

List rows with limit, offset and sort, and read one row by primary key - the exact routes, parameters, defaults and response shapes of a generated API.

Each table is served at /api/<schema>/<table>, for example /api/public/artist (PostgreSQL default schema public, SQL Server dbo, MySQL: the database name, Oracle: the connecting user, upper-cased). Column names in responses are exactly the table's column names.

Route Returns
GET /api/<schema>/<table> JSON array of rows
GET /api/<schema>/<table>/<id> One row as a JSON object, or 404

The examples assume the setup from Authentication (RESTWARD_API_URL, RESTWARD_API_KEY).

List rows

curl -s "$RESTWARD_API_URL/api/public/artist?limit=3" \
  -H "X-API-Key: $RESTWARD_API_KEY"
const url = new URL("/api/public/artist", process.env.RESTWARD_API_URL);
url.searchParams.set("limit", "3");

const rows = await (await fetch(url, { headers: { "X-API-Key": process.env.RESTWARD_API_KEY } })).json();
rows = session.get(f"{api}/api/public/artist", params={"limit": 3}).json()
var rows = await http.GetFromJsonAsync<List<Dictionary<string, JsonElement>>>("/api/public/artist?limit=3");
JSON
[
  { "artist_id": 1, "name": "AC/DC" },
  { "artist_id": 2, "name": "Accept" },
  { "artist_id": 3, "name": "Aerosmith" }
]

The response is the array itself. Add count=true to also get the total number of matching rows (see Total count), and see Pagination & sync for walking a whole table.

Query parameters

Parameter Meaning Default
limit Rows to return, clamped to 1–1000 100
offset Rows to skip (negative values count as 0) 0
sort Comma-separated columns; prefix - for descending: sort=artist_id,-title Primary key
fields Comma-separated columns to return: fields=title,artist_id All columns
count true adds the total number of matching rows false
<column>=<value>, <column>[op]=<value> Filters, see Filtering none

Rows are always in a stable order: without sort they are ordered by the primary key, and with sort the primary key breaks ties (sort=artist_id returns albums by artist, then by album_id). Only tables without a primary key have no guaranteed order.

A limit above 1000 returns 1000 rows. Non-numeric limit or offset values are ignored and the defaults apply. An unknown column in sort is a 400 naming the sort parameter.

curl -s "$RESTWARD_API_URL/api/public/album?sort=artist_id,-title&limit=3" \
  -H "X-API-Key: $RESTWARD_API_KEY"
const url = new URL("/api/public/album", process.env.RESTWARD_API_URL);
url.search = new URLSearchParams({ sort: "artist_id,-title", limit: "3" });
const albums = await (await fetch(url, { headers })).json();
albums = session.get(f"{api}/api/public/album", params={"sort": "artist_id,-title", "limit": 3}).json()
var albums = await http.GetFromJsonAsync<List<Dictionary<string, JsonElement>>>(
    "/api/public/album?sort=artist_id,-title&limit=3");
JSON
[
  { "album_id": 4, "title": "Let There Be Rock", "artist_id": 1 },
  { "album_id": 1, "title": "For Those About To Rock We Salute You", "artist_id": 1 },
  { "album_id": 3, "title": "Restless and Wild", "artist_id": 2 }
]

Choosing columns

fields returns only the listed columns, in the order you list them, for lists and for reading one row. The primary key is not added automatically: include it if you need it.

Shell
curl -s "$RESTWARD_API_URL/api/public/album?fields=title,artist_id&limit=2" -H "X-API-Key: $RESTWARD_API_KEY"
# [{"title":"For Those About To Rock We Salute You","artist_id":1},{"title":"Balls to the Wall","artist_id":2}]

curl -s "$RESTWARD_API_URL/api/public/album/1?fields=title" -H "X-API-Key: $RESTWARD_API_KEY"
# {"title":"For Those About To Rock We Salute You"}

An unknown column is a 400: {"error":"Unknown column 'genre' in fields on 'album'.","parameter":"fields"}.

Total count

count=true runs a second COUNT query with the same filters and changes the response to an object with the total and the page, plus an X-Total-Count header:

curl -si "$RESTWARD_API_URL/api/public/album?artist_id=90&limit=2&count=true" \
  -H "X-API-Key: $RESTWARD_API_KEY"
const url = new URL("/api/public/album", process.env.RESTWARD_API_URL);
url.search = new URLSearchParams({ artist_id: "90", limit: "2", count: "true" });
const { total, items } = await (await fetch(url, { headers })).json();
page = session.get(f"{api}/api/public/album", params={"artist_id": 90, "limit": 2, "count": "true"}).json()
total, items = page["total"], page["items"]
var page = await http.GetFromJsonAsync<JsonElement>("/api/public/album?artist_id=90&limit=2&count=true");
var total = page.GetProperty("total").GetInt64();
HTTP
HTTP/1.1 200
X-Total-Count: 21

{
  "total": 21,
  "items": [
    { "album_id": 94, "title": "A Matter of Life and Death", "artist_id": 90 },
    { "album_id": 95, "title": "A Real Dead One", "artist_id": 90 }
  ]
}

Counting costs an extra query that scans every matching row, so on large tables ask for it only when you need it (for example on the first page), not on every page. count must be true or false.

Read one row

Pass the primary key as the last path segment. For a composite primary key, pass the values comma-separated in key-column order: /api/public/playlist_track/1,3402.

curl -s "$RESTWARD_API_URL/api/public/album/1" \
  -H "X-API-Key: $RESTWARD_API_KEY"
const res = await fetch(`${process.env.RESTWARD_API_URL}/api/public/album/1`, { headers });
const album = res.status === 404 ? null : await res.json();
res = session.get(f"{api}/api/public/album/1")
album = None if res.status_code == 404 else res.json()
var res = await http.GetAsync("/api/public/album/1");
var album = res.StatusCode == HttpStatusCode.NotFound
    ? null
    : await res.Content.ReadFromJsonAsync<Dictionary<string, JsonElement>>();
JSON
{ "album_id": 1, "title": "For Those About To Rock We Salute You", "artist_id": 1 }
Situation Response
No row with that key 404 with an empty body
Key of the wrong type (/artist/abc on an integer key) 422 {"error":"Value 'abc' is not valid for column 'artist_id' of type 'integer'.","column":"artist_id"}
Composite key with the wrong number of values 400 with an error naming the key columns
Unknown table 404 with an empty body

Tables without a primary key are listable, but cannot be read, updated or deleted by key.

Caching

If the endpoint has a cache TTL (set on the dashboard's Endpoints page), GET responses are served from a cache for that many seconds. Each response says which:

HTTP
X-Cache: HIT
Age: 12
Cache-Control: private, max-age=18

A write through the API to the same table clears its cached responses immediately; changes made directly in the database show up once the TTL has passed.

Data types

Values are returned as the database driver reads them: numbers as JSON numbers, text as strings, NULL as null, and timestamps as ISO 8601 strings, for example "invoice_date": "2022-02-18T00:00:00" for a PostgreSQL timestamp column.

Reconnecting to server...

Please wait while we restore your connection

Connection lost

Retrying in seconds...

Unable to reconnect

The server connection has been lost.
You may need to log in again.

Session Paused

The server has temporarily paused your session.

Session Expired

Your session could not be resumed.
Please reload the page to continue.