api-design

REST and GraphQL API design best practices including OpenAPI specs. Use when designing APIs, documenting endpoints, or reviewing API architecture.

31 stars

Best use case

api-design is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

REST and GraphQL API design best practices including OpenAPI specs. Use when designing APIs, documenting endpoints, or reviewing API architecture.

Teams using api-design should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/api-design/SKILL.md --create-dirs "https://raw.githubusercontent.com/travisjneuman/.claude/main/skills/api-design/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/api-design/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How api-design Compares

Feature / Agentapi-designStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

REST and GraphQL API design best practices including OpenAPI specs. Use when designing APIs, documenting endpoints, or reviewing API architecture.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# API Design Guide

Best practices for designing developer-friendly, maintainable APIs.

## REST API Principles

### Resource Naming

**Use nouns, not verbs**:

```
✓ GET /users
✓ GET /users/123
✓ GET /users/123/orders

✗ GET /getUsers
✗ GET /fetchUserById
✗ POST /createNewOrder
```

**Use plural nouns**:

```
✓ /users
✓ /orders
✓ /products

✗ /user
✗ /order
```

**Hierarchical relationships**:

```
/users/{userId}/orders           # User's orders
/users/{userId}/orders/{orderId} # Specific order
```

---

### HTTP Methods

| Method | Purpose                   | Idempotent | Request Body |
| ------ | ------------------------- | ---------- | ------------ |
| GET    | Retrieve resource(s)      | Yes        | No           |
| POST   | Create resource           | No         | Yes          |
| PUT    | Replace resource entirely | Yes        | Yes          |
| PATCH  | Update resource partially | No         | Yes          |
| DELETE | Remove resource           | Yes        | No           |

---

### Status Codes

**Success (2xx)**:

- `200 OK` - Request succeeded
- `201 Created` - Resource created (return Location header)
- `204 No Content` - Success with no response body

**Client Error (4xx)**:

- `400 Bad Request` - Malformed request
- `401 Unauthorized` - Authentication required
- `403 Forbidden` - No permission
- `404 Not Found` - Resource doesn't exist
- `409 Conflict` - State conflict
- `422 Unprocessable Entity` - Validation failed
- `429 Too Many Requests` - Rate limited

**Server Error (5xx)**:

- `500 Internal Server Error` - Unexpected error
- `503 Service Unavailable` - Temporary outage

---

### Response Format

**Successful response**:

```json
{
  "data": {
    "id": "123",
    "name": "John Doe",
    "email": "john@example.com"
  }
}
```

**Collection response**:

```json
{
  "data": [
    { "id": "1", "name": "Item 1" },
    { "id": "2", "name": "Item 2" }
  ],
  "meta": {
    "page": 1,
    "perPage": 20,
    "total": 100,
    "totalPages": 5
  },
  "links": {
    "self": "/items?page=1",
    "next": "/items?page=2",
    "prev": null
  }
}
```

**Error response**:

```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": [
      {
        "field": "email",
        "code": "INVALID_FORMAT",
        "message": "Must be a valid email address"
      }
    ]
  }
}
```

---

### Pagination

**Offset-based** (simple, but slow on large datasets):

```
GET /users?page=2&perPage=20
GET /users?offset=40&limit=20
```

**Cursor-based** (efficient, recommended):

```
GET /users?cursor=eyJpZCI6MTIzfQ&limit=20
```

Response includes next cursor:

```json
{
  "data": [...],
  "meta": {
    "nextCursor": "eyJpZCI6MTQzfQ",
    "hasMore": true
  }
}
```

---

### Filtering, Sorting, Fields

**Filtering**:

```
GET /users?status=active
GET /users?created_after=2024-01-01
GET /users?role=admin,moderator
```

**Sorting**:

```
GET /users?sort=name
GET /users?sort=-created_at         # Descending
GET /users?sort=status,-created_at  # Multiple fields
```

**Field selection**:

```
GET /users?fields=id,name,email
GET /users?include=orders,profile
```

---

### Versioning

**URL path** (recommended):

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

**Header**:

```
Accept: application/vnd.api+json;version=2
```

---

