| title | Expose database records through an API |
|---|---|
| description | Build a first data controller that serves CRUD routes for a users table, then check which fields it reads and writes. |
| mode | tutorial |
In this tutorial, we expose a users table through five CRUD routes with @antelopejs/interface-data-api. A data controller connects the table model to HTTP handlers. Its metadata decides which fields clients can read, write, list and filter.
We build one resource in four steps.
- Prepare the database. Define a table and register its schema with database-decorators. The AntelopeJS project needs a database module and an API module.
- Choose the routes. Start with the route set your clients need, instead of exposing every write route by default.
- Set the field policy. Add access rights, validators and list fields. Field permissions do not authenticate users and do not authorize access to rows.
- Check one read and one rejected write. Confirm that the response leaves out private fields and that invalid input never reaches storage. Then add relationships and filters.
The example declares all five CRUD routes for a users table. It assumes a configured database module and an existing my-database instance. Import the table declaration, then await RegisterSchema("myapp") when the declaring module initializes. Wait for that setup to finish before the module serves requests.
This example sets a field policy. It is not a production account system. AccessMode.WriteOnly keeps the password out of responses, but it does not hash the password or authenticate requests. Add a database modifier and your authentication policy before you accept 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";
@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;
}
class UserModel extends BasicDataModel(User, "users") {}
@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;
}The controller serves these REST endpoints.
| Method | Endpoint | Description |
|---|---|---|
| GET | /users/get?id=<id> |
Read one user |
| GET | /users/list?limit=10 |
List users, one page |
| POST | /users/new |
Create a user |
| PUT | /users/edit?id=<id> |
Update a user |
| DELETE | /users/delete?id=<id> |
Delete a user |
Use disposable data and the base URL of your API module. First, create a user with POST /users/new and a body that holds name, email and a dummy password. The response is the created user, with its _id and without password. Use that _id in the next checks.
GET /users/get?id=<id>returns the readable fields. You see_id,emailandname, and neverpassword.GET /users/list?limit=10returns_id,nameandemailfor each entry ofresults.PUT /users/edit?id=<id>with{ "name": "Updated" }keeps the email you did not send. With{ "email": "" }, the route answers400, becauseemailis mandatory onedit.
@Mandatory does not check the email syntax or the password strength. Add validators before you accept untrusted input.
- Data controllers. Create and configure data controllers.
- Routes. Default routes, custom routes and route options.
- Access rights. Which fields each action reads and writes.
- Validators. Field validation and mandatory fields.
- Listable fields. Pagination, pluck modes and sorting.
- Foreign keys. Relations between tables.
- Filters. Filters on list endpoints.
- Modifiers. Data transformation with database-decorators modifiers.
- Joined fields. A remote field flattened onto each row, sortable and filterable in the database.
- Computed fields. Values computed in the database, sortable and pageable there.