Quickback Docs

CRUD Endpoints

Auto-generated RESTful CRUD endpoints for each resource. Learn how to use list, get, create, update, and delete operations with filtering and pagination.

Quickback automatically generates RESTful CRUD endpoints for each resource you define. This page covers how to use these endpoints.

Endpoint Overview

For a resource named rooms, Quickback generates:

MethodEndpointDescription
GET/roomsList all records
GET/rooms/:idGet a single record
POST/roomsCreate a new record
POST/rooms/batchBatch create multiple records
PATCH/rooms/:idUpdate a record
PATCH/rooms/batchBatch update multiple records
DELETE/rooms/:idDelete a record
DELETE/rooms/batchBatch delete multiple records
PUT/rooms/:idUpsert a record (requires config)
PUT/rooms/batchBatch upsert multiple records (requires config)

List Records

GET /rooms

Returns a paginated list of records the user has access to.

Query Parameters

ParameterDescriptionExample
limitNumber of records to return (default: 50, max: 100)?limit=25
offsetNumber of records to skip?offset=50
sortField to sort by?sort=createdAt
orderSort direction: asc or desc?order=desc

Filtering

Filter records using query parameters:

GET /rooms?status=active                    # Exact match
GET /rooms?capacity.gt=10                   # Greater than
GET /rooms?capacity.gte=10                  # Greater than or equal
GET /rooms?capacity.lt=50                   # Less than
GET /rooms?capacity.lte=50                  # Less than or equal
GET /rooms?status.ne=deleted                # Not equal
GET /rooms?name.like=Conference             # Pattern match (LIKE %value%)
GET /rooms?status.in=active,pending,review  # IN clause

Response

{
  "data": [
    {
      "id": "room_123",
      "name": "Conference Room A",
      "capacity": 10,
      "roomTypeId": "rt_456",
      "roomType_label": "Conference",
      "status": "active",
      "createdAt": "2024-01-15T10:30:00Z"
    }
  ],
  "pagination": {
    "limit": 50,
    "offset": 0,
    "count": 1
  }
}

FK Label Resolution

Foreign key columns are automatically enriched with _label fields containing the referenced table's display value. For example, roomTypeId gets a corresponding roomType_label field. See Display Column for details.

Get Single Record

GET /rooms/:id

Returns a single record by ID.

Response

{
  "id": "room_123",
  "name": "Conference Room A",
  "capacity": 10,
  "roomTypeId": "rt_456",
  "roomType_label": "Conference",
  "status": "active",
  "createdAt": "2024-01-15T10:30:00Z"
}

Errors

StatusDescription
404Record not found or not accessible
403User lacks permission to view this record

Create Record

POST /rooms
Content-Type: application/json

{
  "name": "Conference Room B",
  "capacity": 8,
  "roomType": "meeting"
}

Creates a new record. Only fields listed in guards.createable are accepted.

Response

{
  "data": {
    "id": "room_456",
    "name": "Conference Room B",
    "capacity": 8,
    "roomType": "meeting",
    "createdAt": "2024-01-15T11:00:00Z",
    "createdBy": "user_789"
  }
}

Errors

StatusDescription
400Invalid field or missing required field
403User lacks permission to create records

Update Record

PATCH /rooms/:id
Content-Type: application/json

{
  "name": "Updated Room Name",
  "capacity": 12
}

Updates an existing record. Only fields listed in guards.updatable are accepted.

Response

{
  "data": {
    "id": "room_123",
    "name": "Updated Room Name",
    "capacity": 12,
    "modifiedAt": "2024-01-15T12:00:00Z",
    "modifiedBy": "user_789"
  }
}

Errors

StatusDescription
400Invalid field or field not updatable
403User lacks permission to update this record
404Record not found

Delete Record

DELETE /rooms/:id

Deletes a record. Behavior depends on the delete.mode configuration.

Soft Delete (default)

Sets deletedAt and deletedBy fields. Record remains in database but is filtered from queries.

Hard Delete

Permanently removes the record from the database.

Response

{
  "data": {
    "id": "room_123",
    "deleted": true
  }
}

Errors

StatusDescription
403User lacks permission to delete this record
404Record not found

Upsert Record (PUT)

PUT /rooms/:id
Content-Type: application/json

{
  "name": "External Room",
  "capacity": 20,
  "externalId": "ext-123"
}

Creates or updates a record by ID. Requires special configuration:

  1. generateId: false in database config
  2. guards: false in resource definition

Behavior

  • If record exists: Updates all provided fields
  • If record doesn't exist: Creates with the provided ID

Use Cases

  • Syncing data from external systems
  • Webhook handlers with external IDs
  • Idempotent operations (safe to retry)

See Guards documentation for setup details.

Batch Operations

Quickback provides batch endpoints for efficient bulk operations. Batch operations automatically inherit from their corresponding CRUD operations and maintain full security layer consistency.

Batch Create Records

POST /rooms/batch
Content-Type: application/json

{
  "records": [
    { "name": "Room A", "capacity": 10 },
    { "name": "Room B", "capacity": 20 },
    { "name": "Room C", "capacity": 15 }
  ],
  "options": {
    "atomic": false
  }
}

Creates multiple records in a single request. Each record follows the same validation rules as single create operations.

Request Body

FieldTypeDescription
recordsArrayArray of record objects to create
options.atomicBooleanIf true, all records succeed or all fail (default: false)

Response (Partial Success - Default)

{
  "success": [
    { "id": "room_1", "name": "Room A", "capacity": 10 },
    { "id": "room_2", "name": "Room B", "capacity": 20 }
  ],
  "errors": [
    {
      "index": 2,
      "record": { "name": "Room C", "capacity": 15 },
      "error": {
        "error": "Field cannot be set during creation",
        "layer": "guards",
        "code": "GUARD_FIELD_NOT_CREATEABLE",
        "details": { "fields": ["status"] }
      }
    }
  ],
  "meta": {
    "total": 3,
    "succeeded": 2,
    "failed": 1,
    "atomic": false
  }
}

HTTP Status Codes

  • 201 - All records created successfully
  • 207 - Partial success (some records failed)
  • 400 - Atomic mode enabled and one or more records failed

Batch Size Limit

Default: 100 records per request (configurable via maxBatchSize)

Batch Update Records

PATCH /rooms/batch
Content-Type: application/json

{
  "records": [
    { "id": "room_1", "capacity": 12 },
    { "id": "room_2", "name": "Updated Room B" },
    { "id": "room_3", "capacity": 25 }
  ],
  "options": {
    "atomic": false
  }
}

Updates multiple records in a single request. All records must include an id field.

Request Body

FieldTypeDescription
recordsArrayArray of record objects with id and fields to update
options.atomicBooleanIf true, all records succeed or all fail (default: false)

Response

{
  "success": [
    { "id": "room_1", "capacity": 12, "modifiedAt": "2024-01-15T14:00:00Z" },
    { "id": "room_2", "name": "Updated Room B", "modifiedAt": "2024-01-15T14:00:00Z" }
  ],
  "errors": [
    {
      "index": 2,
      "record": { "id": "room_3", "capacity": 25 },
      "error": {
        "error": "Not found",
        "layer": "firewall",
        "code": "NOT_FOUND",
        "details": { "id": "room_3" }
      }
    }
  ],
  "meta": {
    "total": 3,
    "succeeded": 2,
    "failed": 1,
    "atomic": false
  }
}

Features

  • Batch fetching: Single database query for all IDs (with firewall)
  • Per-record access: Access checks run with record context
  • Field validation: Guards apply to each record individually

Batch Delete Records

DELETE /rooms/batch
Content-Type: application/json

{
  "ids": ["room_1", "room_2", "room_3"],
  "options": {
    "atomic": false
  }
}

Deletes multiple records in a single request. Supports both soft and hard delete modes.

Request Body

FieldTypeDescription
idsArrayArray of record IDs to delete
options.atomicBooleanIf true, all records succeed or all fail (default: false)

Response (Soft Delete)

{
  "success": [
    { "id": "room_1", "deletedAt": "2024-01-15T15:00:00Z", "deletedBy": "user_789" },
    { "id": "room_2", "deletedAt": "2024-01-15T15:00:00Z", "deletedBy": "user_789" }
  ],
  "errors": [
    {
      "index": 2,
      "id": "room_3",
      "error": {
        "error": "Not found",
        "layer": "firewall",
        "code": "NOT_FOUND",
        "details": { "id": "room_3" }
      }
    }
  ],
  "meta": {
    "total": 3,
    "succeeded": 2,
    "failed": 1,
    "atomic": false
  }
}

Delete Modes

  • Soft delete (default): Sets deletedAt, deletedBy, modifiedAt, modifiedBy fields
  • Hard delete: Permanently removes records from database

Batch Upsert Records

PUT /rooms/batch
Content-Type: application/json

{
  "records": [
    { "id": "room_1", "name": "Updated Room A", "capacity": 10 },
    { "id": "new_room", "name": "New Room", "capacity": 30 }
  ],
  "options": {
    "atomic": false
  }
}

Creates or updates multiple records in a single request. Creates if ID doesn't exist, updates if it does.

Strict Requirements (same as single PUT):

  1. generateId: false in database config (user provides IDs)
  2. guards: false in resource definition (no field restrictions)
  3. All records must include an id field

Note: System-managed fields (createdAt, createdBy, modifiedAt, modifiedBy, deletedAt, deletedBy) are always protected and will be rejected if included in the request, regardless of guards configuration.

Request Body

FieldTypeDescription
recordsArrayArray of record objects with id and all fields
options.atomicBooleanIf true, all records succeed or all fail (default: false)

Response

{
  "success": [
    { "id": "room_1", "name": "Updated Room A", "capacity": 10, "modifiedAt": "2024-01-15T16:00:00Z" },
    { "id": "new_room", "name": "New Room", "capacity": 30, "createdAt": "2024-01-15T16:00:00Z" }
  ],
  "errors": [],
  "meta": {
    "total": 2,
    "succeeded": 2,
    "failed": 0,
    "atomic": false
  }
}

How It Works

  1. Batch existence check with firewall
  2. Split records into CREATE and UPDATE batches
  3. Validate new records with validateCreate()
  4. Validate existing records with validateUpdate()
  5. Check CREATE access for new records
  6. Check UPDATE access for existing records (per-record)
  7. Execute bulk insert and individual updates
  8. Return combined results

Batch Operation Features

Partial Success Mode (Default)

By default, batch operations use partial success mode:

  • All records are processed independently
  • Failed records go into errors array with detailed error information
  • Successful records go into success array
  • HTTP status 207 Multi-Status if any errors, 201/200 if all success
{
  "success": [ /* succeeded records */ ],
  "errors": [
    {
      "index": 2,
      "record": { /* original input */ },
      "error": {
        "error": "Human-readable message",
        "layer": "guards",
        "code": "GUARD_FIELD_NOT_CREATEABLE",
        "details": { "fields": ["status"] },
        "hint": "These fields are set automatically or must be omitted"
      }
    }
  ],
  "meta": {
    "total": 10,
    "succeeded": 8,
    "failed": 2,
    "atomic": false
  }
}

Atomic Mode (Opt-in)

Enable atomic mode for all-or-nothing behavior:

{
  "records": [ /* ... */ ],
  "options": {
    "atomic": true
  }
}

Atomic mode behavior:

  • First error immediately stops processing
  • All changes are rolled back (database transaction)
  • HTTP status 400 Bad Request
  • Returns single error with failure details
{
  "error": "Batch operation failed in atomic mode",
  "layer": "validation",
  "code": "BATCH_ATOMIC_FAILED",
  "details": {
    "failedAt": 2,
    "reason": { /* the actual error */ }
  },
  "hint": "Transaction rolled back. Fix the error and retry the entire batch."
}

Human-Readable Errors

All batch operation errors include:

  • Layer identification: Which security layer rejected the request
  • Error code: Machine-readable code for programmatic handling
  • Clear message: Human-readable explanation
  • Details: Contextual information (fields, IDs, reasons)
  • Helpful hints: Actionable guidance for resolution

Performance Optimizations

  • Batch size limits: Default 100 records (prevents memory exhaustion)
  • Single firewall query: WHERE id IN (...) instead of N queries
  • Bulk operations: Single INSERT for multiple records (CREATE, UPSERT)
  • O(1) lookups: Map-based record lookup instead of Array.find()

Configuration

Batch operations are auto-enabled when corresponding CRUD operations exist:

// Auto-enabled - no configuration needed
crud: {
  create: { access: { roles: ['member'] } },
  update: { access: { roles: ['member'] } }
  // batchCreate and batchUpdate automatically available
}

// Customize batch operations
crud: {
  create: { access: { roles: ['member'] } },
  batchCreate: {
    access: { roles: ['admin'] },  // Different access rules
    maxBatchSize: 50,               // Lower limit
    allowAtomic: false              // Disable atomic mode
  }
}

// Disable batch operations
crud: {
  create: { access: { roles: ['member'] } },
  batchCreate: false  // Explicitly disable
}

Security Layer Application

Batch operations maintain full security layer consistency:

  1. Firewall: Auto-apply ownership fields, batch fetch with isolation
  2. Access: Operation-level for CREATE, per-record for UPDATE/DELETE
  3. Guards: Per-record field validation (same rules as single operations)
  4. Masking: Applied to success array (respects user permissions)
  5. Audit: Single timestamp for entire batch for consistency

Authentication

All endpoints require authentication. Include your auth token in the request header:

Authorization: Bearer <your-token>

The user's context (userId, roles, organizationId) is extracted from the token and used to:

  1. Apply firewall filters (data isolation)
  2. Check access permissions
  3. Set audit fields (createdBy, modifiedBy)

Error Responses

All errors use a flat structure with contextual fields:

{
  "error": "Insufficient permissions",
  "layer": "access",
  "code": "ACCESS_ROLE_REQUIRED",
  "details": {
    "required": ["admin"],
    "current": ["member"]
  },
  "hint": "Contact an administrator to grant necessary permissions"
}

See Errors for the complete reference of error codes by security layer.

On this page