视觉画布设计
canvas-design
基于设计原则创作静态视觉作品,用于海报与品牌图形。
backend-openapi-documentation【文档与办公】Use this skill when the user says 'OpenAPI', 'Swagger', 'API documentation', 'spec-first', 'API spec', 'openapi.yaml', 'swagger.json', 'codegen', 'openapi-generator', 'API contract first'. This skill enforces spec-first API documentation with OpenAPI 3.x, code generation, and versioned specs. Applies to any backend stack. Do NOT use for: proto/gRPC s…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Drive all API development with an OpenAPI 3.x spec-first workflow: spec defines the contract, code is generated from it, and the spec is versioned alongside the code. The OpenAPI spec is the single source of truth for the API contract.
Exact user phrases: "OpenAPI", "Swagger", "API documentation", "spec-first", "API spec", "openapi.yaml", "swagger.json", "codegen", "openapi-generator", "API contract first".
OpenAPI YAML/JSON spec snippet or full spec file. No file unless requested.
Path: {path}
Method: {method}
OperationId: {operationId}
Tags: [{tag}]
6 lines per endpoint. Unlimited for full spec.
Who owns the API contract?
├── Spec-first (OpenAPI as source of truth)
│ ├── PRO: Contract before implementation, generates client/server code
│ ├── CON: Slower initial development, requires spec discipline
│ └── Use when: Public API, multiple consumers, external integrations
└── Code-first (annotations/comments generate spec)
├── PRO: Faster development, single source (code)
├── CON: Spec is afterthought, easy to forget docs
└── Use when: Internal API, single consumer, rapid prototyping
Do you need JSON Schema full compatibility?
├── Yes → OpenAPI 3.1.x (fully compatible with JSON Schema 2020-12)
│ ├── PRO: $ref anywhere, JSON Schema ecosystem
│ └── CON: Less tooling support, newer standard
└── No → OpenAPI 3.0.x (wider tool support)
├── PRO: Most tools support this (Swagger UI, codegen, Spectral)
└── CON: Limited JSON Schema compatibility
REST or resource-based?
├── Yes → Standard resource endpoints:
│ GET /resources → List resources
│ POST /resources → Create resource
│ GET /resources/{id} → Get resource
│ PUT /resources/{id} → Replace resource
│ PATCH /resources/{id} → Partial update
│ DELETE /resources/{id} → Delete resource
└── No → RPC-style operations:
POST /rpc/operation → Google-style, non-CRUD
openapi: 3.0.3
info:
title: Payment Service API
version: 1.0.0
description: Handles payment processing and reconciliation
contact:
name: Payment Team
email: payment-team@example.com
license:
name: MIT
servers:
- url: https://api.example.com/v1
description: Production server
- url: https://staging-api.example.com/v1
description: Staging server
paths:
/payments:
get:
operationId: listPayments
summary: List all payments with pagination and filtering
tags: [Payments]
parameters:
- $ref: '#/components/parameters/pageParam'
- $ref: '#/components/parameters/limitParam'
- name: status
in: query
schema:
type: string
enum: [pending, completed, failed, refunded]
responses:
'200':
description: Paginated list of payments
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedPayments'
'400':
$ref: '#/components/responses/BadRequest'
post:
operationId: createPayment
summary: Create a new payment
tags: [Payments]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreatePaymentRequest'
responses:
'201':
description: Payment created
headers:
Location:
schema:
type: string
format: uri
content:
application/json:
schema:
$ref: '#/components/schemas/Payment'
'409':
$ref: '#/components/responses/Conflict'
components:
schemas:
Payment:
type: object
required: [id, amount, currency, status, createdAt]
properties:
id:
type: string
format: uuid
description: Unique payment identifier
amount:
type: number
minimum: 0.01
example: 49.99
currency:
type: string
pattern: '^[A-Z]{3}#x27;
example: USD
status:
type: string
enum: [pending, completed, failed, refunded]
description:
type: string
maxLength: 500
createdAt:
type: string
format: date-time
components:
responses:
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Conflict:
description: Resource conflict
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
schemas:
ErrorResponse:
type: object
required: [code, message, requestId]
properties:
code:
type: string
description: Machine-readable error code
example: PAYMENT_ALREADY_EXISTS
message:
type: string
description: Human-readable error message
example: Payment with this idempotency key already exists
requestId:
type: string
format: uuid
description: Trace ID for support
details:
type: array
items:
type: object
properties:
field:
type: string
description: Field that caused the error
message:
type: string
description: Error message for this field
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: Standard JWT authentication
apiKey:
type: apiKey
in: header
name: X-API-Key
description: API key for service-to-service auth
security:
- bearerAuth: []
# Lint with Spectral
npx @stoplight/spectral-cli lint openapi.yaml
# Structural validation
npx swagger-cli validate openapi.yaml
# Diff against previous version
npx @openapitools/openapi-diff openapi-v1.yaml openapi-v2.yaml
# Server stub
npx @openapitools/openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-express \
-o ./generated/server \
--additional-properties=typescriptThreePlus=true
# Client SDK
npx @openapitools/openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-axios \
-o ./generated/client \
--additional-properties=withInterfaces=true
# Define reusable pagination parameters
components:
parameters:
pageParam:
name: page
in: query
schema:
type: integer
minimum: 1
default: 1
description: Page number (1-indexed)
limitParam:
name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
description: Items per page
schemas:
PaginatedResponse:
type: object
required: [data, pagination]
properties:
data:
type: array
pagination:
type: object
properties:
page: { type: integer }
limit: { type: integer }
total: { type: integer }
totalPages: { type: integer }
# OneOf for polymorphic responses
components:
schemas:
CreatePaymentResponse:
oneOf:
- $ref: '#/components/schemas/PaymentSuccess'
- $ref: '#/components/schemas/PaymentError'
discriminator:
propertyName: type
mapping:
success: '#/components/schemas/PaymentSuccess'
error: '#/components/schemas/PaymentError'
paths:
/payments:
post:
callbacks:
paymentCompleted:
'{$request.body#/callbackUrl}':
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentWebhook'
| Strategy | Mechanism | Breaking Change? | Example |
|---|---|---|---|
| URL path | /v1/, /v2/ | New version | api.example.com/v1/payments |
| Header | Accept: application/vnd.api+json;version=2 | New version | Custom accept header |
| Query param | ?version=2 | New version | api.example.com/payments?version=2 |
| No versioning | Always backward compatible | Never | api.example.com/payments |
| Aspect | Recommendation |
|---|---|
| When to generate | On spec change, committed to repo |
| What to generate | Client SDK, server interfaces, docs |
| What NOT to generate | Business logic, database access |
| Custom templates | Use mustache templates for custom patterns |
| Generated code | Check in to version control (deterministic) |
# Spectral ruleset
extends: [[spectral:oas, all]]
rules:
operation-operationId: error
path-params: error
path-declarations-must-exist: error
no-identical-paths: error
operation-tags: error
operation-summary: error
oas3-unused-component: warn
oas3-valid-media-example: error
$ref.| Spec Size | Load Time | Notes |
|---|---|---|
| < 100KB | Instant | Single service, simple API |
| 100KB-1MB | < 1s | Multiple services, many endpoints |
| 1MB-10MB | 1-5s | Use multi-file spec with $ref |
| > 10MB | Slow | Consider splitting into multiple specs |
# openapi.yaml (root)
paths:
/users:
$ref: paths/users.yaml
components:
schemas:
User:
$ref: schemas/user.yaml
format: sensitiveNo artifact produced unless requested. Next skill: contract-testing — verify the OpenAPI spec against provider behavior. Carry forward: OpenAPI spec, generated client/server code, validation rules.
` interface EventObserver { onEvent(event: T): Promise; }
class EventBus { private observers: Set<EventObserver> = new Set(); subscribe(observer: EventObserver): void { this.observers.add(observer); } unsubscribe(observer: EventObserver): void { this.observers.delete(observer); } async emit(event: T): Promise { const results = Array.from(this.observers).map(o => o.onEvent(event)); await Promise.allSettled(results); } } `
config: defaults: timeout: 30s retryCount: 3 overrides: production: timeout: 60s retryCount: 5 development: timeout: 300s retryCount: 1
| Metric | Threshold | Severity | Action |
|---|---|---|---|
| Error rate | > 1% over 5min | Critical | Page on-call |
| p99 latency | > 2s over 5min | Warning | Investigate |
| Throughput drop | > 50% over 1min | Critical | Check upstream |
| Queue depth | > 1000 over 1min | Warning | Scale consumers |
| Disk usage | > 85% | Warning | Clean or expand |
| Memory usage | > 90% heap | Critical | Restart or scale |
| Anti-Pattern | Symptom | Root Cause | Solution |
|---|---|---|---|
| Premature optimization | Complex code for no measured benefit | Guessing instead of profiling | Measure first, optimize based on data |
| Copy-paste reuse | Duplicate code across codebase | Lack of abstraction | Extract shared logic into libraries |
| Gold-plating | Features with no current requirement | Over-engineering | YAGNI — build what's needed now |
| Magical thinking | Assumptions without validation | Skipping error handling | Handle all failure modes explicitly |
Cache hierarchy: L1 (in-memory local) → L2 (distributed Redis/Memcached) → L3 (CDN/Edge). Cache invalidation: TTL-based (simple, stale), event-based (complex, fresh), write-through (consistent, higher write latency), write-behind (fast writes, eventual consistency).