API linting y análisis estático
1) Por qué lintar la API
API - Contrato entre equipos e integradores externos. Linting y análisis estático:- previenen cambios incompatibles e implícitos;
- unificar estados, errores, paginación, seguridad;
- hacen que las especificaciones sean verificables por máquina y las liberaciones son predecibles;
- reducen el costo con rugidos y el tiempo de onboarding.
Principio: "Los contratos se verifican automáticamente; La PR sin linting verde no se detendrá".
2) Objetos de linting
1. Contratos: OpenAPI/AsyncAPI/GraphQL SDL, Protobuf/Avro/JSON Schema.
2. Implementación: PEN/gRPC, middleware, códigos de estado/encabezados.
3. Infraestructura: encabezados de seguridad, límites, políticas de caché.
4. Artefactos relacionados: ejemplos (ejemplos), colecciones de Postman, esquemas de errores.
3) Reglas básicas para la API HTTP (perfil recomendado)
3. 1 Notación y URL
snake_case en los cuerpos JSON, kebab-case en las vías o kebab-case/'/v1/... 'uniforme.
Los recursos son plurales: '/v1/payments ', anidados - '/v1/wallets/{ id }/transactions'.
Identificadores como path-params: '/v1/payments/{ payment _ id} '(tipo: string, formato: uuuid).
3. 2 Métodos y estados
'GET' - 200/206; 'POST' - 201 (+ 'Ubicación'), conflictos - 409; validación - 422; los límites son 429 (+ 'Retry-After').
No devolver 200 por errores. Las solicitudes condicionales son 304 por 'If-None-Match'.
3. 3 Errores (formato único)
json
{ "code":"validation_error", "message":"amount must be ≥ 1", "trace_id":"...", "details":[{"field":"amount","reason":"min:1"}] }
Obligatorios: 'code', 'message', 'trace _ id'; local - a través de 'Content-Language'.
3. 4 Paginación/filtros
Cursor-based: `page_size`, `page_token`, ответ: `next_page_token`.
Los filtros y la ordenación son whitelists documentados en 'parameters'.
3. 5 Seguridad
Esquema de seguridad univariable: OAuth2/OIDC scopes o mTLS; prohibir 'http' (sólo 'https').
No devolver encabezados sensibles, enmascarar tokens en ejemplos.
3. 6 Limitaciones y dimensiones
Límites de encabezado/cuerpo: 413/414/431; documentar los valores máximos permitidos.
4) Instrumentos y ecosistema
4. 1 OpenAPI
Spectral (enlace JSON/YAML), Redocly linter, oas-diff/openapi-diff (diff semántico), schemathesis/dredd (verificaciones realizadas).
4. 2 Protobuf/gRPC
buf (lint + breaking check), protolint, generadores SDK; gnostic para el análisis.
4. 3 GraphQL
graphql-schema-linter, graphql-inspector (breaking).
4. 4 Linternas de código y SAST
ESLint, golangci-lint, Detekt/Ktlint, Pylint/Flake8, Semgrep (plantillas de olores API y seguridad).
5) Ejemplos de reglas: Spectral/Redocly
5. 1 Spectral (ejemplo 'spectral. yaml`)
yaml extends: ["spectral:oas", "spectral:asyncapi"]
rules:
openapi-tags: off info-contact: error no-http: error path-kebab-case:
description: "Paths must be kebab-case"
given: "$.paths[]~"
severity: error then:
function: pattern functionOptions: { match: "^/(?:[a-z0-9]+(?--[a-z0-9]+)/?)+$" }
response-error-schema:
description: "Error responses must use standard schema"
given: "$.paths[][].responses[?(@property >= '400')]"
then:
field: "content.application/json.schema.$ref"
function: truthy id-as-uuid:
given: "$..parameters[?(@.name =~ /.id$/i)]"
then:
field: schema.format function: enumeration functionOptions: { values: ["uuid"] }
5. 2 Redocly (fragmento '.redocly. yaml`)
yaml apis:
main: openapi.yaml lint:
extends:
- recommended rules:
no-ambiguous-paths: error operation-2xx-only: off operation-success-response:
severity: error where:
subject: response filterInParentKeys: ["200","201","204"]
operation-security-defined: error no-plain-http: error
6) Protobuf/gRPC: perfil buf
6. 1 `buf. yaml`
yaml version: v2 modules:
- path: proto lint:
use:
- DEFAULT except:
- PACKAGE_VERSION_SUFFIX # используем v1 в package breaking:
use:
- WIRE_JSON deps: []
Recomendaciones:
- No vuelva a utilizar los números de campo; eliminables - en 'reservado'.
- Los nuevos campos son 'optional' o con impagos; no cambiar tipos/semántica.
7) Diff semántico y cambios «rompedores»
7. 1 HTTP
Ejemplos de breaking:- cambiar el tipo/la obligatoriedad del campo;
- eliminar el estado/ruta/parámetro;
- estrechamiento de enum/rango;
- cambio de formato id (uuid → string).
- agregar campos opcionales
- Nuevos estados que no afecten al happy-path (por ejemplo, el documentado '422');
- extensión enum.
7. 2 gRPC/Protobuf
Eliminar el campo sin 'reservado '/cambiar el número - breaking.
Cambio de tipo (int32 → string) - breaking.
Agregar una nueva etiqueta como optional - normalmente safe.
8) Enlace de linting de contratos y código
La coherencia está garantizada por dos flujos:1. Contrato → código: generación de enchufes SDK/servidor, ejemplos negativos en las pruebas.
2. Código → contrato: pruebas de especificación, comprobación automática de estados/encabezados.
Ideas Semgrep:- la prohibición de 'retorno 200' cuando 'error! = nil';
- obligatoriamente 'Idempotency-Key' en las rutas de pago write;
- enmascarar tokens en los logs.
9) CI/CD pipeline (referencia)
pre-commit: spectral lint, redocly lint
PR gate: openapi-diff (base..PR), buf breaking-check, graphql-inspector build: schemathesis smoke, unit/integration linters (ESLint/golangci-lint)
release: publish contracts (artifact/broker), sign & tag
La PR debe caer si:
- hay breaking-diff;
- Se han infringido las normas básicas (estados/seguridad/errores);
- faltan ejemplos/descripciones de parámetros.
10) Catálogo de reglas (plantilla para su organización)
Identificadores y tipos
`_id` — `string`, `format: uuid`.
Los campos monetarios son 'string '/' decimal' con escala; moneda - ISO-4217.
Errores
Esquema único (véase § 3. 3), códigos: '400/401/403/404/409/422/429/5xx'.
Siempre 'trace _ id'; 'Retry-After' para 429/503.
Paginación
Sólo cursor; max 'page _ size' está documentado.
Seguridad
Todas las operaciones - 'seguridad' bloque; descritos por 'scopes'.
No hay 'http:' referencias; TLS 1. 2+.
Caché/idempotencia
Для GET — `ETag/Last-Modified`; para escribir - 'Idempotency-Key' (cuando corresponda).
Documentación
'resumen', 'descripción', ejemplos de consultas/respuestas (válidas).
11) Ejemplos de inspecciones automatizadas
11. 1 Comprobación de las cabeceras de seguridad obligatorias (Spectral)
yaml security-headers:
given: "$.paths[][].responses['200'].headers"
then:
function: truthy
11. 2 openapi-diff (paso pseudo CI)
openapi-diff --fail-on-incompatible base.yaml pr.yaml
11. 3 buf breaking-check
buf breaking --against '.git#branch=main'
12) Observabilidad de la calidad de los contratos
Métricas: proporción de PR con errores de linting, tiempo de fix, número de intentos de breaking, «deudas» según las reglas.
Dashboards: progreso de la migración a un esquema de error unificado, cobertura con ejemplos, estabilidad de versiones.
13) Antipatternas
El «Doc» vive separado del código → la resincronización. Mantenga el contrato cerca del servicio y libere el artefacto versionado.
Linter sólo manualmente. Necesita una puerta de PR rígida.
Los ejemplos aleatorios (no-deterministic) son flautas en las verificaciones.
Falta de ejemplos negativos y códigos de error.
Reimpresión del esquema de errores para cada servicio.
Ignorar las comprobaciones de breaking de Protobuf (cambiar las etiquetas «por un ojo»).
14) Especificidad de iGaming/finanzas
Campos monetarios: escala fija/redondeo; Prohibición de float.
Las cabeceras obligatorias son 'X-Tenant', 'X-Región' y el rastreo 'traceparent'.
Bolígrafos de pago: comprobación de la existencia de 'Idempotency-Key', 'Retry-After' y las 409/201 semánticas correctas.
Webhooks PSP/KYC: HMAC/mTLS se describen en 'securitySchemes'; anti-replay ('X-Timestamp', ventana).
Restricciones regionales y localización de errores ('Content-Language').
15) Lista de comprobación prod
- Los perfiles Spectral/Redocly están diseñados y conectados en pre-commit y PR-gate.
- Esquema único de errores y estados - fijo y verificado.
- openapi-diff/GraphQL Inspector/buf - bloquear los cambios de breaking.
- Los ejemplos de solicitudes/respuestas son válidos; paginación/filtros documentados.
- SecuritySchemes y scopes están llenos; no hay enlaces http.
- Para Protobuf: 'reservado' en etiquetas remotas; nuevos campos - optional.
- Semgrep/linters de código incluidos; enmascarar secretos en los logs.
- CI publica los artefactos de los contratos y los informes linting.
- Playbook: cómo actuar con un breaking diff (rollback, hotfix, notificaciones a los integradores).
16) TL; DR
Implemente linting automático de contratos (Spectral/Redocly, buf/GraphQL Inspector) y diff semántico, registre un único esquema de errores/estados/paginación/seguridad, conecte PR-gate y publique contratos como artefactos. Cualquier breaking-diff es una señal de parada. Para el dinero/pagos - reglas especiales (idempotencia, 'Retry-After', HMAC/mTLS).