본문으로 건너뛰기
cccskills
무료GitHub에 공개

api-design

REST/GraphQL/gRPC API design best practices. Use when designing APIs, defining contracts, handling versioning. Covers OpenAPI 3.2, GraphQL Federation, gRPC streaming.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(8)

  • SKILL.md8.3 KB
  • reference/comparison.md6.1 KB
  • reference/graphql.md6.2 KB
  • reference/grpc.md7.4 KB
  • reference/rest.md5.3 KB
  • templates/graphql/schema.graphql4.5 KB
  • templates/grpc/service.proto6.0 KB
  • templates/openapi/openapi.yaml8.3 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

API Design

Core Principles

  • Contract-First — Define API spec before implementation
  • OpenAPI 3.2 — Use OpenAPI for REST API documentation
  • URL Versioning — Version in path /v1/, with Sunset headers
  • Idempotency — PUT/DELETE must be idempotent, POST uses Idempotency-Key
  • Cursor Pagination — Avoid offset-based pagination
  • RFC 7807 Errors — Standard Problem Details format
  • No backwards compatibility — Delete, don't deprecate

Quick Reference

When to Use What

ScenarioChoiceReason
Public API / MVPRESTSimple, universal, easy debugging
Frontend-driven / MobileGraphQLFetch exactly what you need
Microservices internalgRPCHigh performance, strong typing
Real-time datagRPC / GraphQL SubscriptionsBidirectional streaming

REST API Design

Resource Naming

# Good
GET  /users              # List users
GET  /users/123          # Get user
POST /users              # Create user
PUT  /users/123          # Replace user
PATCH /users/123         # Update user
DELETE /users/123        # Delete user

# Nested resources
GET /users/123/orders    # User's orders

# Actions (when CRUD doesn't fit)
POST /users/123/activate # Action on resource

# Query parameters for filtering
GET /users?status=active&role=admin&limit=20

HTTP Methods

MethodPurposeIdempotentSafe
GETReadYesYes
POSTCreateNoNo
PUTReplaceYesNo
PATCHUpdateNoNo
DELETERemoveYesNo

Status Codes

# Success
200 OK              - Successful GET/PUT/PATCH
201 Created         - Successful POST (include Location header)
204 No Content      - Successful DELETE

# Client Errors
400 Bad Request     - Malformed request syntax
401 Unauthorized    - Missing/invalid authentication
403 Forbidden       - Authenticated but not authorized
404 Not Found       - Resource doesn't exist
409 Conflict        - Duplicate/conflict (e.g., unique constraint)
422 Unprocessable   - Validation failed
429 Too Many        - Rate limited

# Server Errors
500 Internal Error  - Unexpected server error
503 Unavailable     - Service temporarily down

Error Response (RFC 7807)

{
  "type": "https://api.example.com/errors/validation",
  "title": "Validation Error",
  "status": 422,
  "detail": "The request contains invalid parameters",
  "instance": "/users/123",
  "errors": [
    { "field": "email", "message": "Invalid email format" },
    { "field": "age", "message": "Must be positive integer" }
  ]
}

Pagination (Cursor-Based)

// Request
GET /users?limit=20&cursor=eyJpZCI6MTAwfQ

// Response
{
  "data": [...],
  "pagination": {
    "next_cursor": "eyJpZCI6MTIwfQ",
    "prev_cursor": "eyJpZCI6ODB9",
    "has_next": true,
    "has_prev": true,
    "limit": 20
  }
}

Versioning

# URL versioning (recommended)
GET /v1/users
GET /v2/users

# Deprecation headers
Sunset: Sat, 31 Dec 2025 23:59:59 GMT
Deprecation: true
Link: </v2/users>; rel="successor-version"

Idempotency

# For non-idempotent operations (POST)
POST /orders
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

# Server stores result and returns same response for duplicate key

GraphQL Design

Schema Principles

  • Domain-driven — Schema reflects business domain, not database
  • Descriptive names — Clear field/type names for monitoring
  • Limit nesting — Deep nesting hurts performance
  • Use @key — Mark entity identifiers for Federation

Type Definitions

type Query {
  user(id: ID!): User
  users(first: Int, after: String, filter: UserFilter): UserConnection!
}

type Mutation {
  createUser(input: CreateUserInput!): CreateUserPayload!
  updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
}

type User @key(fields: "id") {
  id: ID!
  email: String!
  name: String!
  orders(first: Int, after: String): OrderConnection!
  createdAt: DateTime!
}

