[data-reveal]{opacity:1!important;transform:none!important}
Parameter Decoration
Database Decorators

Parameter Decoration

The Database Decorators package provides the Model decorator for injecting data model instances into API controller methods. This decorator integrates with the @antelopejs/interface-api package's parameter provider system.

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);
    });
  },
);