Communitygithub.com

api-design

Patrones de diseño de API REST que incluyen nomenclatura de recursos, códigos de estado, paginación, filtrado, respuestas de error, versionado y límites de tasa para API de producción. Úselo al diseñar o revisar endpoints REST, nombres de recursos, códigos de estado, paginación o versionado.

¿Qué es api-design?

Esta habilidad proporciona una guía completa de patrones de diseño para construir API REST consistentes y amigables para desarrolladores. Cubre todas las etapas del ciclo de vida de una API: desde la nomenclatura de recursos (sustantivos en plural, kebab-case) y la selección correcta de métodos HTTP (GET, POST, PUT, PATCH, DELETE) hasta el uso semántico de códigos de estado (200, 201, 204, 400, 401, 404, 409, 422, 429, 500, etc.). Incluye formatos de respuesta estandarizados (éxito, colección paginada, error con detalles de campo), estrategias de paginación (basada en desplazamiento vs cursor) y filtrado con operadores de comparación. También aborda autenticación (Bearer token, API Key), autorización basada en roles, límites de tasa con cabeceras estándar y estrategias de versionado (recomendando versionado en la ruta URL). Incluye ejemplos de implementación en TypeScript (Next.js), Python (Django REST Framework) y Go (net/http), así como una checklist para asegurar endpoints de calidad antes del despliegue.

Compatible con~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/api-design

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Patrones de Diseño de API

Convenciones y mejores prácticas para diseñar API REST consistentes y amigables para desarrolladores.

Cuándo Activar

  • Diseñar nuevos endpoints de API
  • Revisar contratos de API existentes
  • Añadir paginación, filtrado o ordenamiento
  • Implementar manejo de errores para API
  • Planificar estrategia de versionado de API
  • Construir API públicas o para socios

Diseño de Recursos

Estructura de URL

# Los recursos son sustantivos, en plural, minúsculas y con kebab-case
GET    /api/v1/users
GET    /api/v1/users/:id
POST   /api/v1/users
PUT    /api/v1/users/:id
PATCH  /api/v1/users/:id
DELETE /api/v1/users/:id

# Subrecursos para relaciones
GET    /api/v1/users/:id/orders
POST   /api/v1/users/:id/orders

# Acciones que no se asignan a CRUD (usar verbos con moderación)
POST   /api/v1/orders/:id/cancel
POST   /api/v1/auth/login
POST   /api/v1/auth/refresh

Reglas de Nomenclatura

# BIEN
/api/v1/team-members          # kebab-case para recursos de varias palabras
/api/v1/orders?status=active  # parámetros de consulta para filtrado
/api/v1/users/123/orders      # recursos anidados para relaciones de propiedad

# MAL
/api/v1/getUsers              # verbo en la URL
/api/v1/user                  # singular (use plural)
/api/v1/team_members          # snake_case en URLs
/api/v1/users/123/getOrders   # verbo en recurso anidado

Métodos HTTP y Códigos de Estado

Semántica de Métodos

MétodoIdempotenteSeguroUso
GETSíSíRecuperar recursos
POSTNoNoCrear recursos, desencadenar acciones
PUTSíNoReemplazo completo de un recurso
PATCHNo*NoActualización parcial de un recurso
DELETESíNoEliminar un recurso

*PATCH puede hacerse idempotente con una implementación adecuada

Referencia de Códigos de Estado

# Éxito
200 OK                    — GET, PUT, PATCH (con cuerpo de respuesta)
201 Created               — POST (incluir cabecera Location)
204 No Content            — DELETE, PUT (sin cuerpo de respuesta)

# Errores del Cliente
400 Bad Request           — Error de validación, JSON mal formado
401 Unauthorized          — Autenticación faltante o inválida
403 Forbidden             — Autenticado pero no autorizado
404 Not Found             — El recurso no existe
409 Conflict              — Entrada duplicada, conflicto de estado
422 Unprocessable Entity  — Semánticamente inválido (JSON válido, datos incorrectos)
429 Too Many Requests     — Límite de tasa excedido

# Errores del Servidor
500 Internal Server Error — Fallo inesperado (nunca exponer detalles)
502 Bad Gateway           — El servicio upstream falló
503 Service Unavailable   — Sobrecarga temporal, incluir Retry-After

Errores Comunes

# MAL: 200 para todo
{ "status": 200, "success": false, "error": "No encontrado" }

# BIEN: Usar códigos de estado HTTP semánticamente
HTTP/1.1 404 Not Found
{ "error": { "code": "not_found", "message": "Usuario no encontrado" } }

# MAL: 500 para errores de validación
# BIEN: 400 o 422 con detalles a nivel de campo

# MAL: 200 para recursos creados
# BIEN: 201 con cabecera Location
HTTP/1.1 201 Created
Location: /api/v1/users/abc-123

Formato de Respuesta

Respuesta Exitosa

{
  "data": {
    "id": "abc-123",
    "email": "[email protected]",
    "name": "Alice",
    "created_at": "2025-01-15T10:30:00Z"
  }
}

