Guides

Data API

Generate automatic CRUD endpoints from database tables with customizable routes, authentication, and middleware in AntelopeJS.

Prerequisites

The Data API builds on both the API and database systems. Install all three interface packages in your module.

npm install @antelopejs/interface-data-api @antelopejs/interface-api @antelopejs/interface-database-decorators

Import from these packages as needed:

  • @antelopejs/interface-data-api -- DataController, RegisterDataController, DefaultRoutes
  • @antelopejs/interface-api -- Controller
  • @antelopejs/interface-database-decorators -- Table definitions and models

Before using the Data API, you need a registered table. Refer to the Database guide for table setup.

Creating a Data Controller

The DataController function generates a controller class with CRUD endpoints mapped to a database table. It accepts three arguments: the table class, a route definition object, and a base controller. The @RegisterDataController() decorator registers the generated controller with the framework.

src/data-api/tasks.ts
import { DataController, RegisterDataController, DefaultRoutes } from "@antelopejs/interface-data-api";
import { Controller } from "@antelopejs/interface-api";
import { Task } from "../db/tables/task";

@RegisterDataController()
class TaskDataController extends DataController(
  Task,
  {
    get: DefaultRoutes.Get,
    list: DefaultRoutes.List,
    new: DefaultRoutes.New,
    edit: DefaultRoutes.Edit,
    delete: DefaultRoutes.Delete,
  },
  Controller("/api/tasks")
) {}

This single class definition creates five endpoints:

RouteMethodDescription
GET /api/tasks/:idDefaultRoutes.GetRetrieve a single task
GET /api/tasksDefaultRoutes.ListList all tasks
POST /api/tasksDefaultRoutes.NewCreate a new task
PUT /api/tasks/:idDefaultRoutes.EditUpdate an existing task
DELETE /api/tasks/:idDefaultRoutes.DeleteDelete a task
DataController is a function that returns a class, not a decorator. Use extends DataController(...) to create your data controller.

Using DefaultRoutes.All

When you need all five CRUD routes, DefaultRoutes.All provides a shorthand that includes Get, List, New, Edit, and Delete in a single declaration.

src/data-api/tasks.ts
import { DataController, RegisterDataController, DefaultRoutes } from "@antelopejs/interface-data-api";
import { Controller } from "@antelopejs/interface-api";
import { Task } from "../db/tables/task";

@RegisterDataController()
class TaskDataController extends DataController(
  Task,
  DefaultRoutes.All,
  Controller("/api/tasks")
) {}

The shorthand produces the exact same set of endpoints as the explicit route definition. Use the explicit form when you need to include only specific routes or apply different options to each route.

Selective Routes

You can include only the routes your API needs by listing a subset in the route definition. Omitted routes are not generated.

src/data-api/readonly-tasks.ts
import { DataController, RegisterDataController, DefaultRoutes } from "@antelopejs/interface-data-api";
import { Controller } from "@antelopejs/interface-api";
import { Task } from "../db/tables/task";

@RegisterDataController()
class ReadOnlyTaskController extends DataController(
  Task,
  {
    get: DefaultRoutes.Get,
    list: DefaultRoutes.List,
  },
  Controller("/api/public/tasks")
) {}

This controller exposes only GET endpoints. No create, update, or delete operations are available, making it suitable for public or read-only APIs.

Adding Authentication

The DefaultRoutes.WithOptions function wraps a route definition with additional options. The function is the primary way to add authentication, middleware, or other request processing to Data API routes.

src/data-api/tasks.ts
import { DataController, RegisterDataController, DefaultRoutes } from "@antelopejs/interface-data-api";
import { Controller } from "@antelopejs/interface-api";
import { Authentication } from "@antelopejs/interface-auth";
import { Task } from "../db/tables/task";

@RegisterDataController()
class TaskDataController extends DataController(
  Task,
  {
    get: DefaultRoutes.WithOptions(DefaultRoutes.Get, { auth: Authentication }),
    list: DefaultRoutes.WithOptions(DefaultRoutes.List, { auth: Authentication }),
    new: DefaultRoutes.WithOptions(DefaultRoutes.New, { auth: Authentication }),
    edit: DefaultRoutes.WithOptions(DefaultRoutes.Edit, { auth: Authentication }),
    delete: DefaultRoutes.WithOptions(DefaultRoutes.Delete, { auth: Authentication }),
  },
  Controller("/api/tasks")
) {}

Every route now requires a valid authentication token. Requests without authentication receive an error response before reaching the route handler. You can apply different options to each route independently.

Mixed Access Patterns

A common pattern exposes read endpoints publicly while restricting write operations to authenticated users. Apply WithOptions only to the routes that need protection.

src/data-api/articles.ts
import { DataController, RegisterDataController, DefaultRoutes } from "@antelopejs/interface-data-api";
import { Controller } from "@antelopejs/interface-api";
import { Authentication } from "@antelopejs/interface-auth";
import { Article } from "../db/tables/article";

@RegisterDataController()
class ArticleDataController extends DataController(
  Article,
  {
    get: DefaultRoutes.Get,
    list: DefaultRoutes.List,
    new: DefaultRoutes.WithOptions(DefaultRoutes.New, { auth: Authentication }),
    edit: DefaultRoutes.WithOptions(DefaultRoutes.Edit, { auth: Authentication }),
    delete: DefaultRoutes.WithOptions(DefaultRoutes.Delete, { auth: Authentication }),
  },
  Controller("/api/articles")
) {}

Anyone can read articles, but only authenticated users can create, edit, or delete them. This approach keeps the route definitions declarative and easy to audit.

Custom Route Options

The DefaultRoutes.WithOptions function accepts an optional third argument for the endpoint path. The third argument allows you to customize the URL pattern for individual routes.

DefaultRoutes.WithOptions(DefaultRoutes.Get, { auth: Authentication }, "/by-id")

Use custom endpoints when the default URL pattern does not match your API design or when you need to avoid path conflicts with other controllers. The custom path replaces the default path segment for that specific route only.

Combining with the Database Guide

The Data API works directly with tables defined using the database decorators. Here is a complete example that defines a table and exposes it as a CRUD API.

src/db/tables/task.ts
import { Table, RegisterTable, Index } from "@antelopejs/interface-database-decorators";

@RegisterTable("tasks", "main")
class Task extends Table {
  @Index()
  declare userId: string;

  declare title: string;
  declare description: string;
  declare completed: boolean;
}

export { Task };

The data controller below exposes CRUD endpoints for the Task table using DefaultRoutes.All:

src/data-api/tasks.ts
import { DataController, RegisterDataController, DefaultRoutes } from "@antelopejs/interface-data-api";
import { Controller } from "@antelopejs/interface-api";
import { Task } from "../db/tables/task";

@RegisterDataController()
class TaskDataController extends DataController(
  Task,
  DefaultRoutes.All,
  Controller("/api/tasks")
) {}

The Data API reads the table's schema and generates endpoints that match the table's structure. Column names become the fields in request and response bodies. You can use indexed fields for filtering in list operations.