Skip to main content
command

nextjs-api-tester — Claude Code command: what it does, how to install

Inspects Next.js API routes and generates complete test suites. Useful for verifying authentication, payload validation, and errors across App and Pages Router.

Install into Claude Code · claude-code-templates All methods and platforms ↓
npx claude-code-templates@latest --command nextjs-vercel/nextjs-api-tester
Open on GitHub

What nextjs-api-tester does

The command inspects your project setup by scanning @app/api/ or @pages/api/. It checks the Next.js version via package.json, reads .env.local, and locates tsconfig.json alongside either jest.config.js or vitest.config.js. Then it inspects the route file to understand supported HTTP verbs, dynamic parameters, middleware, validation schemas, and database models.

From this analysis, it writes test cases covering common failure points. It creates checks for valid responses, missing JWT tokens returning 401 or 403, invalid JSON payloads, timeouts, and simulated database errors returning 500. It also outlines concurrency checks and rate-limit handling with status 429, plus manual curl calls for http://localhost:3000/.

The command requests Read, Write, Edit, and Bash tool permissions. Without Jest or Vitest pre-configured in the repository, the generated test files will fail to execute directly.

What it helps with

  • generate unit tests for GET, POST, PUT, DELETE, and PATCH endpoints
  • verify route protection against missing or invalid JWT tokens
  • test input schema validation against malformed payloads
  • produce cURL command snippets for local manual testing

Example prompts for the agent

  • /nextjs-api-tester users --method=GET
  • /nextjs-api-tester auth/login --method=POST --data='{"email":"[email protected]"}'
  • /nextjs-api-tester orders --method=POST --headers='{"Authorization":"Bearer test"}'

How to install nextjs-api-tester

1claude-code-templates

npx claude-code-templates@latest --command nextjs-vercel/nextjs-api-tester

2Manually: put the files in place

.claude/commands/nextjs-api-tester.md

Call it with /nextjs-api-tester. For all projects use ~/.claude/commands/

Questions about nextjs-api-tester

How to install nextjs-api-tester in Claude Code?

Run npx claude-code-templates@latest --command nextjs-vercel/nextjs-api-tester. This creates .claude/commands/nextjs-api-tester.md in your repository.

What does nextjs-api-tester do?

It analyzes Next.js API route implementations across App Router and Pages Router. It then generates test files covering auth, input validation, database failure handling, and concurrency.

Which test runners does it support?

It checks for either jest.config.js or vitest.config.js in the project root. Generated test syntax aligns with Jest and Vitest conventions.

Source text

nextjs-api-tester.md · MIT
---
allowed-tools: Read, Write, Edit, Bash
argument-hint: "[route-path] [--method=GET] [--data='{}'] [--headers='{}']"
description: Test and validate Next.js API routes with comprehensive test scenarios
---

## Next.js API Route Tester

**API Route**: $ARGUMENTS

## Current Project Analysis

### API Routes Detection
- App Router API: @app/api/
- Pages Router API: @pages/api/
- API configuration: @next.config.js
- Environment variables: @.env.local

### Project Context
- Next.js version: !`grep '"next"' package.json | head -1`
- TypeScript config: @tsconfig.json (if exists)
- Testing framework: @jest.config.js or @vitest.config.js (if exists)

## API Route Analysis

### Route Discovery
Based on the provided route path, analyze:
- **Route File**: Locate the actual route file
- **HTTP Methods**: Supported methods (GET, POST, PUT, DELETE, PATCH)
- **Route Parameters**: Dynamic segments and query parameters
- **Middleware**: Applied middleware functions
- **Authentication**: Required authentication/authorization

### Route Implementation Review
- Route handler implementation: @app/api/[route-path]/route.ts or @pages/api/[route-path].ts
- Type definitions: @types/ or inline types
- Validation schemas: @lib/validations/ or inline validation
- Database models: @lib/models/ or @models/

## Test Generation Strategy

### 1. Basic Functionality Tests
```javascript
// Basic API route test template
describe('API Route: /api/[route-path]', () => {
  describe('GET requests', () => {
    test('should return 200 for valid request', async () => {
      const response = await fetch('/api/[route-path]');
      expect(response.status).toBe(200);
    });

    test('should return valid JSON response', async () => {
      const response = await fetch('/api/[route-path]');
      const data = await response.json();
      expect(data).toBeDefined();
      expect(typeof data).toBe('object');
    });
  });

  describe('POST requests', () => {
    test('should create resource with valid data', async () => {
      const testData = { name: 'Test', email: '[email protected]' };
      const response = await fetch('/api/[route-path]', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(testData)
      });
      
      expect(response.status).toBe(201);
      const result = await response.json();
      expect(result.name).toBe(testData.name);
    });

    test('should reject invalid data', async () => {
      const invalidData = { invalid: 'field' };
      const response = await fetch('/api/[route-path]', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(invalidData)
      });
      
      expect(response.status).toBe(400);
    });
  });
});
```

