Communitygithub.com

diseño-de-api

Patrones de diseño para APIs REST, incluyendo nombres de recursos, códigos de estado, paginación, filtrado, respuestas de error, versionado y limitación de velocidad para APIs en producción. Úsalo al diseñar o revisar endpoints REST, nombres de recursos, códigos de estado, paginación o versionado.

¿Qué es diseño-de-api?

Este skill proporciona una guía completa y práctica para diseñar APIs REST consistentes y amigables para desarrolladores. Cubre todos los aspectos esenciales: desde la estructura de URLs y nomenclatura de recursos (plural, kebab-case, sin verbos) hasta la semántica correcta de métodos HTTP y códigos de estado. Incluye patrones detallados para paginación (basada en offset y cursor), filtrado, ordenación y búsqueda de texto completo, con ejemplos claros de implementación en TypeScript, Python (Django REST Framework) y Go. Además, aborda la autenticación y autorización, el limitado de velocidad con diferentes niveles, estrategias de versionado (URL path vs. header) y un formato estándar para respuestas exitosas, de colección y de error. Incluye una lista de verificación previa al lanzamiento para garantizar que los endpoints cumplan con las mejores prácticas. Es compatible con cualquier plataforma que desarrolle APIs REST, como Claude Code, Cursor o Codex. El skill se activa al diseñar nuevos endpoints, revisar contratos existentes, agregar paginación o manejo de errores, y al planificar estrategias de versionado.

Compatible con~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/affaan-m/ECC/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 APIs REST consistentes y amigables para desarrolladores.

Cuándo Activar

  • Al diseñar nuevos endpoints de API
  • Al revisar contratos de API existentes
  • Al agregar paginación, filtrado u ordenación
  • Al implementar manejo de errores para APIs
  • Al planificar una estrategia de versionado de API
  • Al construir APIs 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

# Sub-recursos para relaciones
GET    /api/v1/users/:id/orders
POST   /api/v1/users/:id/orders

# Acciones que no corresponden 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 múltiples palabras
/api/v1/orders?status=active  # parámetros de consulta para filtrado
/api/v1/users/123/orders      # recursos anidados para propiedad

# MAL
/api/v1/getUsers              # verbo en la URL
/api/v1/user                  # singular (usar 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 se puede hacer 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 velocidad excedido

# Errores del Servidor
500 Internal Server Error — Fallo inesperado (nunca exponer detalles)
502 Bad Gateway           — El servicio ascendente 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 envoltorio de datos (recomendado para APIs 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 APIs 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, soporta "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 adicional 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 Cuál

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

Filtrado, Ordenación 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

Ordenación

# Campo único (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=auriculares+inalámbricos

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

Conjuntos de Campos Dispersos

# 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...

# API key (para comunicación 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 });
});

// Basado 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();
});

Limitación de Velocidad

Cabeceras

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

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

Niveles de Límite de Velocidad

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

Versionado

Versionado por Ruta de 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. Comienza con /api/v1/ — no versiones hasta que sea necesario
2. Mantén como máximo 2 versiones activas (actual + anterior)
3. Cronograma de desaprobación:
   - Anunciar la desaprobación (aviso de 6 meses para APIs públicas)
   - Agregar 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 rupturistas no requieren una nueva versión:
   - Agregar nuevos campos a las respuestas
   - Agregar nuevos parámetros de consulta opcionales
   - Agregar nuevos endpoints
5. Los cambios rupturistas requieren una nueva versión:
   - Eliminar o renombrar campos
   - Cambiar tipos de campo
   - Cambiar la estructura de la 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 no vá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 un 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)
  • Limitación de velocidad configurada
  • La respuesta no filtra detalles internos (trazas de pila, errores SQL)
  • Nomenclatura coherente 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/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

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.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

Skills relacionados