@oxlayer/snippets
v0.1.0
Published
Reusable code templates for OxLayer microservices
Readme
@oxlayer/snippets
Reusable code templates for building domain-driven microservices with OxLayer foundation and capabilities packages.
Overview
This package provides templates and base classes for common patterns in OxLayer applications, helping you maintain architectural consistency while accelerating development.
Installation
pnpm add @oxlayer/snippetsUsage
AppResult Type
All use case templates return AppResult<T> for explicit error handling:
import type { AppResult } from '@oxlayer/snippets/use-cases';
// AppResult is a discriminated union type:
type AppResult<T> =
| { success: true; data: T }
| { success: false; error: { code: string; message: string } };
// Usage in use case
export class CreateTodoUseCase extends CreateUseCaseTemplate<
CreateTodoInput,
Todo,
AppResult<TodoOutput>
> {
// ...
}
// Usage in controller
const result = await this.createTodoUseCase.execute(input);
if (!result.success) {
return this.badRequest(result.error?.message || 'Failed to create todo');
}
return this.created({ todo: result.data });Domain Layer
Create entities using the template base classes:
import { CrudEntityTemplate, StatusEntityTemplate, TimestampedEntityTemplate } from '@oxlayer/snippets/domain';
export type TodoStatus = 'pending' | 'in_progress' | 'completed';
export interface TodoProps {
id: string;
title: string;
status: TodoStatus;
userId: string;
createdAt: Date;
updatedAt: Date;
}
export class Todo extends CrudEntityTemplate<string> {
private props: TodoProps;
private constructor(props: TodoProps) {
super(props.id);
this.props = props;
}
// Getters
get title(): string { return this.props.title; }
get status(): TodoStatus { return this.props.status; }
get userId(): string { return this.props.userId; }
// Business methods
markAsCompleted(): void {
this.updateStatus('completed');
}
// Factory methods
static create(data: CreateTodoInput): Todo {
return new Todo({
id: this.generateId(),
title: data.title,
status: 'pending',
userId: data.userId,
createdAt: new Date(),
updatedAt: new Date(),
});
}
static fromPersistence(data: TodoProps): Todo {
return new Todo(data);
}
toPersistence(): TodoProps {
return { ...this.props };
}
}Use Case Layer
Create use cases using the template base classes:
import { CreateUseCaseTemplate } from '@oxlayer/snippets/use-cases';
export class CreateTodoUseCase extends CreateUseCaseTemplate<
CreateTodoInput,
Todo,
Result<TodoOutput>
> {
constructor(
todoRepository: TodoRepository,
eventBus: EventBus,
tracer?: unknown | null
) {
super({
generateId: () => `todo_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
createEntity: (data) => Todo.create(data),
persistEntity: (entity) => todoRepository.create(entity),
publishEvent: (event) => eventBus.emit(event),
recordMetric: (name, value) => businessMetrics.increment(name, { value }),
toOutput: (entity) => ({
id: entity.id,
title: entity.title,
status: entity.status,
createdAt: entity.createdAt,
}),
tracer,
});
}
protected getUseCaseName(): string {
return 'CreateTodo';
}
}Repository Layer
Create repositories using the template base classes:
import { PostgresRepositoryTemplate } from '@oxlayer/snippets/repositories';
export class PostgresTodoRepository extends PostgresRepositoryTemplate<
Todo,
TodoFilters,
TodoProps
> {
constructor(db: Database, tracer?: unknown | null) {
super(db, tracer, { tableName: 'todos' });
}
protected mapRowToEntity(row: TodoProps): Todo {
return Todo.fromPersistence(row);
}
protected mapEntityToProps(entity: Todo): TodoProps {
return entity.toPersistence();
}
protected applyFilters(query: any, filters: TodoFilters): any {
if (filters.status) {
query = query.where({ status: filters.status });
}
if (filters.userId) {
query = query.where({ user_id: filters.userId });
}
if (filters.search) {
query = query.where('title', 'like', `%${filters.search}%`);
}
return query;
}
}Controller Layer
Create controllers using the template base classes:
import { CrudControllerTemplate } from '@oxlayer/snippets/controllers';
export class TodosController extends CrudControllerTemplate<
CreateTodoInput,
UpdateTodoInput,
TodoOutput,
TodoOutput,
TodoOutput,
{ items: TodoOutput[]; total: number }
> {
constructor(
createTodoUseCase: CreateTodoUseCase,
getTodoUseCase: GetTodoUseCase,
updateTodoUseCase: UpdateTodoUseCase,
deleteTodoUseCase: DeleteTodoUseCase,
listTodosUseCase: ListTodosUseCase
) {
super({
create: createTodoUseCase,
getById: getTodoUseCase,
update: updateTodoUseCase,
delete: deleteTodoUseCase,
list: listTodosUseCase,
});
}
protected getResourcePath(): string {
return '/api/todos';
}
}Configuration Layer
Create configuration using the template helpers:
import { createEnvSchema, loadEnv } from '@oxlayer/snippets/config';
const envSchema = createEnvSchema({
server: true,
postgres: true,
observability: true,
});
export const ENV = loadEnv(envSchema);Create a DI container using the template base classes:
import { CompleteContainerTemplate } from '@oxlayer/snippets/config';
export class DIContainer extends CompleteContainerTemplate {
private static instance: DIContainer;
// Infrastructure
public postgres: ReturnType<typeof createPostgresConnection>;
public eventBus: Awaited<ReturnType<typeof createEventBus>>;
public cache: ReturnType<typeof createRedisConnection>;
// Lazy-loaded dependencies
private _todoRepository?: TodoRepository;
private _createTodoUseCase?: CreateTodoUseCase;
private constructor() {
super();
this.postgres = createPostgresConnection();
this.cache = createRedisConnection();
}
static getInstance(): DIContainer {
if (!DIContainer.instance) {
DIContainer.instance = new DIContainer();
}
return DIContainer.instance;
}
protected async initializeTelemetry(): Promise<void> {
const telemetryClient = getTelemetryClient();
this.tracer = telemetryClient?.getTracer() || null;
}
protected async initializeInfrastructure(): Promise<void> {
this.eventBus = await createEventBus();
}
get todoRepository() {
if (!this._todoRepository) {
this._todoRepository = new PostgresTodoRepository(
this.postgres.db,
this.tracer
);
}
return this._todoRepository;
}
get createTodoUseCase() {
if (!this._createTodoUseCase) {
this._createTodoUseCase = new CreateTodoUseCase(
this.todoRepository,
this.eventBus,
this.tracer
);
}
return this._createTodoUseCase;
}
}Available Templates
Domain (@oxlayer/snippets/domain)
EntityTemplate- Base class for all entitiesStatusEntityTemplate- For entities with status transitionsTimestampedEntityTemplate- For entities with timestampsOwnedEntityTemplate- For multi-tenant entitiesCrudEntityTemplate- Combined template with all common featuresDomainEventTemplate- Base class for domain eventsValueObject- Base class for value objectsPrimitiveValueObject<T>- For single-value VOsCompositeValueObject- For multi-field VOs- Built-in VOs:
Email,PhoneNumber,Money,DateRange,Pagination
Use Cases (@oxlayer/snippets/use-cases)
BaseUseCase- Base class for all use casesCreateUseCase- Base class for create operationsUpdateUseCase- Base class for update operationsDeleteUseCase- Base class for delete operationsGetByIdUseCase- Base class for get by ID operationsListUseCase- Base class for list operationsCreateUseCaseTemplate- Template implementation for createsUpdateUseCaseTemplate- Template implementation for updatesDeleteUseCaseTemplate- Template implementation for deletesGetByIdUseCaseTemplate- Template implementation for get by IDListUseCaseTemplate- Template implementation for lists
Repositories (@oxlayer/snippets/repositories)
PostgresRepositoryTemplate- Base class for PostgreSQL reposSoftDeleteRepositoryTemplate- For soft-delete entitiesOwnedRepositoryTemplate- For multi-tenant repos
Controllers (@oxlayer/snippets/controllers)
ControllerTemplate- Base class for all controllersCrudControllerTemplate- Full CRUD controller templateReadOnlyControllerTemplate- Read-only controller template
Configuration (@oxlayer/snippets/config)
CommonEnvSchemas- Pre-built environment schemascreateEnvSchema()- Helper to build env schemasloadEnv()- Load and validate env varsgenerateEnvExample()- Generate .env.example fileContainerTemplate- Base class for DI containersTelemetryContainerTemplate- Container with telemetry supportCompleteContainerTemplate- Full-featured container
Patterns
The snippets enforce these OxLayer architectural patterns:
- Domain-Driven Design - Clear separation of domain, application, and infrastructure layers
- Dependency Injection - All dependencies injected through constructors
- Tracing - Automatic span creation for observability
- Error Handling - Consistent Result type for explicit error handling
- Event-Driven - Domain events for loose coupling
- Clean Architecture - Business logic independent of frameworks
License
MIT
