[data-reveal]{opacity:1!important;transform:none!important}
Access Rights
Data API

Access Rights

Overview

The @Access decorator controls how fields are read and written through the API. Each field can be set to read-only, write-only, or read-write, providing fine-grained control over data exposure. Access modes can also be overridden on a per-action basis, allowing different permissions for get, list, new, and edit operations.

Separate field policy from caller permissions

@Access answers “may this action read or write this field?”, not “may this user access this record?”. Authenticate the caller and apply record-level policy separately. A write-only password is hidden from responses, but this decorator does not hash it.

Build the field policy in this order:

  1. Set @Access for each public field. Undecorated fields remain private.
  2. Add action overrides for differences between creation and editing.
  3. Add @Listable for the fields selected by list responses; readable alone does not define a list projection.
  4. Add validators and mandatory-field rules for writable inputs.

For example, a display name can be readable and writable, an ID readable only, and a password writable only. Test each direction: attempting to write a read-only field is ignored, while omitting a mandatory writable field is a validation concern.

Access Modes

The AccessMode enum defines three permission levels:

import { Access, AccessMode } from "@antelopejs/interface-data-api/metadata";
ModeValueDescription
AccessMode.ReadOnly1Field is readable; list responses also require selection by the pluck mode. POST and PUT ignore it.
AccessMode.WriteOnly2Field is accepted in POST and PUT bodies but never appears in responses
AccessMode.ReadWrite3Field is both readable and writable

Basic Usage

Read-Only Fields

Read-only fields appear in API responses but cannot be modified through create or update requests. Values sent for these fields in request bodies are silently ignored.

@RegisterDataController()
class UserAPI extends DataController(
  User,
  DefaultRoutes.All,
  Controller("/users"),
) {
  @ModelReference()
  @Model(UserModel, "my-database")
  declare userModel: UserModel;

  @Access(AccessMode.ReadOnly)
  declare _id: string;

  @Access(AccessMode.ReadOnly)
  declare createdAt: string;

  @Access(AccessMode.ReadWrite)
  declare name: string;
}

A PUT request to /users/edit?id=user-123 with { "createdAt": "2025-01-01", "name": "Alice" } updates only name. The createdAt field is ignored.

Write-Only Fields

Write-only fields accept input during create and update operations but are never included in API responses. This is useful for sensitive data like passwords.

@RegisterDataController()
class UserAPI extends DataController(
  User,
  DefaultRoutes.All,
  Controller("/users"),
) {
  @ModelReference()
  @Model(UserModel, "my-database")
  declare userModel: UserModel;

  @Access(AccessMode.ReadWrite)
  declare name: string;

  @Access(AccessMode.ReadWrite)
  declare email: string;

  @Access(AccessMode.WriteOnly)
  declare password: string;
}

A GET request to /users/get?id=user-123 returns name and email but never includes password:

{
  "name": "Bob",
  "email": "[email protected]"
}

Read-Write Fields

Read-write fields are fully accessible: they appear in responses and accept input in request bodies.

@Access(AccessMode.ReadWrite)
declare email: string;

@Access(AccessMode.ReadWrite)
declare name: string;

Per-Action Overrides

The @Access decorator accepts an optional second argument to override the access mode for specific actions. This allows a field to behave differently depending on the operation being performed.

@Access(defaultMode: AccessMode, overrides?: Record<string, AccessMode>)

The overrides object maps action names ("get", "list", "new", "edit") to an AccessMode value. Actions not listed in the overrides use the default mode.

Example: Writable on Create, Read-Only on Edit

@RegisterDataController()
class UserAPI extends DataController(
  User,
  DefaultRoutes.All,
  Controller("/users"),
) {
  @ModelReference()
  @Model(UserModel, "my-database")
  declare userModel: UserModel;

  @Access(AccessMode.ReadOnly)
  declare _id: string;

  @Access(AccessMode.ReadWrite)
  declare name: string;

  // role can be set when creating, but cannot be changed during edit
  @Access(AccessMode.ReadWrite, { edit: AccessMode.ReadOnly })
  declare role: string;

  // age is read-only by default, but writable during creation
  @Access(AccessMode.ReadOnly, { new: AccessMode.ReadWrite })
  declare age: number;
}

In this configuration:

  • role is readable and writable in all operations except edit, where it becomes read-only.
  • age is read-only by default but can be set during new (create) operations.

Fields Without @Access

Ordinary fields need @Access to appear in responses or accept input; @Listable alone does not grant access. The derived-field decorators @Joined and @Computed are exceptions: they set read-only access themselves.

Next Steps

See the validators documentation to learn how to enforce validation rules on field values.