Design-Driven APIs
Table of Contents
1. Overview
Design-driven API development, also known as API-first or contract-first design, prioritizes the API specification as the source of truth before any implementation begins. This approach uses tools like OpenAPI (formerly Swagger), RAML, or API Blueprint to define interfaces, enabling parallel development between frontend and backend teams, automated documentation generation, and consistent API governance.
2. Background
Traditional API development often follows a code-first approach where implementations drive interface design. This leads to inconsistent APIs, poor documentation, and integration friction. The API-first movement emerged from the recognition that APIs are products with their own lifecycle, requiring upfront design consideration similar to user interfaces.
The rise of microservices architecture amplified the need for well-designed APIs, as service boundaries became contractual interfaces between teams. OpenAPI 3.0+ has become the de facto standard for RESTful API specification, while GraphQL and gRPC offer alternative paradigms with their own schema-first workflows.
3. Key Concepts
3.1. OpenAPI Specification Structure
OpenAPI 3.1.0 was released 2021-02-15 (openapis.org changelog), three years after this note's 2018-03-01 date. The version current at the time was 3.0.0, released 2017-07-26. Corrected the example and #+DESCRIPTION from 3.1.0 to 3.0.0.
openapi: 3.0.0
info:
title: Example API
version: 1.0.0
description: A design-first API example
paths:
/users/{userId}:
get:
operationId: getUser
summary: Retrieve a user by ID
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: User not found
components:
schemas:
User:
type: object
required:
- id
- email
properties:
id:
type: string
format: uuid
email:
type: string
format: email
name:
type: string
3.2. Design Principles
3.2.1. Resource-Oriented Design
- Model APIs around resources (nouns), not actions (verbs)
- Use HTTP methods semantically: GET (read), POST (create), PUT/PATCH (update), DELETE (remove)
- Design resource hierarchies that reflect domain relationships
3.2.2. Consistency Patterns
- Standardize naming conventions (camelCase vs snake_case)
- Use consistent pagination, filtering, and sorting patterns
- Establish error response formats across all endpoints
3.2.3. Versioning Strategies
- URL path versioning:
/v1/users - Header versioning:
Accept: application/vnd.api+json;version=1 - Query parameter:
/users?version=1
3.3. API Governance
Establish organizational standards through:
- Style guides documenting naming, structure, and behavior conventions
- Automated linting with tools like speccy
- API review processes before specification approval
- Centralized API catalogs for discoverability
4. Implementation
4.1. Design Workflow
- Requirements gathering: Document use cases and consumer needs
- Schema design: Create OpenAPI specification
- Review cycle: Stakeholder feedback and iteration
- Mock generation: Enable frontend development with Prism or similar
- Implementation: Backend development against the contract
- Validation: Automated contract testing
- Documentation: Generate from specification
4.2. Tooling Ecosystem
4.2.1. Specification Authoring
- Stoplight Studio - Visual OpenAPI editor
- Swagger Editor - Web-based editing
- VS Code with OpenAPI extensions
4.2.2. Code Generation
openapi-generator (the OpenAPITools fork of swagger-codegen) was created 2018-05-12 (per GitHub repo metadata), over two months after this note's 2018-03-01 date. The tool available at the time was swagger-codegen, which already shipped both the python-flask and typescript-axios generators. Corrected the tool name and CLI flags (-l, not -g) to match swagger-codegen's syntax.
# Generate server stubs
java -jar swagger-codegen-cli.jar generate -i spec.yaml -l python-flask -o ./server
# Generate client SDKs
java -jar swagger-codegen-cli.jar generate -i spec.yaml -l typescript-axios -o ./client
4.2.3. Mock Servers
# Prism mock server
prism mock spec.yaml
# Returns realistic mock data based on schema
curl http://localhost:4010/users/123
4.2.4. Linting and Validation
Spectral (Stoplight) was created 2018-08-15 (per GitHub repo metadata), over five months after this note's 2018-03-01 date. speccy, created 2018-01-31, was the OpenAPI linter available at the time. Corrected the governance bullet and CLI example from Spectral to speccy.
# speccy linting
speccy lint spec.yaml
4.3. Contract Testing
// Example with Dredd
// dredd.yml
hooks:
beforeEach: hooks.js
// Validate implementation matches specification
// dredd spec.yaml http://localhost:3000
5. References
6. Notes
- Start with consumer use cases, not internal data models
- Invest in API documentation as a product deliverable
- Consider Developer Experience (DX) as a primary metric
- Automated testing against specifications catches drift early
- API changelogs help consumers track breaking changes
- GraphQL and gRPC are schema-first by design, making contract-first natural