Claude Code Plugins

Community-maintained marketplace

Feedback

Implementar routers e schemas da API em api/. Use quando criar endpoint, rota, schema de request/response, ou registrar router.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name impl-api
description Implementar routers e schemas da API em api/. Use quando criar endpoint, rota, schema de request/response, ou registrar router.
allowed-tools Read, Write, Edit, Glob, Grep

Implementar API (Camada de Routers e Schemas)

Regras Arquiteturais (NON-NEGOTIABLE)

  1. Router SÓ faz: request → service.method() → response
  2. SEM lógica de negócio em routers (validações, cálculos, etc.)
  3. SEM prompts de LLM em routers
  4. SEM acesso direto a banco de dados
  5. Service via getter: instanciar service em função getter com DI pattern
  6. Response models: sempre especificar response_model= nos endpoints
  7. Schemas separados: request/response em api/schemas/

Estrutura de Arquivos

src/synth_lab/api/
├── main.py                   # App FastAPI, lifespan, middleware
├── errors.py                 # Exception handlers
├── routers/
│   └── {entities}.py         # Um arquivo por recurso (plural)
└── schemas/
    └── {entity}.py           # Schemas por entidade

Convenções de nome:

  • Router: {entities}.py (plural: synths.py, experiments.py)
  • Schema: {entity}.py (singular)
  • Sufixos de schema:
    • Create - request de criação
    • Update - request de atualização
    • Summary - resposta resumida (listas)
    • Detail - resposta completa

Padrões de Código

Router

"""
{Entity} router for synth-lab API.

Endpoints for {entity} operations.
"""

from fastapi import APIRouter, HTTPException, Path, Query

from synth_lab.api.schemas.{entity} import (
    {Entity}Create,
    {Entity}Detail,
    {Entity}Summary,
)
from synth_lab.models.pagination import PaginatedResponse, PaginationParams
from synth_lab.services.{entity}_service import {Entity}Service


router = APIRouter()


def get_{entity}_service() -> {Entity}Service:
    """Get {entity} service instance (DI pattern)."""
    return {Entity}Service()


@router.get("/list", response_model=PaginatedResponse[{Entity}Summary])
async def list_{entities}(
    limit: int = Query(default=50, ge=1, le=200, description="Items per page"),
    offset: int = Query(default=0, ge=0, description="Items to skip"),
    sort_by: str | None = Query(default=None, description="Sort field"),
    sort_order: str = Query(default="desc", pattern="^(asc|desc)$"),
) -> PaginatedResponse[{Entity}Summary]:
    """List {entities} with pagination."""
    service = get_{entity}_service()
    params = PaginationParams(
        limit=limit,
        offset=offset,
        sort_by=sort_by,
        sort_order=sort_order,
    )
    return service.list_{entities}(params)


@router.get("/{{{entity}_id}}", response_model={Entity}Detail)
async def get_{entity}(
    {entity}_id: str = Path(..., description="{Entity} ID"),
) -> {Entity}Detail:
    """Get {entity} by ID."""
    service = get_{entity}_service()
    return service.get_{entity}({entity}_id)


@router.post("/", response_model={Entity}Detail, status_code=201)
async def create_{entity}(
    data: {Entity}Create,
) -> {Entity}Detail:
    """Create new {entity}."""
    service = get_{entity}_service()
    return service.create_{entity}(
        name=data.name,
        description=data.description,
    )


@router.delete("/{{{entity}_id}}", status_code=204)
async def delete_{entity}(
    {entity}_id: str = Path(..., description="{Entity} ID"),
) -> None:
    """Delete {entity} by ID."""
    service = get_{entity}_service()
    service.delete_{entity}({entity}_id)

Schemas

"""
{Entity} schemas for API request/response.
"""

from datetime import datetime

from pydantic import BaseModel, Field


class {Entity}Create(BaseModel):
    """Schema for creating a new {entity}."""

    name: str = Field(..., min_length=1, max_length=100, description="Name")
    description: str | None = Field(default=None, max_length=500)


class {Entity}Update(BaseModel):
    """Schema for updating an {entity}."""

    name: str | None = Field(default=None, min_length=1, max_length=100)
    description: str | None = Field(default=None, max_length=500)


class {Entity}Summary(BaseModel):
    """Summary for list responses."""

    id: str = Field(..., description="{Entity} ID")
    name: str = Field(..., description="Name")
    created_at: datetime = Field(..., description="Creation timestamp")


class {Entity}Detail({Entity}Summary):
    """Full details for single item responses."""

    description: str | None = Field(default=None)
    updated_at: datetime | None = Field(default=None)
    # Nested models
    metadata: dict | None = Field(default=None)

Registrar Router em main.py

# Em api/main.py

from synth_lab.api.routers import {entities}

# Registrar router
app.include_router(
    {entities}.router,
    prefix="/{entities}",
    tags=["{entities}"],
)

Exception Handlers (api/errors.py)

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

from synth_lab.services.errors import NotFoundError, ValidationError


def register_exception_handlers(app: FastAPI) -> None:
    """Register all exception handlers."""

    @app.exception_handler(NotFoundError)
    async def not_found_handler(request: Request, exc: NotFoundError):
        return JSONResponse(
            status_code=404,
            content={"error": {"code": exc.code, "message": exc.message}},
        )

    @app.exception_handler(ValidationError)
    async def validation_handler(request: Request, exc: ValidationError):
        return JSONResponse(
            status_code=422,
            content={"error": {"code": exc.code, "message": exc.message}},
        )

Checklist de Verificação

Antes de finalizar, verificar:

  • Router só faz request → service → response
  • SEM lógica de negócio no router
  • Service instanciado via getter function
  • response_model= em todos os endpoints
  • Schemas em arquivo separado (api/schemas/)
  • Schemas usam sufixos corretos (Create, Summary, Detail)
  • Query/Path validators com descriptions
  • Router registrado em main.py com prefix e tags
  • Exception handlers para erros de domínio
  • Docstrings em todos os endpoints