## OpenAPI Specification

```yaml
openapi: 3.0.3
info:
  title: My API
  version: 1.0.0
  description: API for managing users

servers:
  - url: https://api.example.com/v1

paths:
  /users:
    get:
      summary: List users
      tags: [Users]
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
      responses:
        "200":
          description: List of users
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/User"

components:
  schemas:
    User:
      type: object
      required: [id, email]
      properties:
        id:
          type: string
        email:
          type: string
          format: email
        name:
          type: string
```

---

## Authentication

**API Keys** (simple, for server-to-server):

```
Authorization: Api-Key YOUR_API_KEY
```

**Bearer Tokens** (JWT, OAuth):

```
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
```

**Include in OpenAPI**:

```yaml
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - bearerAuth: []
```

---

## Rate Limiting

Include headers in responses:

```
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
```

Return `429 Too Many Requests` when exceeded.

---

## Security Checklist

- [ ] HTTPS only
- [ ] Authentication on protected routes
- [ ] Input validation
- [ ] Output encoding
- [ ] Rate limiting
- [ ] CORS configuration
- [ ] No sensitive data in URLs
- [ ] Audit logging

---

## gRPC and Protocol Buffers

### Proto Definition

```protobuf
syntax = "proto3";
package user.v1;

service UserService {
  rpc GetUser(GetUserRequest) returns (User);
  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
  rpc CreateUser(CreateUserRequest) returns (User);
  rpc StreamUpdates(StreamRequest) returns (stream UserUpdate);
}

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

message GetUserRequest {
  string id = 1;
}

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

message ListUsersResponse {
  repeated User users = 1;
  string next_page_token = 2;
}
```

### When to Use gRPC vs REST

| Factor            | gRPC                        | REST                        |
| ----------------- | --------------------------- | --------------------------- |
| **Performance**   | Binary, fast                | JSON, human-readable        |
| **Streaming**     | Bidirectional               | SSE/WebSocket workaround    |
| **Type safety**   | Proto generates types       | OpenAPI + codegen           |
| **Browser**       | Needs gRPC-Web proxy        | Native                      |
| **Tooling**       | Protoc, Buf                 | Swagger, Postman            |
| **Best for**      | Service-to-service, streaming | Public APIs, web clients  |

---

## tRPC for TypeScript

```typescript
// server/router.ts
import { router, publicProcedure, protectedProcedure } from './trpc';
import { z } from 'zod';

export const appRouter = router({
  user: router({
    get: publicProcedure
      .input(z.object({ id: z.string() }))
      .query(async ({ input }) => {
        return db.user.findUnique({ where: { id: input.id } });
      }),
    create: protectedProcedure
      .input(z.object({
        name: z.string().min(1),
        email: z.string().email(),
      }))
      .mutation(async ({ input, ctx }) => {
        return db.user.create({ data: { ...input, createdBy: ctx.userId } });
      }),
  }),
});

export type AppRouter = typeof appRouter;

// client.ts - Full type inference, no codegen
const user = trpc.user.get.useQuery({ id: '123' });
const createUser = trpc.user.create.useMutation();
```

tRPC is ideal for monorepo full-stack TypeScript apps where client and server share the same codebase.

---

## Webhook Design Patterns

### Webhook Payload

```json
{
  "id": "evt_abc123",
  "type": "order.completed",
  "created_at": "2025-01-15T10:30:00Z",
  "data": {
    "order_id": "ord_456",
    "total": 99.99,
    "currency": "USD"
  }
}
```

### Signature Verification

```typescript
// Sign webhooks with HMAC-SHA256
import crypto from 'crypto';

function signWebhook(payload: string, secret: string): string {
  return crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
}

// Verify on receiving end
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
  const expected = signWebhook(payload, secret);
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected),
  );
}
```

### Retry Strategy

```
Attempt 1: Immediately
Attempt 2: After 1 minute
Attempt 3: After 5 minutes
Attempt 4: After 30 minutes
Attempt 5: After 2 hours
Attempt 6: After 24 hours (final)

Failed webhooks: log, alert, manual retry UI
```

### Idempotency

```typescript
// Include idempotency key in webhook
// Receivers should deduplicate based on event ID
async function handleWebhook(event: WebhookEvent) {
  // Check if already processed
  const existing = await db.processedEvents.findUnique({
    where: { eventId: event.id },
  });
  if (existing) return { status: 'already_processed' };

  // Process and record
  await db.$transaction([
    processEvent(event),
    db.processedEvents.create({ data: { eventId: event.id } }),
  ]);
}
```

---

## API Versioning Strategies

| Strategy            | Example                          | Pros                     | Cons                      |
| ------------------- | -------------------------------- | ------------------------ | ------------------------- |
| **URL path**        | `/api/v1/users`                  | Explicit, easy to route  | URL pollution             |
| **Query parameter** | `/api/users?version=1`           | Optional parameter       | Easy to miss              |
| **Header**          | `Accept: application/vnd.api.v1` | Clean URLs               | Hidden, harder to test    |
| **Content negotiation** | `Accept: application/json;v=2` | Standards-based        | Complex to implement      |

**Recommendation:** URL path versioning for simplicity. Only bump major versions for breaking changes. Use additive, non-breaking changes within a version.

Related Skills

process-flowchart-designer

31
from travisjneuman/.claude

Create process flowcharts and workflow diagrams from descriptions, with optimization suggestions and bottleneck identification. Use when mapping processes, designing workflows, or improving operational efficiency.

graphic-design

31
from travisjneuman/.claude

Professional graphic design principles for digital and print media. Use when creating visual designs, choosing color palettes, typography, layouts, or providing design feedback.

generic-static-design-system

31
from travisjneuman/.claude

Complete design system reference for static HTML/CSS/JS sites. Covers colors, typography, component patterns, animations, and accessibility. Use when implementing UI, choosing colors, or ensuring brand consistency.

generic-react-ux-designer

31
from travisjneuman/.claude

Professional UI/UX design expertise for React applications. Covers design thinking, user psychology (Hick's/Fitts's/Jakob's Law), visual hierarchy, interaction patterns, accessibility, performance-driven design, and design critique. Use when designing features, improving UX, solving user problems, or conducting design reviews.

generic-react-design-system

31
from travisjneuman/.claude

Complete design system reference for React applications. Covers colors, typography, spacing, component patterns, glassmorphism effects, GPU-accelerated animations, and WCAG AA accessibility. Use when implementing UI, choosing colors, applying spacing, creating components, or ensuring brand consistency.

generic-fullstack-ux-designer

31
from travisjneuman/.claude

Professional UI/UX design expertise for full-stack applications. Covers design thinking, user psychology (Hick's/Fitts's/Jakob's Law), visual hierarchy, interaction patterns, accessibility, performance-driven design, and design critique. Use when designing features, improving UX, solving user problems, or conducting design reviews.

generic-fullstack-design-system

31
from travisjneuman/.claude

Complete design system reference for full-stack applications. Covers colors, typography, spacing, component patterns (shadcn/ui), effects, GPU-accelerated animations, and WCAG AA accessibility. Use when implementing UI, choosing colors, applying spacing, creating components, or ensuring brand consistency.

generic-design-system

31
from travisjneuman/.claude

Complete design system reference for any project - colors, typography, spacing, components, animations. Adapts to project theme and tech stack. Use when implementing UI, choosing colors, creating animations, or ensuring brand consistency. For new design systems, use ui-research skill first.

devex-sdk-design

31
from travisjneuman/.claude

Developer experience (DX) engineering, SDK design patterns, API ergonomics, CLI tooling design, documentation-driven development, and developer onboarding. Use when designing SDKs, improving API ergonomics, building developer tools, or creating developer documentation.

example-skill

31
from travisjneuman/.claude

Example skill - replace with your skill's description and activation keywords

websockets-realtime

31
from travisjneuman/.claude

Real-time communication with WebSockets, Server-Sent Events, and related technologies. Use when building chat, live updates, collaborative features, or any real-time functionality.

video-production

31
from travisjneuman/.claude

Professional video production from planning to delivery. Use when creating video content, editing workflows, motion graphics, or optimizing video for different platforms.