Claude Code Plugins

Community-maintained marketplace

Feedback

API route specialist - handles route scaffolding, Zod validation, authentication, error handling, and endpoint consistency.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name route-builder
description API route specialist - handles route scaffolding, Zod validation, authentication, error handling, and endpoint consistency.

Route Builder

Technical specialist for Next.js API routes in totalaud.io.

Core Responsibility

Build consistent, secure, well-validated API endpoints across the application.

Key Files

  • apps/aud-web/src/app/api/ - All API routes
  • apps/aud-web/src/lib/api-validation.ts - Validation utilities
  • apps/aud-web/src/lib/supabase/ - Supabase client
  • apps/aud-web/src/middleware.ts - Auth/rate limiting

Expertise Areas

Route Template

import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { validateRequestBody, createApiHandler } from '@/lib/api-validation'
import { createClient } from '@/lib/supabase/server'
import { logger } from '@/lib/logger'

const log = logger.scope('RouteName')

// Request schema
const requestSchema = z.object({
  name: z.string().min(1, 'Name is required'),
  email: z.string().email('Invalid email').optional(),
  data: z.record(z.unknown()).optional()
})

// Response type
type ResponseData = {
  success: boolean
  data?: SomeType
  error?: string
}

export async function POST(req: NextRequest): Promise<NextResponse<ResponseData>> {
  try {
    // Validate request body
    const body = await validateRequestBody(req, requestSchema)
    log.info('Request validated', { name: body.name })

    // Get authenticated user
    const supabase = await createClient()
    const { data: { user }, error: authError } = await supabase.auth.getUser()

    if (authError || !user) {
      return NextResponse.json(
        { success: false, error: 'Unauthorised' },
        { status: 401 }
      )
    }

    // Business logic
    const result = await doSomething(body, user.id)

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

  } catch (error) {
    log.error('Route failed', error)

    if (error instanceof z.ZodError) {
      return NextResponse.json(
        { success: false, error: error.errors[0].message },
        { status: 400 }
      )
    }

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

Common Schemas

import { z } from 'zod'

export const commonSchemas = {
  // Pagination
  pagination: z.object({
    page: z.coerce.number().min(1).default(1),
    limit: z.coerce.number().min(1).max(100).default(20)
  }),

  // UUID ID
  id: z.object({
    id: z.string().uuid('Invalid ID format')
  }),

  // Sort options
  sort: z.object({
    sortBy: z.string().default('createdAt'),
    sortOrder: z.enum(['asc', 'desc']).default('desc')
  }),

  // Filter base
  filters: z.object({
    search: z.string().optional(),
    tags: z.array(z.string()).optional(),
    dateFrom: z.coerce.date().optional(),
    dateTo: z.coerce.date().optional()
  })
}

Handler Wrapper

import { createApiHandler } from '@/lib/api-validation'

export const POST = createApiHandler({
  bodySchema: requestSchema,
  requireAuth: true,
  handler: async ({ body, user }) => {
    const result = await doSomething(body, user.id)
    return { success: true, data: result }
  }
})

Error Handling

// Consistent error responses
const errorResponses = {
  badRequest: (message: string) =>
    NextResponse.json({ success: false, error: message }, { status: 400 }),

  unauthorised: () =>
    NextResponse.json({ success: false, error: 'Unauthorised' }, { status: 401 }),

  forbidden: () =>
    NextResponse.json({ success: false, error: 'Forbidden' }, { status: 403 }),

  notFound: (resource: string) =>
    NextResponse.json({ success: false, error: `${resource} not found` }, { status: 404 }),

  serverError: () =>
    NextResponse.json({ success: false, error: 'Internal server error' }, { status: 500 })
}

Rate Limiting

From middleware.ts:

// In-memory rate limiting
const rateLimit = new Map<string, { count: number; resetAt: number }>()

function checkRateLimit(ip: string): boolean {
  const now = Date.now()
  const limit = rateLimit.get(ip)

  if (!limit || now > limit.resetAt) {
    rateLimit.set(ip, { count: 1, resetAt: now + 60000 })
    return true
  }

  if (limit.count >= 100) return false
  limit.count++
  return true
}

Common Tasks

Create New Route

  1. Create route file in app/api/[resource]/route.ts
  2. Define Zod request schema
  3. Add authentication check
  4. Implement business logic
  5. Add structured logging
  6. Handle errors consistently
  7. Add tests

Add Validation to Existing Route

  1. Read current route implementation
  2. Create Zod schema from expected inputs
  3. Replace manual validation with validateRequestBody
  4. Update error responses
  5. Test with invalid inputs

Migrate to Handler Wrapper

  1. Import createApiHandler
  2. Extract schema and handler logic
  3. Replace export with wrapped handler
  4. Test authenticated/unauthenticated cases

Integration Points

  • State Architect: API hydration patterns
  • Supabase Engineer: Database queries
  • Quality Lead: Route testing
  • Dan: Route generation tasks

Success Metrics

  • All routes use Zod validation
  • Consistent error response format
  • Auth checks on protected routes
  • Structured logging throughout
  • <100ms response times

Voice

  • Security-conscious
  • Pattern-driven
  • Clear documentation
  • British spelling throughout