8 min read • Guide 805 of 877
API-First Development
API-first development starts with the contract. GitScrum helps teams coordinate API design and track implementation against agreed specifications.
API-First Approach
Design Before Build
API-FIRST WORKFLOW:
┌─────────────────────────────────────────────────────────────┐
│ │
│ TRADITIONAL (CODE-FIRST): │
│ ───────────────────────── │
│ │
│ Backend builds → Frontend waits → Integration → Rework │
│ │ │ │
│ └─ API shape unknown ────────────┘ │
│ │
│ PROBLEM: Frontend blocked, late integration issues │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ API-FIRST: │
│ ────────── │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Design │──→│ Contract │──→│ Parallel │──→│Integrate │ │
│ │ API │ │ Agreed │ │ Work │ │ & Test │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │
│ │ ┌────┴────┐ │
│ │ │ │ │
│ │ Frontend Backend │
│ │ (with mock) (real) │
│ │ │ │ │
│ │ └────┬────┘ │
│ │ │ │
│ └──────────────┘ │
│ Same contract │
│ │
│ BENEFIT: Both teams work in parallel │
└─────────────────────────────────────────────────────────────┘
API Design Process
API DESIGN WORKFLOW:
┌─────────────────────────────────────────────────────────────┐
│ │
│ STEP 1: IDENTIFY CONSUMERS │
│ ───────────────────────── │
│ • Who will use this API? │
│ • Web frontend, mobile app, third parties? │
│ • What do they need? │
│ │
│ STEP 2: DESIGN ENDPOINTS │
│ ──────────────────────── │
│ • Resources and operations │
│ • Request/response shapes │
│ • Error formats │
│ • Authentication │
│ │
│ STEP 3: DOCUMENT IN SPEC │
│ ──────────────────────── │
│ • OpenAPI for REST │
│ • GraphQL SDL │
│ • Machine-readable format │
│ │
│ STEP 4: REVIEW WITH CONSUMERS │
│ ───────────────────────────── │
│ • Share spec with frontend/consumers │
│ • Gather feedback │
│ • Iterate on design │
│ │
│ STEP 5: FINALIZE CONTRACT │
│ ───────────────────────── │
│ • Agreed spec becomes source of truth │
│ • Generate mock server │
│ • Both teams begin work │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ API DESIGN TASK: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ API-010: Design Order API ││
│ │ ││
│ │ CONSUMERS: ││
│ │ • Web checkout (primary) ││
│ │ • Mobile app ││
│ │ • Admin dashboard ││
│ │ ││
│ │ ENDPOINTS PROPOSED: ││
│ │ POST /orders Create order ││
│ │ GET /orders/{id} Get order details ││
│ │ PATCH /orders/{id} Update order ││
│ │ GET /orders List user's orders ││
│ │ ││
│ │ STATUS: Review with frontend team ││
│ │ REVIEW DATE: Jan 25 ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
OpenAPI Specification
Contract Definition
OPENAPI SPECIFICATION:
┌─────────────────────────────────────────────────────────────┐
│ │
│ EXAMPLE OPENAPI SPEC: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ openapi: 3.0.0 ││
│ │ info: ││
│ │ title: Orders API ││
│ │ version: 1.0.0 ││
│ │ ││
│ │ paths: ││
│ │ /orders: ││
│ │ post: ││
│ │ summary: Create a new order ││
│ │ requestBody: ││
│ │ content: ││
│ │ application/json: ││
│ │ schema: ││
│ │ $ref: '#/components/schemas/CreateOrder' ││
│ │ responses: ││
│ │ 201: ││
│ │ description: Order created ││
│ │ content: ││
│ │ application/json: ││
│ │ schema: ││
│ │ $ref: '#/components/schemas/Order' ││
│ │ 400: ││
│ │ description: Invalid request ││
│ │ ││
│ │ components: ││
│ │ schemas: ││
│ │ CreateOrder: ││
│ │ type: object ││
│ │ required: [items, shippingAddress] ││
│ │ properties: ││
│ │ items: ││
│ │ type: array ││
│ │ items: ││
│ │ $ref: '#/components/schemas/OrderItem' ││
│ │ shippingAddress: ││
│ │ $ref: '#/components/schemas/Address' ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ SPEC BECOMES: │
│ • Documentation (SwaggerUI) │
│ • Mock server (for frontend) │
│ • Client SDKs (generated) │
│ • Contract tests (validation) │
└─────────────────────────────────────────────────────────────┘
Parallel Development
Using Mock Servers
MOCK SERVER WORKFLOW:
┌─────────────────────────────────────────────────────────────┐
│ │
│ FROM SPEC TO MOCK: │
│ ────────────────── │
│ │
│ OpenAPI Spec → Mock Server Generator → Mock API │
│ │
│ TOOLS: │
│ • Prism (Stoplight) │
│ • Mockoon │
│ • WireMock │
│ • MSW (Mock Service Worker) │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ PARALLEL WORKFLOW: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ ││
│ │ DAY 1: ││
│ │ API spec agreed ────→ Mock server deployed ││
│ │ ││
│ │ DAY 2-10: ││
│ │ ┌────────────────┐ ┌────────────────┐ ││
│ │ │ Frontend │ │ Backend │ ││
│ │ │ │ │ │ ││
│ │ │ Builds against │ │ Implements │ ││
│ │ │ mock API │ │ real API │ ││
│ │ │ │ │ │ ││
│ │ └───────┬────────┘ └───────┬────────┘ ││
│ │ │ │ ││
│ │ │ Uses mock │ Matches spec ││
│ │ │ │ ││
│ │ ▼ ▼ ││
│ │ DAY 11: Integration ││
│ │ ││
│ │ Frontend ─────────────→ Real Backend ││
│ │ (switch from mock) ││
│ │ ││
│ │ RESULT: Both complete, integration smooth ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ MOCK CONFIG: │
│ ─────────── │
│ Development: Use mock server │
│ Staging: Use real backend │
│ Production: Use real backend │
└─────────────────────────────────────────────────────────────┘
Contract Testing
Ensuring Compatibility
CONTRACT TESTING:
┌─────────────────────────────────────────────────────────────┐
│ │
│ THE PROBLEM: │
│ ──────────── │
│ Backend changes API slightly │
│ Frontend doesn't know │
│ Production breaks │
│ │
│ THE SOLUTION: │
│ ───────────── │
│ Contract tests verify both sides match the spec │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ CONTRACT TEST APPROACHES: │
│ │
│ PROVIDER TESTING: │
│ Test that backend matches spec │
│ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ test('POST /orders matches spec', () => { ││
│ │ const response = api.post('/orders', validOrder); ││
│ │ expect(response).toMatchOpenAPISpec('/orders'); ││
│ │ }); ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ CONSUMER TESTING: │
│ Test that frontend expectations match spec │
│ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ test('checkout expects order response', () => { ││
│ │ const expectations = checkout.getApiExpectations(); ││
│ │ expect(expectations).toBeValidAgainstSpec(); ││
│ │ }); ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ TOOLS: │
│ • Pact (consumer-driven contracts) │
│ • Dredd (test API against spec) │
│ • Spectral (lint OpenAPI specs) │
│ │
│ IN CI: │
│ ───── │
│ PR to backend → Contract tests run → Block if breaking │
│ │
│ Prevents accidental breaking changes │
└─────────────────────────────────────────────────────────────┘
Versioning APIs
Managing Changes
API VERSIONING:
┌─────────────────────────────────────────────────────────────┐
│ │
│ VERSIONING STRATEGIES: │
│ ────────────────────── │
│ │
│ URL PATH: │
│ /v1/orders │
│ /v2/orders │
│ Clear, explicit, easy to route │
│ │
│ HEADER: │
│ X-API-Version: 2 │
│ Accept: application/vnd.api.v2+json │
│ Cleaner URLs, more complex │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ BREAKING VS NON-BREAKING: │
│ │
│ NON-BREAKING (no new version needed): │
│ ✅ Adding new optional field │
│ ✅ Adding new endpoint │
│ ✅ Adding new optional query param │
│ │
│ BREAKING (needs new version): │
│ ❌ Removing field │
│ ❌ Changing field type │
│ ❌ Removing endpoint │
│ ❌ Changing required fields │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ DEPRECATION PROCESS: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ DEPRECATION: /v1/orders endpoint ││
│ │ ││
│ │ TIMELINE: ││
│ │ Jan 1: v2 released, v1 deprecated ││
│ │ Feb 1: Deprecation warnings in v1 responses ││
│ │ Mar 1: v1 returns 410 Gone ││
│ │ ││
│ │ COMMUNICATION: ││
│ │ • Changelog published ││
│ │ • Migration guide provided ││
│ │ • Consumers notified via email ││
│ │ • Deprecation header in responses ││
│ │ ││
│ │ MIGRATION SUPPORT: ││
│ │ • v1 → v2 mapping documented ││
│ │ • SDKs updated ││
│ │ • Test environment available ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