Communitygithub.com

api-design

Padrões de design de API REST, incluindo nomenclatura de recursos, códigos de status, paginação, filtragem, respostas de erro, versionamento e limitação de taxa para APIs de produção. Use ao projetar ou revisar endpoints REST, nomes de recursos, códigos de status, paginação ou versionamento.

O que é api-design?

Esta skill fornece um guia abrangente de padrões e melhores práticas para projetar APIs REST consistentes e amigáveis para desenvolvedores. Ela cobre desde a nomenclatura de recursos (substantivos no plural, kebab-case) e a semântica de métodos HTTP (GET, POST, PUT, PATCH, DELETE) com seus respectivos códigos de status, até padrões de resposta padronizados para sucesso, coleções paginadas e erros detalhados. Além disso, a skill aborda estratégias de paginação (baseada em offset vs. cursor), filtragem, ordenação e busca, autenticação via token ou chave de API, limitação de taxa com cabeçalhos e tiers, e versionamento de API (recomendando versionamento por caminho na URL). Por fim, inclui exemplos de implementação em TypeScript (Next.js), Python (Django REST Framework) e Go (net/http), além de uma checklist prática para garantir que novos endpoints estejam em conformidade com as boas práticas. É útil para qualquer desenvolvedor ou engenheiro de software que esteja projetando, revisando ou implementando APIs REST, seja para sistemas internos, parceiros ou públicos.

Funciona com~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/api-design

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Padrões de Design de API

Convenções e melhores práticas para projetar APIs REST consistentes e amigáveis para desenvolvedores.

Quando Ativar

  • Projetando novos endpoints de API
  • Revisando contratos de API existentes
  • Adicionando paginação, filtragem ou ordenação
  • Implementando tratamento de erros para APIs
  • Planejando estratégia de versionamento de API
  • Construindo APIs públicas ou voltadas para parceiros

Design de Recursos

Estrutura de URL

# Recursos são substantivos, no plural, minúsculos, com hífen
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 relacionamentos
GET    /api/v1/users/:id/orders
POST   /api/v1/users/:id/orders

# Ações que não mapeiam para CRUD (use verbos com moderação)
POST   /api/v1/orders/:id/cancel
POST   /api/v1/auth/login
POST   /api/v1/auth/refresh

Regras de Nomenclatura

# BOM
/api/v1/team-members          # kebab-case para recursos com várias palavras
/api/v1/orders?status=active  # parâmetros de consulta para filtragem
/api/v1/users/123/orders      # recursos aninhados para propriedade

# RUIM
/api/v1/getUsers              # verbo na URL
/api/v1/user                  # singular (use plural)
/api/v1/team_members          # snake_case em URLs
/api/v1/users/123/getOrders   # verbo em recurso aninhado

Métodos HTTP e Códigos de Status

Semântica dos Métodos

MétodoIdempotenteSeguroUso
GETSimSimRecuperar recursos
POSTNãoNãoCriar recursos, acionar ações
PUTSimNãoSubstituição completa de um recurso
PATCHNão*NãoAtualização parcial de um recurso
DELETESimNãoRemover um recurso

*PATCH pode ser tornado idempotente com implementação adequada

Referência de Códigos de Status

# Sucesso
200 OK                    — GET, PUT, PATCH (com corpo de resposta)
201 Created               — POST (incluir cabeçalho Location)
204 No Content            — DELETE, PUT (sem corpo de resposta)

# Erros do Cliente
400 Bad Request           — Falha de validação, JSON malformado
401 Unauthorized          — Autenticação ausente ou inválida
403 Forbidden             — Autenticado mas não autorizado
404 Not Found             — Recurso não existe
409 Conflict              — Entrada duplicada, conflito de estado
422 Unprocessable Entity  — Semanticamente inválido (JSON válido, dados ruins)
429 Too Many Requests     — Limite de taxa excedido

# Erros do Servidor
500 Internal Server Error — Falha inesperada (nunca exponha detalhes)
502 Bad Gateway           — Serviço upstream falhou
503 Service Unavailable   — Sobrecarga temporária, incluir Retry-After

Erros Comuns

# RUIM: 200 para tudo
{ "status": 200, "success": false, "error": "Não encontrado" }

# BOM: Use códigos de status HTTP semanticamente
HTTP/1.1 404 Not Found
{ "error": { "code": "not_found", "message": "Usuário não encontrado" } }

# RUIM: 500 para erros de validação
# BOM: 400 ou 422 com detalhes em nível de campo

# RUIM: 200 para recursos criados
# BOM: 201 com cabeçalho Location
HTTP/1.1 201 Created
Location: /api/v1/users/abc-123

Formato de Resposta

Resposta de Sucesso

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

Resposta de Coleção (com Paginação)

{
  "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"
  }
}

Resposta de Erro

{
  "error": {
    "code": "validation_error",
    "message": "Falha na validação da requisição",
    "details": [
      {
        "field": "email",
        "message": "Deve ser um endereço de email válido",
        "code": "invalid_format"
      },
      {
        "field": "age",
        "message": "Deve estar entre 0 e 150",
        "code": "out_of_range"
      }
    ]
  }
}

Variantes de Invólucro de Resposta

// Opção A: Invólucro com wrapper de dados (recomendado para APIs públicas)
interface ApiResponse<T> {
  data: T;
  meta?: PaginationMeta;
  links?: PaginationLinks;
}

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

// Opção B: Resposta plana (mais simples, comum para APIs internas)
// Sucesso: apenas retorne o recurso diretamente
// Erro: retorne o objeto de erro
// Distinguir pelo código de status HTTP

