Claude
Skills
Sign in
Back

backend-patterns

Included with Lifetime
$97 forever

API design, database operations, error handling, and backend architecture patterns. Use when creating APIs, database schemas, or server-side logic.

Design

What this skill does


# Backend Patterns

Comprehensive patterns for API design, database operations, error handling, and backend architecture.

## When to Use

- Creating API endpoints
- Designing database schemas
- Implementing business logic
- Error handling and logging
- Background jobs and queues
- Caching strategies

## API Design Patterns

### RESTful API Structure

```typescript
// app/api/users/route.ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const page = parseInt(searchParams.get('page') || '1')
  const limit = parseInt(searchParams.get('limit') || '10')

  const users = await db.users.findMany({
    skip: (page - 1) * limit,
    take: limit
  })

  return NextResponse.json({
    success: true,
    data: users,
    pagination: {
      page,
      limit,
      total: await db.users.count()
    }
  })
}

export async function POST(request: Request) {
  const body = await request.json()

  // Validate input
  const validated = CreateUserSchema.parse(body)

  const user = await db.users.create({ data: validated })

  return NextResponse.json(
    { success: true, data: user },
    { status: 201 }
  )
}

// app/api/users/[id]/route.ts
export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  const user = await db.users.findUnique({
    where: { id: params.id }
  })

  if (!user) {
    return NextResponse.json(
      { error: 'User not found' },
      { status: 404 }
    )
  }

  return NextResponse.json({ success: true, data: user })
}

export async function PATCH(
  request: Request,
  { params }: { params: { id: string } }
) {
  const body = await request.json()
  const validated = UpdateUserSchema.parse(body)

  const user = await db.users.update({
    where: { id: params.id },
    data: validated
  })

  return NextResponse.json({ success: true, data: user })
}

export async function DELETE(
  request: Request,
  { params }: { params: { id: string } }
) {
  await db.users.delete({ where: { id: params.id } })

  return NextResponse.json({ success: true }, { status: 204 })
}
```

### Consistent API Response Format

```typescript
type ApiResponse<T> = {
  success: true
  data: T
  meta?: {
    pagination?: {
      page: number
      limit: number
      total: number
    }
  }
} | {
  success: false
  error: string
  details?: any
}

// Success response helper
function successResponse<T>(data: T, meta?: any): Response {
  return NextResponse.json({ success: true, data, meta })
}

// Error response helper
function errorResponse(error: string, status: number, details?: any): Response {
  return NextResponse.json(
    { success: false, error, details },
    { status }
  )
}

// Usage
export async function GET(request: Request) {
  try {
    const users = await db.users.findMany()
    return successResponse(users)
  } catch (error) {
    return errorResponse('Failed to fetch users', 500)
  }
}
```

### API Versioning

```typescript
// app/api/v1/users/route.ts
export async function GET(request: Request) {
  // Version 1 implementation
  return NextResponse.json({ version: 1, users: [] })
}

// app/api/v2/users/route.ts
export async function GET(request: Request) {
  // Version 2 implementation with breaking changes
  return NextResponse.json({ version: 2, data: { users: [] } })
}
```

### Request Validation

```typescript
import { z } from 'zod'

const CreateMarketSchema = z.object({
  name: z.string().min(3).max(100),
  description: z.string().min(10).max(1000),
  category: z.enum(['politics', 'sports', 'entertainment', 'crypto']),
  endDate: z.string().datetime(),
  options: z.array(z.object({
    name: z.string().min(1).max(50),
    probability: z.number().min(0).max(1).optional()
  })).min(2).max(10)
})

export async function POST(request: Request) {
  try {
    const body = await request.json()
    const validated = CreateMarketSchema.parse(body)

    // Safe to use validated data
    const market = await db.markets.create({ data: validated })

    return NextResponse.json({ success: true, data: market })

  } catch (error) {
    if (error instanceof z.ZodError) {
      return NextResponse.json(
        {
          success: false,
          error: 'Validation failed',
          details: error.errors
        },
        { status: 400 }
      )
    }

    return NextResponse.json(
      { success: false, error: 'Internal server error' },
      { status: 500 }
    )
  }
}
```

## Database Patterns

### Database Schema Design

```typescript
// Prisma schema example
model User {
  id            String   @id @default(cuid())
  email         String   @unique
  name          String
  passwordHash  String
  role          Role     @default(USER)
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt

  posts         Post[]
  comments      Comment[]

  @@index([email])
  @@index([createdAt])
}

model Post {
  id          String   @id @default(cuid())
  title       String
  content     String   @db.Text
  published   Boolean  @default(false)
  authorId    String
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  author      User     @relation(fields: [authorId], references: [id], onDelete: Cascade)
  comments    Comment[]
  tags        Tag[]

  @@index([authorId])
  @@index([published])
  @@index([createdAt])
  @@fulltext([title, content]) // For search
}

model Comment {
  id        String   @id @default(cuid())
  content   String   @db.Text
  postId    String
  authorId  String
  createdAt DateTime @default(now())

  post      Post     @relation(fields: [postId], references: [id], onDelete: Cascade)
  author    User     @relation(fields: [authorId], references: [id], onDelete: Cascade)

  @@index([postId])
  @@index([authorId])
}

enum Role {
  USER
  MODERATOR
  ADMIN
}
```

### Transaction Patterns

```typescript
// ❌ WRONG: No transaction (race condition)
export async function transferFunds(fromId: string, toId: string, amount: number) {
  const sender = await db.accounts.findUnique({ where: { id: fromId } })

  if (sender.balance < amount) {
    throw new Error('Insufficient funds')
  }

  // Race condition: balance could change between these operations
  await db.accounts.update({
    where: { id: fromId },
    data: { balance: sender.balance - amount }
  })

  await db.accounts.update({
    where: { id: toId },
    data: { balance: { increment: amount } }
  })
}

// ✅ CORRECT: Use transactions
export async function transferFunds(fromId: string, toId: string, amount: number) {
  await db.$transaction(async (tx) => {
    // Lock sender account for update
    const sender = await tx.accounts.findUnique({
      where: { id: fromId }
    })

    if (!sender || sender.balance < amount) {
      throw new Error('Insufficient funds')
    }

    // Atomic updates
    await tx.accounts.update({
      where: { id: fromId },
      data: { balance: { decrement: amount } }
    })

    await tx.accounts.update({
      where: { id: toId },
      data: { balance: { increment: amount } }
    })

    // Create transaction record
    await tx.transactions.create({
      data: {
        fromId,
        toId,
        amount,
        status: 'completed'
      }
    })
  })
}
```

### Query Optimization

```typescript
// ❌ WRONG: N+1 query problem
const users = await db.users.findMany()
for (const user of users) {
  user.posts = await db.posts.findMany({
    where: { authorId: user.id }
  })
}

// ✅ CORRECT: Use includes/eager loading
const users = await db.users.findMany({
  include: {
    posts: true
  }
})

// ✅ CORRECT: Select only needed fields
const users = await db.users.findMany({
  select: {
    id: true,
    name: true,
    email: true,
    posts: {
      select: {
        id: true,
        title: true,
        createdAt: true
      }
    }
  }
})

// ✅ CORRECT: Pagination for large datasets
const posts = await db.posts.findMany({
  take: 20,
  skip: (page - 1) * 20,
  orderBy: { createdAt: 'desc' }
})
```

### Supabase Patterns

```typescript
im

Related in Design