Files
gh-igpastor-sng-claude-mark…/commands/sng-endpoint.md
2025-11-29 18:47:58 +08:00

7.1 KiB

Create API Endpoint Command

You are helping the user create a new API endpoint following Sngular's backend development best practices.

Instructions

  1. Detect the backend framework:

    • Node.js with Express
    • Node.js with Fastify
    • NestJS
    • Python with FastAPI
    • Python with Flask/Django
    • Go with Gin/Echo
    • Other framework
  2. Ask for endpoint details:

    • HTTP method (GET, POST, PUT, PATCH, DELETE)
    • Route path (e.g., /api/users, /api/posts/:id)
    • Purpose and description
    • Request body schema (if applicable)
    • Response schema
    • Authentication required (yes/no)
    • Rate limiting needed (yes/no)
  3. Determine API style:

    • REST API
    • GraphQL (query/mutation/subscription)
    • gRPC
    • WebSocket

Implementation Tasks

For REST Endpoints:

  1. Create route handler with:

    • HTTP method and path
    • Request validation middleware
    • Business logic / controller method
    • Response formatting
    • Error handling
  2. Add request validation:

    • Query parameters validation
    • Path parameters validation
    • Request body validation (using Zod, Joi, class-validator)
    • File upload validation (if needed)
  3. Implement authentication/authorization:

    • JWT token verification
    • Role-based access control (RBAC)
    • Permission checks
    • API key validation
  4. Add error handling:

    • Try-catch blocks
    • Custom error classes
    • HTTP status codes
    • Error response formatting
  5. Create tests:

    • Unit tests for controller logic
    • Integration tests for full endpoint
    • Mock database/external services
    • Test authentication flows
  6. Add documentation:

    • OpenAPI/Swagger annotations
    • JSDoc/docstrings
    • Request/response examples
    • Error codes documentation

For GraphQL:

  1. Define schema:

    • Type definitions
    • Input types
    • Custom scalars
  2. Create resolver:

    • Query/Mutation/Subscription resolver
    • Field resolvers
    • DataLoader for N+1 prevention
  3. Add validation & auth:

    • Schema directives
    • Resolver-level authorization
    • Input validation

Files to Create/Update

  1. Route/Controller file: Define the endpoint handler
  2. Validation schema: Request/response validation
  3. Service layer: Business logic (separate from controller)
  4. Tests: Comprehensive endpoint testing
  5. Types/Interfaces: TypeScript types or Pydantic models
  6. Documentation: API docs/Swagger definitions

Best Practices to Follow

Code Structure

src/
├── routes/
│   └── users.routes.ts         # Route definitions
├── controllers/
│   └── users.controller.ts     # Request handlers
├── services/
│   └── users.service.ts        # Business logic
├── validators/
│   └── users.validator.ts      # Input validation
├── types/
│   └── users.types.ts          # TypeScript types
└── tests/
    └── users.test.ts           # Endpoint tests

Request Validation

import { z } from 'zod'

const CreateUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(2).max(100),
  age: z.number().int().positive().optional(),
})

Error Handling

// Custom error classes
class BadRequestError extends Error {
  statusCode = 400
}

class UnauthorizedError extends Error {
  statusCode = 401
}

// Error handling middleware
app.use((err, req, res, next) => {
  res.status(err.statusCode || 500).json({
    error: {
      message: err.message,
      code: err.code,
    },
  })
})

Authentication

// JWT middleware
const authMiddleware = async (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1]

  if (!token) {
    throw new UnauthorizedError('No token provided')
  }

  const decoded = jwt.verify(token, process.env.JWT_SECRET)
  req.user = decoded

  next()
}

Rate Limiting

import rateLimit from 'express-rate-limit'

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
})

app.use('/api/', limiter)

Response Formatting

// Success response
res.status(200).json({
  success: true,
  data: result,
  meta: {
    page: 1,
    limit: 20,
    total: 100,
  },
})

// Error response
res.status(400).json({
  success: false,
  error: {
    code: 'VALIDATION_ERROR',
    message: 'Invalid email format',
    details: validationErrors,
  },
})

Database Operations

// Use transactions for multiple operations
await db.transaction(async (trx) => {
  const user = await trx('users').insert(userData)
  await trx('profiles').insert({ user_id: user.id, ...profileData })
})

Logging

import logger from './utils/logger'

app.post('/api/users', async (req, res) => {
  logger.info('Creating new user', { email: req.body.email })

  try {
    const user = await createUser(req.body)
    logger.info('User created successfully', { userId: user.id })
    res.status(201).json({ data: user })
  } catch (error) {
    logger.error('Failed to create user', { error, body: req.body })
    throw error
  }
})

Testing Example

import request from 'supertest'
import app from '../app'

describe('POST /api/users', () => {
  it('creates a new user with valid data', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({
        email: 'test@example.com',
        name: 'Test User',
      })
      .expect(201)

    expect(response.body.data).toHaveProperty('id')
    expect(response.body.data.email).toBe('test@example.com')
  })

  it('returns 400 for invalid email', async () => {
    await request(app)
      .post('/api/users')
      .send({
        email: 'invalid-email',
        name: 'Test User',
      })
      .expect(400)
  })

  it('requires authentication', async () => {
    await request(app)
      .post('/api/users')
      .send({ email: 'test@example.com' })
      .expect(401)
  })
})

OpenAPI/Swagger Documentation

/**
 * @swagger
 * /api/users:
 *   post:
 *     summary: Create a new user
 *     tags: [Users]
 *     security:
 *       - bearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - email
 *               - name
 *             properties:
 *               email:
 *                 type: string
 *                 format: email
 *               name:
 *                 type: string
 *     responses:
 *       201:
 *         description: User created successfully
 *       400:
 *         description: Invalid input
 *       401:
 *         description: Unauthorized
 */

Security Considerations

  • Always validate and sanitize input
  • Use parameterized queries to prevent SQL injection
  • Implement rate limiting
  • Use HTTPS in production
  • Never expose sensitive data in responses
  • Hash passwords with bcrypt
  • Implement CORS properly
  • Use security headers (helmet.js)
  • Validate JWT tokens properly
  • Implement proper session management

Ask the user: "What API endpoint would you like to create?"