Respuesta de Colección (con Paginación)

{
  "data": [
    { "id": "abc-123", "name": "Alice" },
    { "id": "def-456", "name": "Bob" }
  ],
  "meta": {
    "total": 142,
    "page": 1,
    "per_page": 20,
    "total_pages": 8
  },
  "links": {
    "self": "/api/v1/users?page=1&per_page=20",
    "next": "/api/v1/users?page=2&per_page=20",
    "last": "/api/v1/users?page=8&per_page=20"
  }
}

Respuesta de Error

{
  "error": {
    "code": "validation_error",
    "message": "La validación de la solicitud falló",
    "details": [
      {
        "field": "email",
        "message": "Debe ser una dirección de correo electrónico válida",
        "code": "invalid_format"
      },
      {
        "field": "age",
        "message": "Debe estar entre 0 y 150",
        "code": "out_of_range"
      }
    ]
  }
}

Variantes de Envoltura de Respuesta

// Opción A: Envoltura con contenedor de datos (recomendada para API públicas)
interface ApiResponse<T> {
  data: T;
  meta?: PaginationMeta;
  links?: PaginationLinks;
}

interface ApiError {
  error: {
    code: string;
    message: string;
    details?: FieldError[];
  };
}

// Opción B: Respuesta plana (más simple, común para API internas)
// Éxito: devolver el recurso directamente
// Error: devolver objeto de error
// Distinguir por código de estado HTTP

Paginación

Basada en Desplazamiento (Simple)

GET /api/v1/users?page=2&per_page=20

# Implementación
SELECT * FROM users
ORDER BY created_at DESC
LIMIT 20 OFFSET 20;

Ventajas: Fácil de implementar, admite "saltar a la página N" Desventajas: Lento en desplazamientos grandes (OFFSET 100000), inconsistente con inserciones concurrentes

Basada en Cursor (Escalable)

GET /api/v1/users?cursor=eyJpZCI6MTIzfQ&limit=20

# Implementación
SELECT * FROM users
WHERE id > :cursor_id
ORDER BY id ASC
LIMIT 21;  -- obtener uno extra para determinar has_next
{
  "data": [...],
  "meta": {
    "has_next": true,
    "next_cursor": "eyJpZCI6MTQzfQ"
  }
}

Ventajas: Rendimiento consistente independientemente de la posición, estable con inserciones concurrentes Desventajas: No se puede saltar a una página arbitraria, el cursor es opaco

Cuándo Usar Cada Una

Caso de UsoTipo de Paginación
Paneles de administración, conjuntos de datos pequeños (<10K)Desplazamiento
Desplazamiento infinito, feeds, conjuntos de datos grandesCursor
API públicasCursor (predeterminado) con desplazamiento (opcional)
Resultados de búsquedaDesplazamiento (los usuarios esperan números de página)

Filtrado, Ordenamiento y Búsqueda

Filtrado

# Igualdad simple
GET /api/v1/orders?status=active&customer_id=abc-123

# Operadores de comparación (usar notación de corchetes)
GET /api/v1/products?price[gte]=10&price[lte]=100
GET /api/v1/orders?created_at[after]=2025-01-01

# Múltiples valores (separados por comas)
GET /api/v1/products?category=electronics,clothing

# Campos anidados (notación de puntos)
GET /api/v1/orders?customer.country=US

Ordenamiento

# Un solo campo (prefijo - para descendente)
GET /api/v1/products?sort=-created_at

# Múltiples campos (separados por comas)
GET /api/v1/products?sort=-featured,price,-created_at

Búsqueda de Texto Completo

# Parámetro de consulta de búsqueda
GET /api/v1/products?q=wireless+headphones

# Búsqueda por campo específico
GET /api/v1/users?email=alice

Conjuntos de Campos Escasos

# Devolver solo los campos especificados (reduce el payload)
GET /api/v1/users?fields=id,name,email
GET /api/v1/orders?fields=id,total,status&include=customer.name

Autenticación y Autorización

Autenticación Basada en Token

# Token Bearer en la cabecera Authorization
GET /api/v1/users
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

# Clave API (para servidor a servidor)
GET /api/v1/data
X-API-Key: sk_live_abc123

Patrones de Autorización

// A nivel de recurso: verificar propiedad
app.get("/api/v1/orders/:id", async (req, res) => {
  const order = await Order.findById(req.params.id);
  if (!order) return res.status(404).json({ error: { code: "not_found" } });
  if (order.userId !== req.user.id) return res.status(403).json({ error: { code: "forbidden" } });
  return res.json({ data: order });
});

// Basada en roles: verificar permisos
app.delete("/api/v1/users/:id", requireRole("admin"), async (req, res) => {
  await User.delete(req.params.id);
  return res.status(204).send();
});

Límites de Tasa

Cabeceras

HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640000000

# Cuando se excede
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Límite de tasa excedido. Intente de nuevo en 60 segundos."
  }
}

