Skip to main content

SERVICE

service.ts

Business logic, ownership checks, typed errors.

Stark avatarStark

WHAT THIS PATTERN TEACHES

How to encapsulate business logic in services that own their errors and enforce data access rules.

WHEN TO USE THIS

Any business logic that goes beyond simple CRUD. Services are the heart of the application.

AT A GLANCE

export class ProjectService {
  async create(data: CreateInput): Promise<Project> {
    // ownership check, validation, persist
  }
}

FRAMEWORK IMPLEMENTATIONS

TypeScript
import { db } from "@/lib/db";
import { ApiError } from "@/lib/errors";

interface CreateProjectInput {
  name: string;
  description?: string;
  workspaceId: string;
}

export const projectService = {
  async create(data: CreateProjectInput, userId: string) {
    // Ownership check: user must belong to workspace
    const membership = await db.workspaceMember.findFirst({
      where: { workspaceId: data.workspaceId, userId },
    });
    if (!membership) {
      throw new ApiError("NOT_FOUND", "Workspace not found", 404);
    }

    // Business rule: max 50 projects per workspace
← All Patterns