Guides

Interface Examples

Concrete examples of using AntelopeJS interfaces for routing, models, databases, and authentication in your applications.

Overview

This guide provides practical examples of how to use various AntelopeJS interfaces in your applications. These examples demonstrate how interfaces enable modular communication and provide powerful abstractions for common development tasks.

These examples showcase how AntelopeJS interfaces work together to create modular, maintainable applications. Each example focuses on a specific interface and shows how it integrates with the broader AntelopeJS ecosystem.

Routing Examples

The API interface provides a decorator-based framework for building HTTP services. It simplifies route definition and request handling using TypeScript decorators.

Simple Controller with HTTP Routes

This example demonstrates basic HTTP route handling using the core API interface decorators. The @Controller decorator defines the base path, while HTTP method decorators like @Get, @Post, @Put, and @Delete create specific endpoints.

import { Controller, Get, Post, Put, Delete, Parameter } from '@ajs/api/beta';

@Controller('/users')
class UserController {
  @Get()
  async listUsers() {
    return { users: [] };
  }

  @Get('/:id')
  async getUser(@Parameter('id') id: string) {
    return { id, name: 'John Doe' };
  }

  @Post()
  async createUser(@RawBody() userData: any) {
    return { id: 'new-id', ...userData };
  }

  @Put('/:id')
  async updateUser(@Parameter('id') id: string, @RawBody() userData: any) {
    return { id, ...userData };
  }

  @Delete('/:id')
  async deleteUser(@Parameter('id') id: string) {
    return { success: true };
  }
}

Controller with Priorities and Prefixes

Advanced routing features include @Prefix and @Postfix decorators that allow you to execute code before or after the main handler.

In the following example, we are using it to log requests and responses on the /api/data route.

import { Controller, Get, Prefix, Postfix, HandlerPriority } from '@ajs/api/beta';

@Controller('/api')
class ApiController {
  @Prefix('any', 'data')
  async logRequest() {
    // Logging before processing requests
  }

  @Get('/data')
  async getData() {
    return { data: 'main response' };
  }

  @Postfix('get', 'data')
  async logResponse() {
    // Logging after processing
  }
}

Data Model Examples

The Database Decorators interface provides TypeScript decorators for defining database tables and models with built-in support for encryption, hashing, and localization.

User Model with Decorators

This example shows how to create a user model with security features using the Database Decorators interface. The @Hashed decorator automatically hashes passwords, while @Encrypted protects sensitive data. The @Index decorators optimize database queries.

import { Table, Index, RegisterTable } from '@ajs/database-decorators/beta/table';
import { Hashed, Encrypted } from '@ajs/database-decorators/beta/modifiers';

@RegisterTable('users')
class User extends Table {
  @Index({ primary: true })
  declare _id: string;

  @Index()
  declare email: string;

  @Hashed({ algorithm: 'sha256' })
  declare password: string;

  @Encrypted({ secretKey: 'your-secret-key' })
  declare secretData: Record<string, unknown>;

  declare firstName: string;
  declare lastName: string;
  declare isActive: boolean;
  declare createdAt: Date;
}

Product Model with Relations

This example demonstrates a more complex model structure with multiple indexes for efficient querying. The @Index decorators on sku and category enable fast lookups and filtering operations.

import { Table, Index, RegisterTable } from '@ajs/database-decorators/beta/table';

@RegisterTable('products')
class Product extends Table {
  @Index({ primary: true })
  declare _id: string;

  @Index()
  declare sku: string;

  @Index()
  declare category: string;

  declare name: string;
  declare description: string;
  declare price: number;
  declare stockQuantity: number;
  declare isActive: boolean;
  declare tags: string[];
  declare createdAt: Date;
  declare updatedAt: Date;
}

@RegisterTable('orders')
class Order extends Table {
  @Index({ primary: true })
  declare _id: string;

  @Index()
  declare customerId: string;

  declare status: string;
  declare totalAmount: number;
  declare createdAt: Date;
}

Database Usage Examples

The Database interface provides database-agnostic operations using Antelope Query Language (AQL), ensuring consistent data operations across different database implementations.

Basic CRUD Operations

This example demonstrates the fundamental database operations using the BasicDataModel class from the Database Decorators interface. It provides a clean, type-safe interface for creating, reading, updating, and deleting records.

import { Database } from '@ajs/database/beta';
import { BasicDataModel } from '@ajs/database-decorators/beta/model';

// Create the model
const UserModel = BasicDataModel(User, 'users');
const database = Database('my-app');
const userModel = new UserModel(database);

// Create a user
const newUser = {
  email: '[email protected]',
  password: 'securePassword123',
  firstName: 'John',
  lastName: 'Doe',
  isActive: true,
  secretData: { token: 'secret-token' }
};

const insertResult = await userModel.insert(newUser);
const userId = insertResult.generated_keys![0];

// Retrieve a user
const user = await userModel.get(userId);

// Update a user
await userModel.update(userId, { isActive: false });

// Delete a user
await userModel.delete(userId);

// List all users
const allUsers = await userModel.getAll();

// Search by criteria
const activeUsers = await userModel.getBy('isActive', true);

Batch Operations

Batch operations allow you to perform multiple database operations efficiently in a single transaction, improving performance for bulk data operations.

// Insert multiple users
const users = [
  { email: '[email protected]', firstName: 'Alice', lastName: 'Smith' },
  { email: '[email protected]', firstName: 'Bob', lastName: 'Johnson' },
  { email: '[email protected]', firstName: 'Carol', lastName: 'Williams' }
];

const batchResult = await userModel.insert(users);
console.log(`Created ${batchResult.generated_keys!.length} users`);