### 2. Authentication Tests
```javascript
describe('Authentication', () => {
  test('should require authentication for protected routes', async () => {
    const response = await fetch('/api/protected-route');
    expect(response.status).toBe(401);
  });

  test('should allow authenticated requests', async () => {
    const token = 'valid-jwt-token';
    const response = await fetch('/api/protected-route', {
      headers: { 'Authorization': `Bearer ${token}` }
    });
    expect(response.status).not.toBe(401);
  });

  test('should validate JWT token format', async () => {
    const invalidToken = 'invalid-token';
    const response = await fetch('/api/protected-route', {
      headers: { 'Authorization': `Bearer ${invalidToken}` }
    });
    expect(response.status).toBe(403);
  });
});
```

### 3. Input Validation Tests
```javascript
describe('Input Validation', () => {
  const validationTests = [
    { field: 'email', invalid: 'not-an-email', valid: '[email protected]' },
    { field: 'phone', invalid: '123', valid: '+1234567890' },
    { field: 'age', invalid: -1, valid: 25 },
    { field: 'name', invalid: '', valid: 'John Doe' }
  ];

  validationTests.forEach(({ field, invalid, valid }) => {
    test(`should validate ${field} field`, async () => {
      const invalidData = { [field]: invalid };
      const validData = { [field]: valid };

      // Test invalid data
      const invalidResponse = await fetch('/api/[route-path]', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(invalidData)
      });
      expect(invalidResponse.status).toBe(400);

      // Test valid data
      const validResponse = await fetch('/api/[route-path]', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(validData)
      });
      expect(validResponse.status).not.toBe(400);
    });
  });
});
```

### 4. Error Handling Tests
```javascript
describe('Error Handling', () => {
  test('should handle malformed JSON', async () => {
    const response = await fetch('/api/[route-path]', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: 'invalid-json'
    });
    expect(response.status).toBe(400);
  });

  test('should handle missing Content-Type header', async () => {
    const response = await fetch('/api/[route-path]', {
      method: 'POST',
      body: JSON.stringify({ test: 'data' })
    });
    expect(response.status).toBe(400);
  });

  test('should handle request timeout', async () => {
    // Mock slow endpoint
    jest.setTimeout(5000);
    const response = await fetch('/api/slow-endpoint');
    // Test appropriate timeout handling
  }, 5000);

  test('should handle database connection errors', async () => {
    // Mock database failure
    const mockDbError = jest.spyOn(db, 'connect').mockRejectedValue(new Error('DB Error'));
    
    const response = await fetch('/api/[route-path]');
    expect(response.status).toBe(500);
    
    mockDbError.mockRestore();
  });
});
```

### 5. Performance Tests
```javascript
describe('Performance', () => {
  test('should respond within acceptable time', async () => {
    const startTime = Date.now();
    const response = await fetch('/api/[route-path]');
    const endTime = Date.now();
    
    expect(response.status).toBe(200);
    expect(endTime - startTime).toBeLessThan(1000); // 1 second
  });

  test('should handle concurrent requests', async () => {
    const promises = Array.from({ length: 10 }, () =>
      fetch('/api/[route-path]')
    );
    
    const responses = await Promise.all(promises);
    responses.forEach(response => {
      expect(response.status).toBe(200);
    });
  });

  test('should implement rate limiting', async () => {
    const requests = Array.from({ length: 100 }, () =>
      fetch('/api/[route-path]')
    );
    
    const responses = await Promise.all(requests);
    const rateLimitedResponses = responses.filter(r => r.status === 429);
    expect(rateLimitedResponses.length).toBeGreaterThan(0);
  });
});
```

## Manual Testing Commands

### cURL Commands Generation
```bash
# GET request
curl -X GET "http://localhost:3000/api/[route-path]" \
  -H "Accept: application/json"

# POST request with data
curl -X POST "http://localhost:3000/api/[route-path]" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"key": "value"}'

# Authenticated request
curl -X GET "http://localhost:3000/api/protected-route" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -H "Accept: application/json"

# Upload file
curl -X POST "http://localhost:3000/api/upload" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -F "file=@path/to/file.jpg"
```

