Interface Examples
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.
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;
}