DEV Community

Preecha
Preecha

Posted on

How to Set Up 5 AI Agents to Build a Complete API (From Spec to Test)

Stop using one generic AI assistant for everything. Instead, use five specialized agents to build and validate a complete API: a Backend Architect designs the system, a Database Optimizer reviews the schema, a Frontend Developer builds the client, a Code Reviewer checks security, and a Reality Checker validates the result before you ship.

Try Apidog today

When you need to build an API quickly, it is tempting to ask one AI to handle everything: database design, endpoints, frontend, code review, and testing.

That approach often leaves gaps:

  • Missing database indexes
  • Security issues in endpoints
  • Frontend flows without loading or error states
  • Validation based on “looks good to me”

Specialized agents address this by giving each stage a focused responsibility, checklist, and output. The Backend Architect focuses on system design. The Database Optimizer finds schema and query issues. The Code Reviewer audits implementation risks. The Reality Checker requires evidence before approval.

In this tutorial, you will configure five agents from The Agency collection and use them in an end-to-end API workflow. You will also integrate Apidog for API testing and documentation so endpoints can be validated against OpenAPI specifications before deployment.

The 5 Agents You’ll Use

Agent Division Responsibility
Backend Architect Engineering API design, database schema, authentication
Database Optimizer Engineering Index recommendations, query optimization
Frontend Developer Engineering React components, API client, state management
Code Reviewer Engineering Security audit, type safety, error handling
Reality Checker Testing Evidence-based validation, screenshot proof

Install the agents:

# Clone The Agency repo
git clone https://github.com/msitarzewski/agency-agents.git
cd agency-agents

# Copy agents to Claude Code
cp engineering/engineering-backend-architect.md ~/.claude/agents/
cp engineering/engineering-database-optimizer.md ~/.claude/agents/
cp engineering/engineering-frontend-developer.md ~/.claude/agents/
cp engineering/engineering-code-reviewer.md ~/.claude/agents/
cp testing/testing-reality-checker.md ~/.claude/agents/
Enter fullscreen mode Exit fullscreen mode

Step 1: Use Backend Architect to Design the System

Start a new Claude Code session and activate Backend Architect mode.

Use this prompt:

Activate Backend Architect mode.

Design a REST API for an e-commerce platform with:
- User authentication (JWT with refresh tokens)
- Product catalog with categories and filtering
- Shopping cart management
- Order processing with status tracking
- Payment webhook integration

Output:
1. OpenAPI 3.0 specification
2. PostgreSQL database schema with relationships
3. Project folder structure (Express.js + TypeScript)
4. Authentication flow diagram
Enter fullscreen mode Exit fullscreen mode

Save the output from this step. The OpenAPI specification and database schema become inputs for the next agents.

Expected Deliverables

OpenAPI specification

openapi: 3.0.0
info:
  title: E-commerce API
  version: 1.0.0
paths:
  /auth/login:
    post:
      summary: User login
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email: { type: string, format: email }
                password: { type: string, minLength: 8 }
      responses:
        '200':
          description: JWT tokens
          content:
            application/json:
              schema:
                type: object
                properties:
                  accessToken: { type: string }
                  refreshToken: { type: string }
Enter fullscreen mode Exit fullscreen mode

PostgreSQL schema

CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE TABLE products (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(255) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
    category_id UUID REFERENCES categories(id),
    inventory_count INTEGER DEFAULT 0,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE TABLE orders (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID REFERENCES users(id),
    total_amount DECIMAL(10, 2) NOT NULL,
    status VARCHAR(50) DEFAULT 'pending',
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
Enter fullscreen mode Exit fullscreen mode

Express and TypeScript project structure

src/
├── controllers/
│   ├── auth.controller.ts
│   ├── products.controller.ts
│   └── orders.controller.ts
├── middleware/
│   ├── auth.middleware.ts
│   └── validation.middleware.ts
├── routes/
│   ├── auth.routes.ts
│   ├── products.routes.ts
│   └── orders.routes.ts
├── services/
│   ├── auth.service.ts
│   ├── products.service.ts
│   └── orders.service.ts
├── models/
│   ├── User.ts
│   ├── Product.ts
│   └── Order.ts
└── index.ts
Enter fullscreen mode Exit fullscreen mode

Step 2: Ask Database Optimizer to Review the Schema

Open a new session and activate Database Optimizer mode.

Paste the schema generated in Step 1, then use this prompt:

Activate Database Optimizer mode.

Review this PostgreSQL schema for an e-commerce API:

[Paste the schema from Step 1]

Check for:
1. Missing indexes on foreign keys and frequently queried columns
2. Query performance on product search (name, category, price range)
3. Proper constraints for data integrity
4. Missing tables for common e-commerce features (reviews, wishlists)
5. Soft delete patterns for audit trails

Output specific ALTER TABLE statements and new table definitions.
Enter fullscreen mode Exit fullscreen mode

Apply the recommended indexes, constraints, and tables before implementing the API.

Expected Deliverables

Index recommendations

-- Add indexes on foreign keys
CREATE INDEX idx_products_category_id ON products(category_id);
CREATE INDEX idx_orders_user_id ON orders(user_id);

-- Add index for product search
CREATE INDEX idx_products_name_search
ON products
USING gin(to_tsvector('english', name));

CREATE INDEX idx_products_price
ON products(price)
WHERE inventory_count > 0;

-- Add composite index for category filtering
CREATE INDEX idx_products_category_price
ON products(category_id, price);
Enter fullscreen mode Exit fullscreen mode

Missing tables

CREATE TABLE reviews (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    product_id UUID REFERENCES products(id),
    user_id UUID REFERENCES users(id),
    rating INTEGER CHECK (rating >= 1 AND rating <= 5),
    comment TEXT,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(product_id, user_id)
);

CREATE TABLE cart_items (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID REFERENCES users(id),
    product_id UUID REFERENCES products(id),
    quantity INTEGER DEFAULT 1 CHECK (quantity > 0),
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(user_id, product_id)
);
Enter fullscreen mode Exit fullscreen mode

Constraints and soft-delete support

-- Email format validation
ALTER TABLE users
ADD CONSTRAINT chk_email_format
CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$');

-- Soft delete column
ALTER TABLE products
ADD COLUMN deleted_at TIMESTAMP WITH TIME ZONE NULL;

CREATE INDEX idx_products_deleted_at
ON products(deleted_at)
WHERE deleted_at IS NULL;
Enter fullscreen mode Exit fullscreen mode

Step 3: Have Frontend Developer Build the Client

Open another session and activate Frontend Developer mode.

Provide the OpenAPI specification from Step 1:

Activate Frontend Developer mode.

Build a React dashboard for this e-commerce API:

[Paste OpenAPI spec from Step 1]

Requirements:
- TypeScript with strict mode
- React Query for server state management
- Product list with filters (category, price range, search)
- Shopping cart with real-time updates
- Order history with status tracking
- Proper error handling and loading states
- Responsive design (mobile, tablet, desktop)

Output:
1. Project setup (Vite + React + TypeScript)
2. API client with React Query hooks
3. Core components (ProductList, ProductCard, Cart, OrderHistory)
4. Error boundary and loading skeletons
Enter fullscreen mode Exit fullscreen mode

Expected Deliverables

API client with React Query hooks

// src/lib/api-client.ts
import { QueryClient, useQuery, useMutation } from '@tanstack/react-query';

const API_BASE = 'http://localhost:3000/api';

async function fetcher<T>(endpoint: string, options?: RequestInit): Promise<T> {
  const response = await fetch(`${API_BASE}${endpoint}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...options?.headers,
    },
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message || 'Request failed');
  }

  return response.json();
}

export function useProducts(filters?: ProductFilters) {
  const params = new URLSearchParams(filters as Record<string, string>);

  return useQuery({
    queryKey: ['products', filters],
    queryFn: () => fetcher<Product[]>(`/products?${params}`),
  });
}

export function useAddToCart() {
  return useMutation({
    mutationFn: (item: CartItem) =>
      fetcher<CartItem>('/cart', {
        method: 'POST',
        body: JSON.stringify(item),
      }),
  });
}
Enter fullscreen mode Exit fullscreen mode

Product list component

// src/components/ProductList.tsx
import { useProducts } from '@/lib/api-client';
import { ProductCard } from './ProductCard';
import { FilterSidebar } from './FilterSidebar';
import { Skeleton } from './ui/skeleton';

export function ProductList() {
  const [filters, setFilters] = useState<ProductFilters>({});
  const { data: products, isLoading, error } = useProducts(filters);

  if (error) {
    return <Alert variant="destructive">{error.message}</Alert>;
  }

  return (
    <div className="flex gap-4">
      <FilterSidebar filters={filters} onFilterChange={setFilters} />

      <div className="flex-1 grid grid-cols-1 md:grid-cols-3 gap-4">
        {isLoading ? (
          Array.from({ length: 6 }).map((_, i) => (
            <Skeleton key={i} className="h-64" />
          ))
        ) : products?.length === 0 ? (
          <EmptyState message="No products found" />
        ) : (
          products?.map((product) => (
            <ProductCard key={product.id} product={product} />
          ))
        )}
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Error boundary

// src/components/ErrorBoundary.tsx
export class ErrorBoundary extends React.Component<
  { children: React.ReactNode },
  { hasError: boolean; error: Error | null }
> {
  constructor(props: { children: React.ReactNode }) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error: Error) {
    return { hasError: true, error };
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="p-4 bg-red-50 border border-red-200 rounded">
          <h2 className="text-lg font-semibold text-red-800">
            Something went wrong
          </h2>

          <p className="text-red-600">{this.state.error?.message}</p>

          <Button
            onClick={() => window.location.reload()}
            className="mt-2"
          >
            Reload
          </Button>
        </div>
      );
    }

    return this.props.children;
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Run Code Reviewer Before Deployment

Once the backend and frontend implementation exist, open a new session and activate Code Reviewer mode.

Activate Code Reviewer mode.

Review this codebase for:

1. Security vulnerabilities:
   - SQL injection risks
   - XSS vulnerabilities
   - CSRF protection
   - Authentication bypass possibilities

2. TypeScript strict mode compliance:
   - No implicit any
   - Proper type definitions
   - Null/undefined handling

3. Error handling gaps:
   - Uncaught promise rejections
   - Missing try/catch blocks
   - Silent failures

[Paste the code from Steps 1-3]

Output a report with severity ratings (Critical, High, Medium, Low) and specific fixes.
Enter fullscreen mode Exit fullscreen mode

Do not proceed to final validation until Critical and High issues are addressed.

Expected Deliverables

Security report

## Critical Issues

### 1. SQL Injection in Product Search

**Location:** `src/controllers/products.controller.ts:24`

**Issue:** User input concatenated directly into SQL query.

Enter fullscreen mode Exit fullscreen mode


typescript
// VULNERABLE
const query = SELECT * FROM products WHERE name LIKE '%${search}%';


**Fix:** Use parameterized queries.

Enter fullscreen mode Exit fullscreen mode


typescript
const query = 'SELECT * FROM products WHERE name LIKE $1';
await db.query(query, [%${search}%]);


## High Issues

### 2. Missing CSRF Protection

**Location:** `src/index.ts`

**Issue:** No CSRF middleware for state-changing operations.

**Fix:** Add `csurf` middleware.

Enter fullscreen mode Exit fullscreen mode


typescript
import csrf from 'csurf';

app.use(csrf({ cookie: true }));


## Medium Issues

### 3. Implicit Any in API Response

**Location:** `src/lib/api-client.ts:8`

**Issue:** Generic `any` type for the fetcher function.

**Fix:** Add proper type constraints.

Enter fullscreen mode Exit fullscreen mode


typescript
async function fetcher>(
endpoint: string,
options?: RequestInit
): Promise {
// ...
}

Enter fullscreen mode Exit fullscreen mode


markdown

Type safety report

## TypeScript Violations

1. `products.controller.ts:45` - Missing return type annotation
2. `auth.middleware.ts:12` - Implicit any in catch block
3. `orders.service.ts:78` - Object possibly undefined

Run `tsc --noEmit` to see the full list. Fix before deployment.
Enter fullscreen mode Exit fullscreen mode

Apply the fixes, then run TypeScript validation:

tsc --noEmit
Enter fullscreen mode Exit fullscreen mode

Step 5: Use Reality Checker for Final Validation

The Reality Checker should be the last gate before deployment. It verifies that claimed features exist in the codebase and requires test evidence.

Open a new session:

Activate Reality Checker mode.

This e-commerce API is ready for production validation.

Run your mandatory reality check process:

1. Verify files exist
2. Cross-reference claimed features with actual code
3. Require screenshot evidence from Playwright tests
4. Review test-results.json for performance metrics

Project URL: http://localhost:3000
Test results: ./public/qa-screenshots/test-results.json

Output: PASS or NEEDS WORK with specific blocking issues.
Enter fullscreen mode Exit fullscreen mode

Reality Check Commands

# 1. Verify files exist
ls -la src/controllers/ src/services/ src/routes/
ls -la src/components/ src/lib/

# 2. Cross-reference claimed features
grep -r "jwt\|jsonwebtoken" . --include="*.ts" || echo "NO JWT FOUND"
grep -r "bcrypt\|argon2" . --include="*.ts" || echo "NO PASSWORD HASHING FOUND"
grep -r "rateLimit\|express-rate-limit" . --include="*.ts" || echo "NO RATE LIMITING FOUND"

# 3. Run Playwright screenshot capture
npx playwright test --config=qa-playwright.config.ts --grep "@screenshot"

# 4. Review test results
cat public/qa-screenshots/test-results.json
Enter fullscreen mode Exit fullscreen mode

Example Validation Report

## Reality Check Results

### File Verification: PASS
- All controller files present
- All component files present

### Feature Verification: NEEDS WORK
- JWT authentication: FOUND
- Password hashing: FOUND
- Rate limiting: NOT FOUND (blocking)

### Screenshot Evidence: NEEDS WORK
- Desktop layout: PASS
- Tablet layout: PASS
- Mobile layout: FAIL (product grid broken at 375px)

### Performance Metrics: NEEDS WORK
- Average load time: 2.3s (target: <1s)
- Console errors: 3 (target: 0)
- Failed network requests: 1 (target: 0)

## Final Status: NEEDS WORK

### Blocking Issues
1. Rate limiting not implemented
2. Mobile layout broken on product list
3. 3 console errors to fix
4. Load time exceeds 1s target

### Non-Blocking
- Add loading skeletons to order history
- Improve error messages
Enter fullscreen mode Exit fullscreen mode

Fix every blocking issue, then run the Reality Checker again.

Workflow Summary

┌─────────────────────────────────────────────────────────────────┐
│  Backend Architect                                              │
│  → OpenAPI spec, database schema, folder structure              │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Database Optimizer                                             │
│  → Index recommendations, missing tables, constraints           │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Frontend Developer                                             │
│  → React components, API client, error handling                 │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Code Reviewer                                                  │
│  → Security audit, type safety, error handling gaps             │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Reality Checker                                                │
│  → Evidence-based validation, screenshot proof, PASS/FAIL       │
└─────────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Parallel Agent Execution

Once you understand the dependencies, run independent stages in separate terminals to reduce overall time.

# Terminal 1: Backend Architect
claude "Activate Backend Architect. Design e-commerce API..."

# Terminal 2: Database Optimizer (wait for schema output)
claude "Activate Database Optimizer. Review this schema..."

# Terminal 3: Frontend Developer (wait for API spec)
claude "Activate Frontend Developer. Build React dashboard..."

# Terminal 4: Code Reviewer (wait for code)
claude "Activate Code Reviewer. Review this codebase..."

# Final validation
claude "Activate Reality Checker. Run mandatory checks..."
Enter fullscreen mode Exit fullscreen mode

With parallel execution, you can complete the workflow in 2–4 hours instead of 6–8 hours.

What You Built

Deliverable Agent Output
API design Backend Architect OpenAPI spec, database schema, folder structure
Schema optimization Database Optimizer Index recommendations, additional tables, constraints
Frontend Frontend Developer React components, API client, error boundaries
Security audit Code Reviewer Vulnerability report, type safety fixes
Final validation Reality Checker Screenshot evidence, PASS/FAIL certification

Next Steps

Deploy the API

  • Set up production PostgreSQL with connection pooling.
  • Configure environment variables for secrets.
  • Add health-check endpoints.
  • Set up monitoring with Prometheus and Grafana.

Extend the workflow

  • Add a Performance Benchmarker agent for load testing.
  • Add a Technical Writer agent for documentation.
  • Add a DevOps Automator agent for the CI/CD pipeline.

Reuse the process

  • Save your agent prompts as templates.
  • Create a workflow script that chains agent sessions.
  • Share the process with your team.

Five specialized agents. One complete API. No generic advice.

Each agent has a focused domain, a checklist, and concrete deliverables. Start with a project, activate the relevant agents, and use evidence-based validation before shipping.

Key Takeaways

  • Specialized agents outperform generic assistants. Each agent has domain expertise, checklists, and specific deliverables.
  • A sequential workflow improves quality. Backend Architect designs, Database Optimizer reviews, Frontend Developer builds, Code Reviewer audits, and Reality Checker validates.
  • Evidence-based approval catches bugs. Reality Checker requires screenshots, grep results, and performance metrics before PASS certification.
  • Parallel execution reduces total time. Run agents in separate terminals to complete the workflow in 2–4 hours instead of 6–8 hours.
  • Save prompts as templates. Reuse the same activations for consistent results across projects.

FAQ

What are AI agents for developers?

AI agents are specialized AI assistants with domain expertise. Unlike generic chatbots, agents such as Backend Architect and Code Reviewer use specific checklists and produce consistent deliverables.

How do I install agents from The Agency?

Clone the repository at github.com/msitarzewski/agency-agents, then copy the .md files to ~/.claude/agents/ for Claude Code. You can also use the install script for other tools.

What is the Reality Checker agent?

Reality Checker is an evidence-based QA agent that does not approve work without proof. It requires screenshots, grep results, and performance metrics before returning PASS certification.

Can I run multiple agents in parallel?

Yes. Open multiple terminals and activate different agents in each. Pass deliverables by copying output between sessions or by using MCP memory for automatic handoffs.

How do I pass context between agents?

Copy output from one agent and paste it into the next agent’s prompt. For automatic handoffs, use MCP memory to store deliverables that the next agent can recall.

What if an agent says NEEDS WORK?

Fix the blocking issues identified in the report, then run that agent again. Reality Checker specifically lists the issues that must be fixed before it can return PASS.

Do I need all five agents for every project?

No. Start with Backend Architect and Code Reviewer for API projects. Add Database Optimizer for complex schemas, Frontend Developer for UI work, and Reality Checker before shipping.

Top comments (0)