API responses and query parameters

Every Shaperail endpoint returns a consistent JSON envelope. This page documents the response shapes, error format, and query parameters available on list endpoints.


Response envelope

Single record (GET /resources/:id, PATCH /resources/:id)

HTTP 200 for GET and PATCH. HTTP 201 for POST.

{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "alice@example.com",
    "name": "Alice",
    "role": "admin",
    "created_at": "2026-01-15T09:30:00Z"
  }
}

List (GET /resources)

The meta object varies by pagination style.

Cursor pagination (default):

{
  "data": [
    { "id": "aaa-...", "name": "Alice" },
    { "id": "bbb-...", "name": "Bob" }
  ],
  "meta": {
    "cursor": "NTUwZTg0MDAtZTI5Yi00MWQ0LWE3MTYtNDQ2NjU1NDQwMDAw",
    "has_more": true
  }
}

cursor is null when there are no more pages. has_more is false on the last page.

Offset pagination:

{
  "data": [
    { "id": "aaa-...", "name": "Alice" },
    { "id": "bbb-...", "name": "Bob" }
  ],
  "meta": {
    "offset": 0,
    "limit": 25,
    "total": 42
  }
}

Bulk operations

{
  "data": [
    { "id": "aaa-...", "status": "created" },
    { "id": "bbb-...", "status": "created" }
  ],
  "meta": {
    "total": 2
  }
}

Delete (DELETE /resources/:id)

Returns HTTP 204 No Content with an empty body.


Error responses

All errors use the same envelope:

{
  "error": {
    "code": "NOT_FOUND",
    "status": 404,
    "message": "Resource not found",
    "request_id": "req-abc-123",
    "details": null
  }
}

Error codes

Status Code Meaning
401 UNAUTHORIZED Missing or invalid authentication.
403 FORBIDDEN Authenticated but insufficient permissions.
404 NOT_FOUND Resource does not exist.
409 CONFLICT Unique constraint or state conflict.
422 VALIDATION_ERROR One or more fields failed validation.
429 RATE_LIMITED Rate limit exceeded.
500 INTERNAL_ERROR Unexpected server error.

Validation errors

When the code is VALIDATION_ERROR, the details field contains an array of per-field errors:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "status": 422,
    "message": "Validation failed",
    "request_id": "req-def-456",
    "details": [
      { "field": "email", "message": "is required", "code": "required" },
      { "field": "name", "message": "too short", "code": "too_short" }
    ]
  }
}

Each entry in details has:

Key Type Description
field string The field that failed validation.
message string Human-readable description.
code string Machine-readable code (e.g. required, too_short).

For all other error codes, details is null.


Query parameters

All list endpoints accept the parameters below. Which filters and search fields are available depends on the resource file for that endpoint.

Filtering

Use bracket syntax on the filter key. Only fields declared in the endpoint’s filters list are accepted; all others are silently ignored.

GET /users?filter[role]=admin&filter[org_id]=550e8400-e29b-41d4-a716-446655440000

Filters produce exact-match WHERE clauses (field = value).

Sorting

Pass a comma-separated list of field names to sort. Prefix a field with - for descending order; no prefix means ascending.

GET /users?sort=-created_at,name

This sorts by created_at DESC, then name ASC. Only fields declared in the endpoint’s sort list are accepted.

Pass a plain-text term to search. The server performs a PostgreSQL full-text search across the fields declared in the endpoint’s search list.

GET /users?search=alice

The generated SQL uses to_tsvector('english', ...) and plainto_tsquery, so standard English stemming applies.

Pagination (cursor)

Cursor pagination is the default when pagination: cursor is set (or when no pagination style is specified).

GET /users?limit=10
GET /users?limit=10&after=NTUwZTg0MDAtZTI5Yi00MWQ0LWE3MTYtNDQ2NjU1NDQwMDAw
Parameter Default Range Description
limit 25 1 – 100 Number of records per page.
after Opaque cursor from previous meta.cursor.

Pagination (offset)

Available when the endpoint declares pagination: offset.

GET /users?limit=25&offset=0
GET /users?limit=25&offset=25
Parameter Default Range Description
limit 25 1 – 100 Number of records per page.
offset 0 >= 0 Number of records to skip.

Field selection

Return only specific fields by passing a comma-separated list to fields. If omitted, all fields are returned.

GET /users?fields=name,email
{
  "data": [
    { "name": "Alice", "email": "alice@example.com" },
    { "name": "Bob", "email": "bob@example.com" }
  ],
  "meta": { "cursor": "...", "has_more": true }
}

Relation loading

Request related resources with include. Pass a comma-separated list of relation names declared in the resource file’s relations block.

GET /users/550e8400-...?include=organization
GET /users?include=organization

Cache bypass

Skip the server-side cache for a single request:

GET /users?nocache=1

Combining parameters

All query parameters can be used together:

GET /users?filter[role]=admin&sort=-created_at&search=alice&limit=10&fields=name,email&include=organization

Back to top

Shaperail documentation lives in the same repository as the framework so every release has versioned instructions.

This site uses Just the Docs, a documentation theme for Jekyll.