Niveles de Límite de Tasa

NivelLímiteVentanaCaso de Uso
Anónimo30/minPor IPEndpoints públicos
Autenticado100/minPor usuarioAcceso API estándar
Premium1000/minPor clave APIPlanes de API de pago
Interno10000/minPor servicioComunicación entre servicios

Versionado

Versionado por Ruta URL (Recomendado)

/api/v1/users
/api/v2/users

Ventajas: Explícito, fácil de enrutar, almacenable en caché Desventajas: La URL cambia entre versiones

Versionado por Cabecera

GET /api/users
Accept: application/vnd.myapp.v2+json

Ventajas: URLs limpias Desventajas: Más difícil de probar, fácil de olvidar

Estrategia de Versionado

1. Comience con /api/v1/ — no versiones hasta que sea necesario
2. Mantenga como máximo 2 versiones activas (actual + anterior)
3. Cronograma de desaprobación:
   - Anunciar desaprobación (6 meses de aviso para API públicas)
   - Añadir cabecera Sunset: Sunset: Sat, 01 Jan 2026 00:00:00 GMT
   - Devolver 410 Gone después de la fecha de desaprobación
4. Los cambios no disruptivos no requieren una nueva versión:
   - Añadir nuevos campos a las respuestas
   - Añadir nuevos parámetros de consulta opcionales
   - Añadir nuevos endpoints
5. Los cambios disruptivos requieren una nueva versión:
   - Eliminar o renombrar campos
   - Cambiar tipos de campo
   - Cambiar la estructura de URL
   - Cambiar el método de autenticación

Patrones de Implementación

TypeScript (Ruta de API de Next.js)

import { z } from "zod";
import { NextRequest, NextResponse } from "next/server";

const createUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1).max(100),
});

export async function POST(req: NextRequest) {
  const body = await req.json();
  const parsed = createUserSchema.safeParse(body);

  if (!parsed.success) {
    return NextResponse.json({
      error: {
        code: "validation_error",
        message: "La validación de la solicitud falló",
        details: parsed.error.issues.map(i => ({
          field: i.path.join("."),
          message: i.message,
          code: i.code,
        })),
      },
    }, { status: 422 });
  }

  const user = await createUser(parsed.data);

  return NextResponse.json(
    { data: user },
    {
      status: 201,
      headers: { Location: `/api/v1/users/${user.id}` },
    },
  );
}

Python (Django REST Framework)

from rest_framework import serializers, viewsets, status
from rest_framework.response import Response

class CreateUserSerializer(serializers.Serializer):
    email = serializers.EmailField()
    name = serializers.CharField(max_length=100)

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["id", "email", "name", "created_at"]

class UserViewSet(viewsets.ModelViewSet):
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticated]

    def get_serializer_class(self):
        if self.action == "create":
            return CreateUserSerializer
        return UserSerializer

    def create(self, request):
        serializer = CreateUserSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = UserService.create(**serializer.validated_data)
        return Response(
            {"data": UserSerializer(user).data},
            status=status.HTTP_201_CREATED,
            headers={"Location": f"/api/v1/users/{user.id}"},
        )

Go (net/http)

func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
    var req CreateUserRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        writeError(w, http.StatusBadRequest, "invalid_json", "Cuerpo de solicitud inválido")
        return
    }

    if err := req.Validate(); err != nil {
        writeError(w, http.StatusUnprocessableEntity, "validation_error", err.Error())
        return
    }

    user, err := h.service.Create(r.Context(), req)
    if err != nil {
        switch {
        case errors.Is(err, domain.ErrEmailTaken):
            writeError(w, http.StatusConflict, "email_taken", "El correo electrónico ya está registrado")
        default:
            writeError(w, http.StatusInternalServerError, "internal_error", "Error interno")
        }
        return
    }

    w.Header().Set("Location", fmt.Sprintf("/api/v1/users/%s", user.ID))
    writeJSON(w, http.StatusCreated, map[string]any{"data": user})
}

Lista de Verificación de Diseño de API

Antes de enviar un nuevo endpoint:

  • La URL del recurso sigue las convenciones de nomenclatura (plural, kebab-case, sin verbos)
  • Se utiliza el método HTTP correcto (GET para lecturas, POST para creaciones, etc.)
  • Se devuelven códigos de estado apropiados (no 200 para todo)
  • Entrada validada con esquema (Zod, Pydantic, Bean Validation)
  • Las respuestas de error siguen el formato estándar con códigos y mensajes
  • Paginación implementada para endpoints de lista (cursor o desplazamiento)
  • Autenticación requerida (o marcada explícitamente como pública)
  • Autorización verificada (el usuario solo puede acceder a sus propios recursos)
  • Límites de tasa configurados
  • La respuesta no filtra detalles internos (trazas de pila, errores de SQL)
  • Nomenclatura consistente con los endpoints existentes (camelCase vs snake_case)
  • Documentado (especificación OpenAPI/Swagger actualizada)

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Skills relacionados