JWT Authentication Examples

The Auth interface provides a flexible framework for implementing authentication and authorization using decorator-based approaches to secure API endpoints.

Token Generation and Validation

This example shows how to generate and validate JWT tokens using the SignRaw and ValidateRaw functions from the Auth interface. The tokens can contain user data and have configurable expiration times.

import { SignRaw, ValidateRaw } from '@ajs/auth-jwt/beta';

// Generate a JWT token
const userData = {
  id: 'user123',
  email: '[email protected]',
  role: 'admin'
};

const token = await SignRaw(userData, { 
  expiresIn: '24h' 
});

// Validate a token
try {
  const verifiedData = await ValidateRaw(token);
  console.log('Authenticated user:', verifiedData);
} catch (error) {
  console.log('Invalid or expired token');
}

Authentication Middleware

This example demonstrates how to create protected routes by validating JWT tokens from request headers. The @Parameter decorator extracts the authorization header for token validation.

import { Controller, Get, Parameter } from '@ajs/api/beta';
import { ValidateRaw } from '@ajs/auth-jwt/beta';

@Controller('/protected')
class ProtectedController {
  @Get('/profile')
  async getProfile(@Parameter('authorization', 'header') authHeader: string) {
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      throw new Error('Authentication token required');
    }

    const token = authHeader.substring(7);
    const userData = await ValidateRaw(token);
    
    return {
      id: userData.id,
      email: userData.email,
      role: userData.role
    };
  }
}

Data API with Controllers Example

The Data API interface extends the core API with specialized functionality for handling database records, making it simple to create RESTful endpoints for your data models.

Automatic Data Controller

This example shows how to create a data controller that automatically provides CRUD operations. The @DataController decorator generates REST endpoints, while metadata decorators control field access and validation.

The Data API interface, by default, provides a set of standard routes for managing records:

  • /get: Retrieves a single record by ID
  • /list: Returns a paginated list of records with optional sorting and filtering
  • /new: Creates a new record
  • /edit: Updates an existing record
  • /delete: Removes one or more records
import { Controller } from '@ajs/api/beta';
import { DataController, DefaultRoutes, RegisterDataController } from '@ajs/data-api/beta';
import { Access, AccessMode, Listable, Mandatory, Validator } from '@ajs/data-api/beta/metadata';

@RegisterDataController()
class CustomerAPI extends DataController(Customer, DefaultRoutes.All, Controller('/customers')) {
  @Listable()
  @Access(AccessMode.ReadOnly)
  declare _id: string;

  @Listable()
  @Access(AccessMode.ReadWrite)
  @Mandatory('new', 'edit')
  @Validator((value) => typeof value === 'string' && value.length >= 2)
  declare firstName: string;

  @Listable()
  @Access(AccessMode.ReadWrite)
  @Mandatory('new', 'edit')
  @Validator((value) => {
    if (typeof value !== 'string') return false;
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(value);
  })
  declare email: string;

  @Listable()
  @Access(AccessMode.ReadWrite)
  declare isActive: boolean;
}

Using the Data API

Once you have a data controller set up, you can interact with it using standard HTTP requests. The Data API interface automatically handles filtering, sorting, and pagination through query parameters.

// Create a customer
const newCustomer = {
  firstName: 'Sophie',
  lastName: 'Marrone',
  email: '[email protected]',
  isActive: true
};

const createResponse = await fetch('/customers', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(newCustomer)
});

const customerIds = await createResponse.json();

// Retrieve a customer
const getResponse = await fetch(`/customers?id=${customerIds[0]}`);
const customer = await getResponse.json();

// List customers
const listResponse = await fetch('/customers?isActive=true&sortKey=firstName');
const customers = await listResponse.json();

Combining Multiple Interfaces

One of the key strengths of AntelopeJS is how interfaces work together seamlessly. Here's an example that combines several interfaces:

import { Controller, Get, Post, Authentication } from '@ajs/api/beta';
import { DataController, DefaultRoutes, RegisterDataController } from '@ajs/data-api/beta';
import { Access, AccessMode, Listable, Mandatory } from '@ajs/data-api/beta/metadata';
import { Table, Index, RegisterTable } from '@ajs/database-decorators/beta/table';

// Define a table using the Database Decorators interface
@RegisterTable('tasks')
class Task extends Table {
  @Index({ primary: true })
  declare _id: string;

  @Index()
  declare userId: string;

  declare title: string;
  declare description: string;
  declare isCompleted: boolean;
  declare createdAt: Date;
}

// Create a data controller that combines API, Data API, and Auth interfaces
@RegisterDataController()
class TaskAPI extends DataController(Task, DefaultRoutes.All, Controller('/tasks')) {
  @Listable()
  @Access(AccessMode.ReadOnly)
  declare _id: string;

  @Listable()
  @Access(AccessMode.ReadOnly)
  declare userId: string;

  @Listable()
  @Access(AccessMode.ReadWrite)
  @Mandatory('new', 'edit')
  declare title: string;

  @Listable()
  @Access(AccessMode.ReadWrite)
  declare description: string;

  @Listable()
  @Access(AccessMode.ReadWrite)
  declare isCompleted: boolean;

  @Listable()
  @Access(AccessMode.ReadOnly)
  declare createdAt: Date;
}
These examples show the most common use cases for developing applications with AntelopeJS interfaces. Each example is self-contained and can be adapted to your specific needs. For more detailed information about each interface, visit the AntelopeJS interfaces page or explore the individual interface repositories on GitHub.
For a complete tutorial that shows how to build a full-stack application using these interfaces together, see the Full-Stack App Tutorial.