Parameter Decoration
The Model Decorator
The Model decorator injects a cached model instance. It can be used as either a parameter decorator or a property decorator.
Static Instance ID
Pass a fixed instance ID to bind the model to a specific schema instance:
import { Controller, Get } from "@antelopejs/interface-api";
import { Model } from "@antelopejs/interface-database-decorators";
import { UserModel } from "./user.model";
class UsersController extends Controller("/users") {
@Get()
async listUsers(
@Model(UserModel, "main") userModel: InstanceType<typeof UserModel>,
) {
return await userModel.getAll();
}
}
Dynamic Instance ID
Pass a callback function to determine the instance ID at request time. The callback receives the request context:
Authorize access to the requested tenant before reading or writing through the injected model. The callback selects an instance; a URL parameter alone is not proof that the caller belongs to that tenant.
import { Controller, Get, Parameter } from "@antelopejs/interface-api";
import { Model } from "@antelopejs/interface-database-decorators";
import { UserModel } from "./user.model";
class MultitenantController extends Controller("/tenants") {
@Get("/:tenantId/users")
async getTenantUsers(
@Parameter("tenantId") tenantId: string,
@Model(UserModel, (ctx) => `tenant-${ctx.params.tenantId}`)
userModel: InstanceType<typeof UserModel>,
) {
return await userModel.getAll();
}
}
Property Decoration
The Model decorator also works as a property decorator. The model is initialized when the controller handles a request:
import { Controller, Get, Parameter } from "@antelopejs/interface-api";
import { Model } from "@antelopejs/interface-database-decorators";
import { UserModel } from "./models";
class UsersController extends Controller("/users") {
@Model(UserModel, "main")
private userModel!: InstanceType<typeof UserModel>;
@Get()
async listUsers() {
return await this.userModel.getAll();
}
@Get("/:id")
async getUser(@Parameter("id") id: string) {
return await this.userModel.get(id);
}
}
Model Caching
The Model decorator uses GetModel internally, which caches model instances by class and instance ID. Multiple decorators referencing the same model class and instance ID share a single instance:
import { GetModel } from "@antelopejs/interface-database-decorators";
// These return the same instance
const model1 = GetModel(UserModel, "main");
const model2 = GetModel(UserModel, "main");
// This returns a different instance
const model3 = GetModel(UserModel, "other");
Combine with API Decorators
Model decorators compose naturally with other API decorators for building complete CRUD controllers:
This example demonstrates injection, not a complete public API policy. Before exposing writes, reject malformed or non-object JSON, allow only permitted fields, validate their values, and authorize the operation. JSON.parse and @Model do not provide these checks; string-token @Field declarations do not validate input either.
import {
Controller,
Get,
Post,
Put,
Delete,
RawBody,
Parameter,
} from "@antelopejs/interface-api";
import { Model } from "@antelopejs/interface-database-decorators";
import { UserModel } from "./user.model";
class UsersController extends Controller("/users") {
@Get()
async list(@Model(UserModel, "main") model: InstanceType<typeof UserModel>) {
return await model.getAll();
}
@Get("/:id")
async get(
@Parameter("id") id: string,
@Model(UserModel, "main") model: InstanceType<typeof UserModel>,
) {
return await model.get(id);
}
@Post()
async create(
@RawBody() body: Buffer,
@Model(UserModel, "main") model: InstanceType<typeof UserModel>,
) {
const data = JSON.parse(body.toString());
return await model.insert(data);
}
@Put("/:id")
async update(
@Parameter("id") id: string,
@RawBody() body: Buffer,
@Model(UserModel, "main") model: InstanceType<typeof UserModel>,
) {
const data = JSON.parse(body.toString());
return await model.update(id, data);
}
@Delete("/:id")
async remove(
@Parameter("id") id: string,
@Model(UserModel, "main") model: InstanceType<typeof UserModel>,
) {
return await model.delete(id);
}
}
Custom Parameter Providers
For more complex injection logic, create custom parameter providers using the core API:
import { SetParameterProvider } from "@antelopejs/interface-api";
import { GetModel } from "@antelopejs/interface-database-decorators";
import { MakeParameterAndPropertyDecorator } from "@antelopejs/interface-core/decorators";
const CustomModel = MakeParameterAndPropertyDecorator(
(target, key, index, modelClass, resolver) => {
SetParameterProvider(target, key, index, (ctx) => {
const instanceId = resolver(ctx);
return GetModel(modelClass, instanceId);
});
},
);
Data Models
Data models provide a high-level interface for interacting with database tables. They handle conversion between database records and TypeScript class instances, and expose methods for common CRUD operations.
Introduction
Send transactional messages, templates, and batches through one provider-neutral contract. @antelopejs/interface-email defines the request and response types; an implementing module supplies the email provider and its configuration.