# Relay-style pagination
type UserConnection {
  edges: [UserEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

type UserEdge {
  node: User!
  cursor: String!
}

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}

Error Handling

type Mutation {
  createUser(input: CreateUserInput!): CreateUserPayload!
}

# Union for typed errors
union CreateUserPayload = User | ValidationError | ConflictError

type ValidationError {
  message: String!
  field: String
  code: String!
}

type ConflictError {
  message: String!
  existingId: ID!
}

N+1 Prevention

// Use DataLoader for batching
const userLoader = new DataLoader(async (ids: string[]) => {
  const users = await db.user.findMany({
    where: { id: { in: ids } }
  });
  return ids.map(id => users.find(u => u.id === id));
});

// Resolver
const resolvers = {
  Order: {
    user: (order) => userLoader.load(order.userId),
  },
};

gRPC Design

Proto Definition

syntax = "proto3";

package api.v1;

import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";

service UserService {
  // Unary
  rpc GetUser(GetUserRequest) returns (User);
  rpc CreateUser(CreateUserRequest) returns (User);

  // Server streaming
  rpc ListUsers(ListUsersRequest) returns (stream User);

  // Client streaming
  rpc BatchCreateUsers(stream CreateUserRequest) returns (BatchCreateResponse);

  // Bidirectional streaming
  rpc SyncUsers(stream UserUpdate) returns (stream UserUpdate);
}

message User {
  string id = 1;
  string email = 2;
  string name = 3;
  google.protobuf.Timestamp created_at = 4;
}

message GetUserRequest {
  string id = 1;
}

message ListUsersRequest {
  int32 page_size = 1;
  string page_token = 2;
  UserFilter filter = 3;
}

message UserFilter {
  optional string status = 1;
  optional string role = 2;
}

Error Handling

// Use Google's richer error model
import "google/rpc/status.proto";
import "google/rpc/error_details.proto";

// For streaming: embed errors in response
message StreamResponse {
  oneof result {
    User user = 1;
    StreamError error = 2;
  }
}

message StreamError {
  string code = 1;
  string message = 2;
  map<string, string> details = 3;
}

Deadlines & Retries

// Always set deadlines
const deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 5);

const user = await client.getUser(
  { id: '123' },
  { deadline }
);

// Configure retry policy
const retryPolicy = {
  maxAttempts: 3,
  initialBackoff: '0.1s',
  maxBackoff: '1s',
  backoffMultiplier: 2,
  retryableStatusCodes: ['UNAVAILABLE', 'DEADLINE_EXCEEDED'],
};

Rate Limiting

Headers

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200
Retry-After: 60

Response (429)

{
  "type": "https://api.example.com/errors/rate-limited",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "You have exceeded the rate limit of 100 requests per minute",
  "retryAfter": 60
}

Checklist

## Design
- [ ] API spec defined before implementation
- [ ] Resources use plural nouns
- [ ] Correct HTTP methods/status codes
- [ ] RFC 7807 error format

## Features
- [ ] Cursor-based pagination
- [ ] Rate limiting with headers
- [ ] Idempotency keys for POST
- [ ] API versioning strategy

## Documentation
- [ ] OpenAPI/GraphQL schema published
- [ ] Examples for all endpoints
- [ ] Error codes documented

## Operations
- [ ] Request/response logging
- [ ] Latency and error rate metrics
- [ ] Deprecation notices for old versions

See Also

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Audit and organize AI coding-agent instructions, including AGENTS.md, CLAUDE.md, skills, and agent definitions. Use when the user asks to diagnose conflicting instructions, excessive approval pauses, broad skill triggers, duplicate guidance, or broken instruction references, or to clean up that instruction set. Ordinary code review, Markdown editing, or application debugging alone does not trigger this workflow. Inspection stays read-only; apply changes when authorized.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

majiayu000/spellbook2882026년 10월 8일 업데이트

Generate or update repository-specific AGENTS.md instruction files from real repo evidence. Use when asked to create, design, scaffold, split, or improve root or scoped AGENTS.md files for Codex/Claude/agent workflows, especially when a repo needs directory-specific rules, validation commands, generated-file boundaries, or a short agent onboarding router.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

majiayu000/spellbook2882026년 10월 8일 업데이트

Mobile app UI design expert for iOS and Android. Use when designing app interfaces, creating design systems, ensuring accessibility, or following platform guidelines. Covers Material Design 3, Human Interface Guidelines, color theory, typography, and 2025 trends.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

majiayu000/spellbook2882026년 10월 8일 업데이트

End-to-end app feature inventory and user-story testing workflow with a canonical tracker. Use when the user asks to audit every feature, derive expected behavior from code, test user journeys, or explicitly fix and retest documented UX or logistical defects.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

majiayu000/spellbook2882026년 10월 8일 업데이트

Design architecture foundations before implementation. Use when asked to design or refactor architecture, choose Rust/Go crate, package, module, runtime, workflow, or service boundaries, compare mature project architecture, prevent stacked one-off PRs, audit migration debt in existing repos, or produce a spec before coding.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

majiayu000/spellbook2882026년 10월 8일 업데이트

Evidence-driven architecture research for understanding real systems and making technical decisions. Use when doing architecture landscape studies, source-backed system archaeology, build-vs-buy or adopt/adapt/build decisions, open-source and commercial comparisons, revisiting an earlier architecture choice, or handling requests such as 架构调研, 架构选型, 竞品架构, 技术尽调, 同类方案, 开源替代, how is X built, and what should we learn from X. Do not use for small mechanical changes, market-only discovery, or detailed design after the technology direction is already fixed.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

majiayu000/spellbook2882026년 10월 8일 업데이트

majiayu000의 스킬 모두 보기

이 스킬의 문제 신고