Expose database records through an API
Overview
Use @antelopejs/interface-data-api to expose a table through named CRUD routes and an explicit field policy. A data controller connects the table model to HTTP handlers; its metadata decides which fields clients may read, write, list, and filter.
Build one resource first
- Prepare the database. Define a table and register its schema with database-decorators. Your AntelopeJS module needs a database provider and an API provider.
- Choose the routes. Start with the route set your clients need, rather than exposing every write operation by default.
- Set the field policy. Add access rights, validators, and list fields. Field permissions are not user authentication or row-level authorization.
- Check one read and one rejected write. Confirm the response excludes private fields and that invalid input cannot reach storage. Then add relationships and filters.
Quick Start
The following example declares all five CRUD routes for a users table. It assumes a configured provider and an existing my-database instance. Import the table declaration before calling await RegisterSchema("myapp") in the declaring module's initialization; await that setup before serving requests.
This is a field-policy example, not a production account system: write-only prevents a password from appearing in responses, but does not hash it or authenticate requests. Add an appropriate database modifier and your authentication policy before accepting real credentials.
import { Controller } from "@antelopejs/interface-api";
import {
DataController,
DefaultRoutes,
RegisterDataController,
} from "@antelopejs/interface-data-api";
import {
Access,
AccessMode,
Listable,
Mandatory,
ModelReference,
} from "@antelopejs/interface-data-api/metadata";
import {
BasicDataModel,
Field,
Index,
Model,
RegisterTable,
Table,
} from "@antelopejs/interface-database-decorators";
// Define the database table
@RegisterTable("users", "myapp")
class User extends Table {
@Field("string")
declare _id: string;
@Index()
@Field("string")
declare email: string;
@Field("string")
declare name: string;
@Field("string")
declare password: string;
}
// Create the database model
class UserModel extends BasicDataModel(User, "users") {}
// Create the data controller
@RegisterDataController()
class UserAPI extends DataController(
User,
DefaultRoutes.All,
Controller("/users"),
) {
@ModelReference()
@Model(UserModel, "my-database")
declare userModel: UserModel;
@Listable()
@Access(AccessMode.ReadOnly)
declare _id: string;
@Listable()
@Access(AccessMode.ReadWrite)
@Mandatory("new", "edit")
declare email: string;
@Listable()
@Access(AccessMode.ReadWrite)
@Mandatory("new")
declare name: string;
@Access(AccessMode.WriteOnly)
@Mandatory("new")
declare password: string;
}
This generates the following REST endpoints:
| Method | Endpoint | Description |
|---|---|---|
| GET | /users/get?id=<id> | Retrieve a single user |
| GET | /users/list?limit=10 | List users with pagination |
| POST | /users/new | Create a new user |
| PUT | /users/edit?id=<id> | Update an existing user |
| DELETE | /users/delete?id=<id> | Delete a user |
Check the field policy
Use disposable data and your configured API base URL. Create a user with name, email, and a dummy password; the response is an array of inserted IDs. Use the first ID for the following checks:
GET /users/get?id=<id>returns the readable fields, neverpassword.GET /users/list?limit=10includes_id,name, andemailinresults.PUT /users/edit?id=<id>with{ "name": "Updated" }preserves the omitted email. With{ "email": "" }, it returns400because email is mandatory on edit.
@Mandatory does not check email syntax or password strength. Add validators before accepting untrusted input.
Core guides
- Data Controllers - Create and configure data controllers
- Routes - Default routes, custom routes, and route options
- Access Rights - Control field read/write permissions
- Validators - Field-level validation and mandatory fields
- Listable Fields - Pagination, pluck modes, and sorting
Relationships and advanced queries
- Foreign Keys - Establish relationships between tables
- Filters - Add filtering capabilities to list endpoints
- Modifiers - Automatic data transformation with database-decorators
- Joined Fields - Flatten a remote field onto rows for native sort/filter
- Computed Fields - In-database computed values, sortable and pageable natively