Paginação

Baseada em Offset (Simples)

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

# Implementação
SELECT * FROM users
ORDER BY created_at DESC
LIMIT 20 OFFSET 20;

Prós: Fácil de implementar, suporta "pular para a página N" Contras: Lento em grandes offsets (OFFSET 100000), inconsistente com inserções simultâneas

Baseada em Cursor (Escalável)

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

# Implementação
SELECT * FROM users
WHERE id > :cursor_id
ORDER BY id ASC
LIMIT 21;  -- buscar um extra para determinar has_next
{
  "data": [...],
  "meta": {
    "has_next": true,
    "next_cursor": "eyJpZCI6MTQzfQ"
  }
}

Prós: Desempenho consistente independentemente da posição, estável com inserções simultâneas Contras: Não é possível pular para uma página arbitrária, cursor é opaco

Quando Usar Qual

Caso de UsoTipo de Paginação
Painéis administrativos, conjuntos de dados pequenos (<10K)Offset
Rolagem infinita, feeds, conjuntos de dados grandesCursor
APIs públicasCursor (padrão) com offset (opcional)
Resultados de pesquisaOffset (usuários esperam números de página)

Filtragem, Ordenação e Pesquisa

Filtragem

# Igualdade simples
GET /api/v1/orders?status=active&customer_id=abc-123

# Operadores de comparação (use notação de colchetes)
GET /api/v1/products?price[gte]=10&price[lte]=100
GET /api/v1/orders?created_at[after]=2025-01-01

# Múltiplos valores (separados por vírgula)
GET /api/v1/products?category=electronics,clothing

# Campos aninhados (notação de ponto)
GET /api/v1/orders?customer.country=US

Ordenação

# Campo único (prefixo - para descendente)
GET /api/v1/products?sort=-created_at

# Múltiplos campos (separados por vírgula)
GET /api/v1/products?sort=-featured,price,-created_at

Pesquisa de Texto Completo

# Parâmetro de consulta de pesquisa
GET /api/v1/products?q=wireless+headphones

# Pesquisa específica de campo
GET /api/v1/users?email=alice

Conjuntos de Campos Esparsos

# Retorna apenas os campos especificados (reduz o payload)
GET /api/v1/users?fields=id,name,email
GET /api/v1/orders?fields=id,total,status&include=customer.name

Autenticação e Autorização

Autenticação Baseada em Token

# Token Bearer no cabeçalho Authorization
GET /api/v1/users
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

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

Padrões de Autorização

// Nível de recurso: verificar propriedade
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 });
});

// Baseado em função: verificar permissões
app.delete("/api/v1/users/:id", requireRole("admin"), async (req, res) => {
  await User.delete(req.params.id);
  return res.status(204).send();
});

Limitação de Taxa

Cabeçalhos

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

# Quando excedido
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Limite de taxa excedido. Tente novamente em 60 segundos."
  }
}

Níveis de Limitação de Taxa

NívelLimiteJanelaCaso de Uso
Anônimo30/minPor IPEndpoints públicos
Autenticado100/minPor usuárioAcesso padrão à API
Premium1000/minPor chave de APIPlanos de API pagos
Interno10000/minPor serviçoServiço-para-serviço

Versionamento

Versionamento por Caminho de URL (Recomendado)

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

Prós: Explícito, fácil de rotear, armazenável em cache Contras: URL muda entre versões

Versionamento por Cabeçalho

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

Prós: URLs limpas Contras: Mais difícil de testar, fácil de esquecer

Estratégia de Versionamento

1. Comece com /api/v1/ — não version até precisar
2. Mantenha no máximo 2 versões ativas (atual + anterior)
3. Cronograma de descontinuação:
   - Anuncie a descontinuação (aviso de 6 meses para APIs públicas)
   - Adicione o cabeçalho Sunset: Sunset: Sat, 01 Jan 2026 00:00:00 GMT
   - Retorne 410 Gone após a data de descontinuação
4. Mudanças não críticas não precisam de nova versão:
   - Adicionar novos campos às respostas
   - Adicionar novos parâmetros de consulta opcionais
   - Adicionar novos endpoints
5. Mudanças críticas exigem uma nova versão:
   - Remover ou renomear campos
   - Alterar tipos de campo
   - Alterar estrutura de URL
   - Alterar método de autenticação

Padrões de Implementação

TypeScript (Next.js Route de API)

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: "Falha na validação da requisição",
        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", "Corpo da requisição 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", "Email já registrado")
        default:
            writeError(w, http.StatusInternalServerError, "internal_error", "Erro interno")
        }
        return
    }

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

Checklist de Design de API

Antes de enviar um novo endpoint:

  • URL do recurso segue as convenções de nomenclatura (plural, kebab-case, sem verbos)
  • Método HTTP correto usado (GET para leituras, POST para criações, etc.)
  • Códigos de status apropriados retornados (não 200 para tudo)
  • Entrada validada com esquema (Zod, Pydantic, Bean Validation)
  • Respostas de erro seguem formato padrão com códigos e mensagens
  • Paginação implementada para endpoints de lista (cursor ou offset)
  • Autenticação exigida (ou explicitamente marcada como pública)
  • Autorização verificada (usuário pode acessar apenas seus próprios recursos)
  • Limitação de taxa configurada
  • Resposta não vaza detalhes internos (stack traces, erros SQL)
  • Nomenclatura consistente com endpoints existentes (camelCase vs snake_case)
  • Documentado (especificação OpenAPI/Swagger atualizada)

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.

Habilidades Relacionadas