English
API overview
Novodat exposes your database through a REST API and a GraphQL API. Both are generated from the schema: there is nothing to declare, and a new table or field is available as soon as it exists.
Base address
Every route hangs from PUBLIC_URL, for example https://data.example.com/items/articles. Requests and responses are JSON (application/json), except file uploads (multipart/form-data) and assets.
Collections, items and fields
| Term | In the database |
|---|---|
| Collection | A table or a view. On PostgreSQL with several schemas, tables outside the default one are named schema.table. |
| Item | A row. |
| Field | A column, or a relation with no column of its own (the "many" side of a relation). |
Your tables are read and written under /items/<collection>. Novodat's own tables (novodat_*) have their own routes: /users, /files, /collections… and are never reachable through /items.
Responses
A successful response wraps its result in data, with meta when you ask for counts:
json
{
"data": [{ "id": 1, "title": "Hello" }],
"meta": { "filter_count": 1 }
}Deletes, and writes whose result you may not read, answer 204 with no body.
Errors
Errors always come as a list, each with a stable code:
json
{
"errors": [
{
"message": "Value for field \"slug\" of collection \"articles\" has to be unique.",
"extensions": { "code": "RECORD_NOT_UNIQUE", "collection": "articles", "field": "slug" }
}
]
}Messages are in English and may change; programs should rely on extensions.code, and translate from it when they show the error to people.
| Code | Status | Meaning | Extra data |
|---|---|---|---|
FORBIDDEN | 403 | No permission, or the resource does not exist. Novodat never reveals whether something exists that you cannot see. | |
INVALID_CREDENTIALS | 401 | Wrong email or password. | |
INVALID_OTP | 401 | Missing or wrong two-factor code. | |
INVALID_TOKEN | 401 | The token is not valid, its session was closed or its user is no longer active. | |
TOKEN_EXPIRED | 401 | The access token expired: refresh it. | |
TFA_REQUIRED | 403 | A policy requires two-factor authentication, and the user has not set it up. | |
INVALID_PAYLOAD | 400 | The body is not valid. | path |
INVALID_QUERY | 400 | A query parameter is not valid. | parameter |
RECORD_NOT_UNIQUE | 400 | A unique value already exists. | collection, field |
VALUE_TOO_LONG | 400 | A value is longer than its field allows. | collection, field, maxLength |
CONTAINS_NULL_VALUES | 400 | A field cannot become required: some rows have no value. | collection, field |
VECTOR_DIMENSION_MISMATCH | 400 | A vector has the wrong number of dimensions. | field, expected, received |
UNSUPPORTED_FEATURE | 400 | The database engine does not offer this feature. | feature, engine |
ROUTE_NOT_FOUND | 404 | No such route. | path |
CONTENT_TOO_LARGE | 413 | The upload is too large. | limit |
RANGE_NOT_SATISFIABLE | 416 | The requested byte range is outside the file. | size |
REQUESTS_EXCEEDED | 429 | Too many requests or failed attempts. The Retry-After header says when to try again. | limit, retryAfter |
EXTENSION_MISSING | 500 | A PostgreSQL extension is needed and could not be installed. The message includes the command for an administrator. | extension, command |
SERVICE_UNAVAILABLE | 503 | A service Novodat needs (the database, an AI provider, a directory…) did not answer. | service |
INTERNAL | 500 | Unexpected error. Details stay in the server log. |
Request id
Every response carries an X-Request-Id header. Novodat keeps the one sent by the client or a proxy when it is safe (up to 128 letters, digits, ., _, : or -), or makes a new one. Logs use the same id, so it is the best thing to quote when reporting a problem.
Engine capabilities
Some features depend on the database engine (see PostgreSQL-only features). GET /database/capabilities tells what the current database offers:
json
{
"data": {
"engine": "postgres",
"capabilities": {
"vector": true, "customTypes": true, "arrays": true, "jsonb": true,
"multiSchema": true, "fullTextSearch": "tsvector", "geometry": "postgis", "…": "…"
}
}
}Features the engine lacks do not appear in GraphQL or OpenAPI, and using them anyway answers UNSUPPORTED_FEATURE.
OpenAPI
GET /server/specs/oas returns an OpenAPI 3.1 document of what the caller may do: only the collections, fields, operations and filter operators available to that user on this engine. Load it into Postman, Insomnia, Swagger UI or a client generator, using the token of the user the client will act as.
bash
curl -s https://data.example.com/server/specs/oas -H "Authorization: Bearer $TOKEN" > novodat.openapi.jsonServer routes
These need no authentication, except where noted.
| Route | Answer |
|---|---|
GET /server/health | { data: { status: "ok", checks: { database: { status, responseTimeMs } } } }, or 503 when the database does not answer. Not counted in the rate limits. |
GET /server/info | { data: { name: "Novodat", version } } |
GET /server/specs/oas | The OpenAPI document of the caller. |
GET /server/specs/graphql, GET /server/specs/graphql/system | The GraphQL schema of the caller, as SDL. |
GET /server/map | The base map in effect and how map fields are drawn. Signed-in users only. |
GET /database/capabilities | The engine and its capabilities. |
GET /database/extensions | PostgreSQL extensions available and installed. Administrators only. |
Next
- Authentication: getting and using tokens.
- Items and query parameters: reading and writing your data.