### HTTPie Commands
```bash
# GET request
http GET localhost:3000/api/[route-path]

# POST request with JSON
http POST localhost:3000/api/[route-path] key=value

# Authenticated request
http GET localhost:3000/api/protected-route Authorization:"Bearer TOKEN"

# Custom headers
http GET localhost:3000/api/[route-path] X-Custom-Header:value
```

## Interactive Testing Tools

### Postman Collection Generation
```json
{
  "info": {
    "name": "Next.js API Tests",
    "description": "Generated API tests for [route-path]"
  },
  "item": [
    {
      "name": "GET [route-path]",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/[route-path]",
          "host": ["{{baseUrl}}"],
          "path": ["api", "[route-path]"]
        }
      }
    },
    {
      "name": "POST [route-path]",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"key\": \"value\"\n}"
        },
        "url": {
          "raw": "{{baseUrl}}/api/[route-path]",
          "host": ["{{baseUrl}}"],
          "path": ["api", "[route-path]"]
        }
      }
    }
  ]
}
```

### Thunder Client Collection
```json
{
  "client": "Thunder Client",
  "collectionName": "Next.js API Tests",
  "dateExported": "2024-01-01",
  "version": "1.1",
  "folders": [],
  "requests": [
    {
      "name": "Test API Route",
      "url": "localhost:3000/api/[route-path]",
      "method": "GET",
      "headers": [
        {
          "name": "Accept",
          "value": "application/json"
        }
      ]
    }
  ]
}
```

## Test Data Management

### Test Fixtures
```typescript
// test/fixtures/apiTestData.ts
export const validUserData = {
  name: 'John Doe',
  email: '[email protected]',
  age: 30,
  role: 'user'
};

export const invalidUserData = {
  name: '',
  email: 'invalid-email',
  age: -1,
  role: 'invalid-role'
};

export const testHeaders = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'User-Agent': 'API-Test-Suite/1.0'
};
```

### Mock Data Generation
```typescript
// test/utils/mockData.ts
export function generateMockUser() {
  return {
    id: Math.random().toString(36).substr(2, 9),
    name: `User ${Math.floor(Math.random() * 1000)}`,
    email: `user${Date.now()}@example.com`,
    createdAt: new Date().toISOString()
  };
}

export function generateBulkTestData(count: number) {
  return Array.from({ length: count }, generateMockUser);
}
```

## Test Environment Setup

### Jest Configuration
```javascript
// jest.config.js for API testing
module.exports = {
  testEnvironment: 'node',
  setupFilesAfterEnv: ['<rootDir>/test/setup.js'],
  testMatch: ['**/__tests__/**/*.test.js', '**/?(*.)+(spec|test).js'],
  collectCoverageFrom: [
    'pages/api/**/*.{js,ts}',
    'app/api/**/*.{js,ts}',
    '!**/*.d.ts',
  ],
  coverageThreshold: {
    global: {
      branches: 70,
      functions: 70,
      lines: 70,
      statements: 70
    }
  }
};
```

### Test Setup
```javascript
// test/setup.js
import { createMocks } from 'node-mocks-http';
import { testDb } from './testDatabase';

// Global test setup
beforeAll(async () => {
  // Setup test database
  await testDb.connect();
});

afterAll(async () => {
  // Cleanup test database
  await testDb.disconnect();
});

beforeEach(async () => {
  // Reset database state
  await testDb.reset();
});

// Helper function for API testing
global.createAPITest = (handler) => {
  return (method, url, options = {}) => {
    const { req, res } = createMocks({
      method,
      url,
      ...options
    });
    return handler(req, res);
  };
};
```

## Automated Testing Integration

### GitHub Actions Workflow
```yaml
name: API Tests
on: [push, pull_request]

jobs:
  test-api:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: npm run test:api
      - name: Upload coverage
        uses: codecov/codecov-action@v3
```

### Continuous Testing
```bash
# Watch mode for development
npm run test:api -- --watch

# Coverage reporting
npm run test:api -- --coverage

# Specific route testing
npm run test:api -- --testNamePattern="api/users"
```

## Test Results Analysis

Generate comprehensive test report including:
1. **Test Coverage**: Line, branch, function coverage percentages
2. **Performance Metrics**: Response times, throughput
3. **Security Analysis**: Authentication, authorization, input validation
4. **Error Handling**: Exception scenarios and error responses
5. **Compatibility**: Cross-environment testing results

Provide actionable recommendations for improving API reliability, performance, and security.

© davila7 · MIT · davila7/claude-code-templates

Similar slash commands

All slash commands for Backend and APIs →

From the same set361

The whole set →

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor