Skip to content
api-architecture logo

API Architecture Skill

api-architecture

REST, GraphQL, and hybrid API architecture patterns for building scalable and maintainable APIs

SKILL.md

Full skill instructions

API Architecture Skill

Purpose

Select and design the optimal API architecture for your use case.

Decision Matrix

┌──────────────────────────────────────────────────────────────────┐
│                    API Style Selection                            │
├──────────────────────────────────────────────────────────────────┤
│                                                                   │
│  Use Case                              → Recommended Style        │
│  ─────────────────────────────────────────────────────────────   │
│  Public API + Wide adoption            → REST (OpenAPI 3.1)      │
│  Complex queries + Frontend-heavy      → GraphQL                 │
│  High performance + Internal           → gRPC                    │
│  Mobile + Offline support              → REST + GraphQL hybrid   │
│  Microservices communication           → gRPC / Event-driven     │
│  Real-time updates                     → GraphQL Subscriptions   │
│                                                                   │
└──────────────────────────────────────────────────────────────────┘

API Comparison

AspectRESTGraphQLgRPC
Learning curveLowMediumHigh
FlexibilityLowHighMedium
PerformanceGoodGoodExcellent
CachingEasy (HTTP)ComplexCustom
ToolingExcellentGoodGood
DocumentationOpenAPISDLProtobuf
Browser supportNativeNativeLimited

REST Architecture (Richardson Maturity Model)

Level 0: Single endpoint, POST everything
Level 1: Multiple endpoints per resource
Level 2: Proper HTTP methods + status codes ← Target
Level 3: HATEOAS (hypermedia links)

Resource Design

# Good resource naming
GET /​api/​v1/​users              # List users
GET /​api/​v1/​users/​{id}         # Get user
POST /​api/​v1/​users             # Create user
PUT /​api/​v1/​users/​{id}         # Replace user
PATCH /​api/​v1/​users/​{id}       # Update user
DELETE /​api/​v1/​users/​{id}      # Delete user

# Nested resources (max 2 levels)
GET /​api/​v1/​users/​{id}/​orders  # User's orders

# Actions (when CRUD doesn't fit)
POST /​api/​v1/​orders/​{id}/​cancel
POST /​api/​v1/​users/​{id}/​verify

GraphQL Architecture

# Schema-first design
type Query {
  user(id: ID!): User
  users(first: Int, after: String): UserConnection!
}

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

type Subscription {
  userCreated: User!
  orderStatusChanged(orderId: ID!): Order!
}

Hybrid Strategy

┌─────────────────────────────────────────────────────────┐
│                    API Gateway                           │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  Public Clients ────► REST API (OpenAPI)                │
│                                                          │
│  Web/​Mobile App ────► GraphQL API                       │
│                                                          │
│  Internal Services ─► gRPC                              │
│                                                          │
└─────────────────────────────────────────────────────────┘

Versioning Strategies

StrategyExampleProsCons
URL path/​api/​v1/​usersClear, cacheableURL pollution
HeaderAccept: application/​vnd.api.v1+jsonClean URLsHidden
Query param/​api/​users?version=1FlexibleUnconventional

Recommendation: URL versioning for public APIs, header for internal.


Unit Test Template

import { describe, it, expect } from 'vitest';
import { selectApiStyle, validateResourceNaming } from './​api-architecture';

describe('API Architecture Skill', () => {
  describe('selectApiStyle', () => {
    it('should recommend REST for public APIs', () => {
      const result = selectApiStyle({
        use_case: 'public_api',
        audience: 'external',
      });
      expect(result.style).toBe('rest');
      expect(result.reasons).toContain('wide tooling support');
    });

    it('should recommend GraphQL for complex frontend needs', () => {
      const result = selectApiStyle({
        use_case: 'internal_api',
        complex_queries: true,
        frontend_heavy: true,
      });
      expect(result.style).toBe('graphql');
    });
  });

  describe('validateResourceNaming', () => {
    it('should accept valid resource names', () => {
      expect(validateResourceNaming('/​api/​v1/​users')).toBe(true);
      expect(validateResourceNaming('/​api/​v1/​users/​{id}/​orders')).toBe(true);
    });

    it('should reject invalid resource names', () => {
      expect(validateResourceNaming('/​api/​v1/​getUsers')).toBe(false); // verb in name
      expect(validateResourceNaming('/​api/​v1/​user')).toBe(false); // singular
    });
  });
});

Troubleshooting

IssueCauseSolution
Over-fetching (REST)Too much data returnedAdd field selection or use GraphQL
Under-fetching (REST)Multiple round tripsEmbed related resources or use GraphQL
N+1 queries (GraphQL)Resolver per fieldUse DataLoader for batching
Version conflictsBreaking changesSemantic versioning + deprecation policy

Quality Checklist

  • API style matches use case requirements
  • Resource naming follows conventions
  • Versioning strategy defined
  • Error response format standardized
  • Pagination strategy chosen
  • Rate limiting planned