mcpField
A
api-endpoint-builder

api-endpoint-builder

github.com/sickn33Development48.7k187 installsUpdated today
Repository

About api-endpoint-builder

A skill for scaffolding reviewable REST API endpoints, aimed at developers adding backend routes. It covers validation, access checks, error handling, response formatting, documentation, and optional tests.

Key features

  1. 01Route handler scaffolds
  2. 02Request input validation
  3. 03Authentication and authorization checks
  4. 04Consistent errors and responses
  5. 05Endpoint documentation and tests

Use cases

  1. 01Add a CRUD endpoint to an API
  2. 02Validate request bodies and parameters
  3. 03Protect routes with access checks
  4. 04Document and test critical routes

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill api-endpoint-builder

After installing, type/api-endpoint-builderin Claude Code to confirm it loaded.

Bundled filesREADME.md

Details

From the project README

API Endpoint Builder

Build complete, reviewable REST API endpoint scaffolds with proper validation, error handling, authentication, and documentation.

When to Use This Skill

  • User asks to "create an API endpoint" or "build a REST API"
  • Building new backend features
  • Adding endpoints to existing APIs
  • User mentions "API", "endpoint", "route", or "REST"
  • Creating CRUD operations

What You'll Build

For each endpoint, you create:

  • Route handler with proper HTTP method
  • Input validation (request body, params, query)
  • Authentication/authorization checks
  • Business logic
  • Error handling
  • Response formatting
  • API documentation
  • Tests (if requested)

Endpoint Structure

1. Route Definition
// Express example
router.post('/api/users', authenticate, validateUser, createUser);

// Fastify example
fastify.post('/api/users', {
  preHandler: [authenticate],
  schema: userSchema
}, createUser);
2. Input Validation

Always validate before processing:

const validateUser = (req, res, next) => {
  const { email, name, password } = req.body ?? {};
  
  if (typeof email !== 'string' || !email.includes('@')) {
    return res.status(400).json({ error: 'Valid email required' });
  }
  
  if (typeof name !== 'string' || name.trim().length < 2) {
    return res.status(400).json({ error: 'Name must be at least 2 characters' });
  }
  
  if (typeof password !== 'string' || password.length < 8) {
    return res.status(400).json({ error: 'Password must be at least 8 characters' });
  }
  
  next();
};
3. Handler Implementation
const createUser = async (req, res) => {
  try {
    const { email, name, password } = req.body ?? {};
    
    // Check if user exists
    const existing = await db.users.findOne({ email });
    if (existing) {
      return res.status(409).json({ error: 'User already exists' });
    }
    
    // Hash password
    const hashedPassword = await bcrypt.hash(password, 10);
    
    // Create user
    const user = await db.users.create({
      email,
      name,
      password: hashedPassword,
      createdAt: new Date()
    });
    
    // Don't return password
    const userWithoutPassword = { id: user.id, email: user.email, name: user.name };
    
    res.status(201).json({
      success: true,
      data: userWithoutPassword
    });
    
  } catch (error) {
    console.error('Create user error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
};

Best Practices

HTTP Status Codes
  • 200 - Success (GET, PUT, PATCH)
  • 201 - Created (POST)
  • 204 - No Content (DELETE)
  • 400 - Bad Request (validation failed)
  • 401 - Unauthorized (not authenticated)
  • 403 - Forbidden (not authorized)
  • 404 - Not Found
  • 409 - Conflict (duplicate)
  • 500 - Internal Server Error
Response Format

Consistent structure:

// Success
{
  "success": true,
  "data": { ... }
}

// Error
{
  "error": "Error message",
  "details": { ... } // optional
}

// List with pagination
{
  "success": true,
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 100
  }
}
Security Checklist
  • Authentication required for protected routes
  • Authorization checks (user owns resource)
  • Input validation on all fields
  • SQL injection prevention (use parameterized queries)
  • Rate limiting on public endpoints
  • No sensitive data in responses (passwords, tokens)
  • CORS configured properly
  • Request size limits set
Error Handling
// Centralized error handler
app.use((err, req, res, next) => {
  console.error(err.stack);
  
  // Don't leak error details in production
  const message = process.env.NODE_ENV === 'production' 
    ? 'Internal server error' 
    : err.message;
  
  res.status(err.status || 500).json({ error: message });
});

Common Patterns

CRUD Operations
// Create
POST /api/resources
Body: { name, description }

// Read (list)
GET /api/resources?page=1&limit=20

// Read (single)
GET /api/resources/:id

// Update
PUT /api/resources/:id
Body: { name, description }

// Delete
DELETE /api/resources/:id
Pagination
const getResources = async (req, res) => {
  const page = Number(req.query.page ?? 1);
  const limit = Number(req.query.limit ?? 20);
  if (!Number.isSafeInteger(page) || page < 1 || !Number.isSafeInteger(limit) || limit < 1 || limit > 100 || (page - 1) * limit > 100000) {
    return res.status(400).json({ error: "Invalid pagination" });
  }
  const skip = (page - 1) * limit;
  
  const [resources, total] = await Promise.all([
    db.resources.find().skip(skip).limit(limit),
    db.resources.countDocuments()
  ]);
  
  res.json({
    success: true,
    data: resources,
    pagination: {
      page,
      limit,
      total,
      pages: Math.ceil(total / limit)
    }
  });
};
Filtering & Sorting
const getResources = async (req, res) => {
  const { status, sort = '-createdAt' } = req.query;
  
  const filter = {};
  if (status && !["active", "inactive"].includes(status)) return res.status(400).json({ error: "Invalid status" });
  if (!["createdAt", "-createdAt", "name", "-name"].includes(sort)) return res.status(400).json({ error: "Invalid sort" });
  if (status) filter.status = status;
  
  const resources = await db.resources
    .find(filter)
    .sort(sort)
    .limit(20);
  
  res.json({ success: true, data: resources });
};

Documentation Template

/**
 * @route POST /api/users
 * @desc Create a new user
 * @access Public
 * 
 * @body {string} email - User email (required)
 * @body {string} name - User name (required)
 * @body {string} password - Password, min 8 chars (required)
 * 
 * @returns {201} User created successfully
 * @returns {400} Validation error
 * @returns {409} User already exists
 * @returns {500} Server error
 * 
 * @example
 * POST /api/users
 * {
 *   "email": "[email protected]",
 *   "name": "John Doe",
 *   "password": "securepass123"
 * }
 */

Testing Example

describe('POST /api/users', () => {
  it('should create a new user', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({
        email: '[email protected]',
        name: 'Test User',
        password: 'password123'
      });
    
    expect(response.status).toBe(201);
    expect(response.body.success).toBe(true);
    expect(response.body.data.email).toBe('[email protected]');
    expect(response.body.data.password).toBeUndefined();
  });
  
  it('should reject invalid email', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({
        email: 'invalid',
        name: 'Test User',
        password: 'password123'
      });
    
    expect(response.status).toBe(400);
    expect(response.body.error).toContain('email');
  });
});

Key Principles

  • Validate all inputs before processing
  • Use proper HTTP status codes
  • Handle errors gracefully
  • Never expose sensitive data
  • Keep responses consistent
  • Add authentication where needed
  • Document your endpoints
  • Write tests for critical paths

Related Skills

  • @security-auditor - Security review
  • @test-driven-development - Testing
  • @database-design - Data modeling

Limitations

  • Use this skill only when the task clearly matches the scope described above.
  • Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
  • Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.

These fragments require the actual database/models, auth middleware and application setup. Use schema validation for email/password length and byte limits rather than the illustrative @ check alone. Enforce normalized-email uniqueness in the database and map duplicate-key races to 409; prechecking is insufficient. Apply authenticated tenant/resource filters to both rows and count queries, allowlist response fields and sort/filter inputs, and sanitize error logging. Test non-string bodies, authorization and concurrent duplicates before production.

Comments

Markdown supported