Skip to the content.

API as DB Specification

This document specifies the HTTP contract that an external API must implement to be used as a data source by the Express REST API and MCP Server Framework’s API-as-DB feature. If you are building a custom API (without using this framework’s generate command to create the proxy) and want it to work as a “database” behind the framework’s proxy, your API must comply with this contract.

Purpose and audience

This specification is for:

If your API satisfies the contract below, the framework can proxy all CRUD and list operations to it, and the generated tests can be used to verify compliance.

Contract summary

Endpoints reference

Operation HTTP URL Request Response
List GET /{endpoint} Query params (see below) { data: [], totalResult: number }
Get one GET /{endpoint}/{id} { data: {} }
Create POST /{endpoint} Body = document { data: {} }
Update one PATCH /{endpoint}/{id} Body = partial document { data: {} }
Update many PUT /{endpoint} Query params + body { data: {} }
Delete one DELETE /{endpoint}/{id} { data: {} }
Delete many DELETE /{endpoint} Query params { data: {} }

Example request/response (list)

Request:

GET /products?limit=2&sort=-_id HTTP/1.1
Host: api.example.com
x-tag: <value-from-framework>

Response:

{
  "data": [
    { "_id": "507f1f77bcf86cd799439011", "name": "Widget A", "createdAt": "2025-01-15T10:00:00.000Z" },
    { "_id": "507f1f77bcf86cd799439012", "name": "Widget B", "createdAt": "2025-01-14T09:00:00.000Z" }
  ],
  "totalResult": 42
}

Example request/response (get one)

Request:

GET /products/507f1f77bcf86cd799439011 HTTP/1.1
Host: api.example.com

Response:

{
  "data": { "_id": "507f1f77bcf86cd799439011", "name": "Widget A", "createdAt": "2025-01-15T10:00:00.000Z" }
}

Example request/response (create)

Request:

POST /products HTTP/1.1
Host: api.example.com
Content-Type: application/json
x-tag: <value-from-framework>

{"name": "New Widget", "price": 9.99}

Response:

{
  "data": { "_id": "507f1f77bcf86cd799439013", "name": "New Widget", "price": 9.99, "createdAt": "2025-01-16T12:00:00.000Z" }
}

Query parameters (list / GET collection)

The framework may send these as query parameters on GET {baseurl}/{endpoint}. Your API should accept and honor the ones it supports:

Parameter Description
limit Page size (number).
sort Sort spec, e.g. -_id (descending by _id) or name (ascending by name).
select Comma-separated field names for projection (e.g. name,price).
populate Related fields to populate (string).
from Start of date range (ISO string; maps from internal createdAt.$gt).
to End of date range (ISO string; maps from internal createdAt.$lt).
lastId Cursor for next page: the _id or id of the last item from the previous page.
search Search string when the list is used as search.

Other query keys may be filter criteria (e.g. name=foo). The framework does not send skip; pagination is cursor-based via lastId.

Optional: schema discovery

For MCP and schema metadata, the framework can discover your API’s schema from:

GET {baseurl}/{endpoint}/schema

Return a JSON Schema object with at least a properties object (and optionally required, description). Example:

{
  "type": "object",
  "properties": {
    "id": { "type": "string", "description": "Unique identifier" },
    "name": { "type": "string", "description": "Product name" },
    "createdAt": { "type": "string", "format": "date-time" }
  },
  "required": ["id", "name"]
}

If this endpoint is missing or returns an invalid response, the framework falls back to the _schema defined in the generated API model file.

Error handling

On failure, the framework uses error.response?.data || error. Your API can return standard HTTP status codes (4xx, 5xx) with a JSON body; that body will be propagated to the framework’s error handling.

Testing for compliance

Compliance is verified by running the generated API-based unit tests against your API:

  1. Generate an API-as-DB service that points at your API:
    npm run generate -- --name MyProxy --baseurl https://your-api.example.com --endpoint resources
    
  2. Start your API so it is reachable at the given base URL (or use a stub server that implements this spec).
  3. Run the test suite:
    npm test
    

    If your API runs on a different URL/port than the default, set TEST_API_BASEURL:

    TEST_API_BASEURL=http://localhost:3000 npm test
    

The generated controller and route tests call your API and assert response shape (data, totalResult), status codes, and CRUD behavior. If these tests pass, your API satisfies the contract.

Optional: manual checklist

If you are not using the framework’s generate command to create the proxy service, you can verify compliance with this checklist:

You can use curl or any REST client to run through these points against your base URL and endpoint.