TL;DR
Design-first API development means you write the API specification before implementation code. The spec becomes the source of truth for mocks, documentation, tests, and generated client/server code. This article shows how to run a practical design-first workflow and what to look for in tooling, using Apidog as an example of an end-to-end design-first platform.
Apidog is a free, all-in-one API development platform built for design-first workflows: visual OpenAPI editing, automatic mock generation from specs, real-time documentation preview, and team review. Try Apidog free, no credit card required.
Introduction
Most developers start with a code-first API workflow:
- Write a route.
- Add annotations.
- Generate docs.
- Hope the docs stay accurate.
That works for small projects, but it often breaks down as teams grow.
The common failure mode is documentation drift. A backend engineer changes a response shape but forgets to update the annotation. Months later, the docs say the API returns this:
["active", "inactive"]
But the real response looks like this:
[
{ "value": "active" },
{ "value": "inactive" }
]
Design-first flips the workflow.
Instead of generating the spec from code, you write the spec first. Then mocks, docs, tests, and client stubs are derived from that spec.
The goal is simple:
OpenAPI spec -> mocks
OpenAPI spec -> documentation
OpenAPI spec -> tests
OpenAPI spec -> generated clients/stubs
When the spec changes, every downstream artifact can update from the same contract.
For this to work in practice, the tooling must make spec authoring fast. If defining an endpoint in your API tool takes 20 minutes but writing the route handler takes 5, the team will skip the tool. A good design-first platform must make the contract-first workflow easier than maintaining docs manually.
What design-first means in practice
Design-first is not just “write OpenAPI.” It is a development workflow where the API contract is agreed on before implementation.
A practical design-first flow looks like this:
Design API contract
↓
Review contract with frontend/backend/product
↓
Publish mock server
↓
Frontend builds against mock
Backend implements against spec
↓
Validate implementation against spec
↓
Update spec first when requirements change
Before writing implementation code
Define the API contract as an OpenAPI spec.
At minimum, include:
- Endpoint paths and HTTP methods
- Path, query, and header parameters
- Request body schemas
- Response schemas for success and error states
- Authentication requirements
- Field descriptions
- Realistic examples
Example:
openapi: 3.0.3
info:
title: "User API"
version: 1.0.0
paths:
/users/{id}:
get:
summary: Get a user by ID
parameters:
- name: id
in: path
required: true
schema:
type: string
example: usr_123
responses:
"200":
description: "User found"
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"404":
description: "User not found"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
User:
type: object
required:
- id
- email
- name
properties:
id:
type: string
example: usr_123
email:
type: string
format: email
example: user@example.com
name:
type: string
example: Jane Doe
Error:
type: object
required:
- code
- message
properties:
code:
type: string
example: USER_NOT_FOUND
message:
type: string
example: User not found
This is where important API decisions should happen:
- Resource naming
- Status codes
- Error format
- Pagination shape
- Authentication rules
- Field naming conventions
- Backward compatibility concerns
During development
Publish the spec to a mock server.
Frontend engineers can start building immediately against stable mock responses. Backend engineers implement against the same spec as their requirements document.
Example frontend usage:
const response = await fetch("https://mock.example.com/users/usr_123");
if (!response.ok) {
throw new Error("Failed to fetch user");
}
const user = await response.json();
console.log(user.email);
The frontend does not need to wait for the backend to finish the endpoint.
After implementation
Run automated tests that verify the real API matches the OpenAPI contract.
For example, a contract test should fail if the spec says email is required but the implementation omits it:
{
"id": "usr_123",
"name": "Jane Doe"
}
This response should fail validation because email is missing.
When requirements change
Update the spec first.
Then:
- Review the contract change.
- Update mocks.
- Update frontend implementation.
- Update backend implementation.
- Run validation tests.
Do not silently change the backend response and update the spec later. That turns the spec back into documentation instead of a contract.
What a design-first platform needs
Not every API tool supports design-first development well. A useful platform should support the full lifecycle from contract design to validation.
1. Visual API editor
Writing raw YAML is fine for small changes, but it is not ideal for collaborative design.
A good visual editor should let you define:
- Paths
- Methods
- Parameters
- Request bodies
- Response schemas
- Reusable components
- Examples
- Validation rules
It should also generate valid OpenAPI behind the scenes.
2. OpenAPI validation
The spec should be valid before you use it to generate mocks, docs, or code.
Validation should catch issues like:
- Missing response descriptions
- Invalid schema references
- Incorrect parameter locations
- Invalid enum values
- Broken
$reflinks
Example of a broken reference:
schema:
$ref: "#/components/schemas/UserProfile"
If UserProfile does not exist under components.schemas, the editor should flag it immediately.
3. Automatic mock generation
A design-first workflow needs instant mocks.
The basic rule should be:
Save spec -> get mock endpoint
Mock data should respect schema definitions such as:
typeformatenumminimummaximum- nested objects
- arrays
- reusable
$refcomponents
For example, this schema:
status:
type: string
enum:
- active
- inactive
- suspended
Should produce one of the allowed values, not arbitrary text.
4. Documentation preview
The OpenAPI spec should render into readable API documentation.
During design review, stakeholders should be able to inspect:
- Endpoint purpose
- Required parameters
- Request examples
- Response examples
- Error codes
- Field descriptions
This is useful before implementation starts because unclear documentation usually means the contract is unclear too.
5. Team review workflow
Design-first API changes should be reviewed like code changes.
A useful review workflow should support:
- Comments on endpoints
- Comments on fields
- Change history
- Reviewer feedback
- Async collaboration
This prevents API contracts from changing without frontend, backend, or product visibility.
6. Standard OpenAPI export
The spec must remain portable.
You should be able to export standard OpenAPI and use it with tools like:
- Code generators
- API gateways
- Testing frameworks
- Documentation sites
- SDK generators
- CI validation tools
Example with openapi-generator:
openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-fetch \
-o ./generated/user-api-client
Or generate server stubs:
openapi-generator-cli generate \
-i openapi.yaml \
-g nodejs-express-server \
-o ./generated/server
Apidog as a design-first platform
Apidog is built around the API specification as the primary artifact. The design editor, mock server, test runner, and documentation are connected to the same API definition.
Visual OpenAPI editor
Apidog’s design interface uses structured forms instead of requiring you to write raw YAML.
For each endpoint, you can define:
- Path
- HTTP method
- Parameters
- Request body
- Response schemas
- Field descriptions
- Validation rules
- Mock behavior
You can still edit the raw OpenAPI JSON/YAML if you prefer. Changes made visually and changes made in raw mode stay synced.
Reusable schema components are also supported. For example, you can define a UserProfile schema once and reuse it across multiple endpoints with $ref.
components:
schemas:
UserProfile:
type: object
properties:
id:
type: string
displayName:
type: string
avatarUrl:
type: string
format: uri
Then reference it:
responses:
"200":
description: User profile
content:
application/json:
schema:
$ref: "#/components/schemas/UserProfile"
When you update the shared schema, every endpoint using it reflects the change.
Real-time documentation preview
As you design an endpoint, Apidog updates the documentation preview.
This helps you check whether the API is understandable before implementation starts.
Review the generated docs for:
- Ambiguous field names
- Missing examples
- Incomplete error responses
- Confusing descriptions
- Inconsistent schema patterns
If the docs are unclear, fix the spec before writing code.
Smart Mock: from spec to working mock
When you save an endpoint in Apidog’s designer, the mock server is available immediately.
The mock response is generated from the schema. For example:
-
format: emailreturns email-like values -
minimumandmaximumconstrain number values -
enumreturns allowed enum values - Nested objects follow the nested schema
- Arrays are generated from array item schemas
-
$refcomponents are resolved
Example schema:
User:
type: object
required:
- id
- email
- role
properties:
id:
type: string
example: usr_123
email:
type: string
format: email
role:
type: string
enum:
- admin
- member
- guest
Example mock response:
{
"id": "usr_123",
"email": "user@example.com",
"role": "member"
}
You can also configure custom mock behavior for specific cases, such as:
- Return
404whenid=0 - Return an empty list for a specific query
- Return a predefined payload for a known test user
Team review and change tracking
Apidog makes API spec changes visible to workspace members.
For a design-first workflow, use this to review:
- New endpoints
- Breaking response changes
- Error format changes
- Authentication changes
- Removed or renamed fields
- Pagination behavior
This keeps API design decisions in the same review culture as code.
Design-first vs. code-first: trade-offs
Design-first is useful, but it is not always the best choice.
Design-first advantages
- Frontend and backend can work in parallel
- Mocks are available before backend implementation
- Documentation stays aligned with the contract
- Integration issues surface earlier
- API changes are explicit and reviewable
- Contract tests can verify implementation behavior
Design-first disadvantages
- Requires upfront spec work
- Requires team discipline
- Spec tooling has a learning curve
- Early over-specification can slow discovery
- Implementation must be kept aligned with the contract
Code-first advantages
- Faster for small experiments
- Lower process overhead
- Natural for solo development
- No separate spec design step
Code-first disadvantages
- Documentation is secondary and can drift
- Frontend often waits for backend availability
- API contracts are less explicit
- Breaking changes are harder to detect
- Refactoring requires manual documentation updates
For multi-engineer teams, design-first usually pays off when frontend and backend work need to happen in parallel.
Tools that support design-first workflows
Apidog
Apidog provides a complete design-first workflow in one platform:
- Visual API editor
- OpenAPI-based design
- Instant mocking
- Documentation
- Testing
- Team review
Its mock generation is especially useful for teams that want frontend work to start before backend implementation is ready.
Stoplight Studio
Stoplight Studio is a strong OpenAPI editor with Spectral linting for style and governance rules. It is useful for teams that care heavily about API standards and consistency.
SwaggerHub
SwaggerHub is a mature OpenAPI editing and collaboration platform. It is widely used in enterprise environments and works well for organizations already using the Swagger ecosystem.
Postman with API Builder
Postman includes API design features and can generate OpenAPI specs. It can work for teams already using Postman collections, though design and collection workflows can feel separate.
Insomnia with document mode
Insomnia supports OpenAPI editing and basic mocking. It is a lightweight option for developers who want a simpler tool for working with API specs.
Setting up a design-first workflow in Apidog
Here is a practical workflow you can apply to a new feature.
Step 1: Start with the API design
Create a new project and open the design tab.
Before writing backend code, define:
- Endpoint path
- HTTP method
- Required parameters
- Success response
- Error responses
Example:
GET /users/{id}
Define at least these responses:
200 - user found
401 - unauthorized
404 - user not found
500 - server error
Step 2: Define shared components first
Before creating many endpoints, define reusable schemas.
Common shared components include:
ErrorResponsePaginationUserAddressAuthTokenValidationError
Example:
ErrorResponse:
type: object
required:
- code
- message
properties:
code:
type: string
example: VALIDATION_ERROR
message:
type: string
example: One or more fields are invalid
details:
type: array
items:
type: object
properties:
field:
type: string
issue:
type: string
This prevents every endpoint from inventing a different error format.
Step 3: Add realistic examples
Examples make mocks and docs more useful.
Instead of this:
{
"id": "string",
"email": "string"
}
Use this:
{
"id": "usr_123",
"email": "jane@example.com"
}
Good examples help frontend developers build realistic UI states earlier.
Step 4: Share the mock URL early
Once the endpoint is saved, copy the mock URL and share it with the frontend developer.
The frontend can integrate immediately:
type User = {
id: string;
email: string;
name: string;
};
async function getUser(id: string): Promise<User> {
const res = await fetch(`${API_BASE_URL}/users/${id}`);
if (!res.ok) {
throw new Error(`Failed to load user: ${res.status}`);
}
return res.json();
}
During early development, API_BASE_URL can point to the mock server. Later, it can point to the real backend.
Step 5: Review generated docs before coding
Open the documentation preview and review the endpoint as if you were a consumer of the API.
Check:
- Is the endpoint purpose clear?
- Are required fields marked correctly?
- Are nullable fields documented?
- Are all error cases included?
- Are examples realistic?
- Are field names consistent?
If something is unclear in the docs, fix the spec first.
Step 6: Lock the spec for implementation
After review, treat the spec as the sprint contract.
If implementation reveals that the API needs to change, update the spec first and review the change.
Avoid this pattern:
Backend changes response -> frontend breaks -> docs updated later
Use this instead:
Spec change proposed -> reviewed -> mock updated -> backend/frontend updated
Step 7: Validate responses in CI
Use API tests to verify that real responses match the spec.
At minimum, test:
- Status codes
- Required fields
- Field types
- Error response format
- Authentication behavior
Example contract expectations:
GET /users/usr_123
Expected: 200
Expected body:
id: string
email: string, email format
name: string
If the backend returns this:
{
"id": "usr_123",
"name": "Jane Doe"
}
The test should fail because email is missing.
FAQ
Is design-first only for REST APIs?
No. The design-first principle applies to any API style where you can define a contract.
Examples:
- REST with OpenAPI
- GraphQL schema-first development
- gRPC with protobuf
- Event-driven APIs with AsyncAPI
Apidog supports REST and GraphQL design. For gRPC, proto files serve a similar contract-first role.
Do we need to define every endpoint before development starts?
No.
You can adopt design-first at the feature level. Before building a feature, define the API contract for that feature.
This makes incremental adoption practical, even in a mostly code-first codebase.
How does design-first work with agile sprints?
Use the beginning of the sprint to design and review the API contract for that sprint’s features.
Then:
- Frontend builds against the mock
- Backend implements against the spec
- Tests verify the implementation
- Spec changes go through review
The API contract becomes part of sprint planning.
What if implementation needs to diverge from the spec?
Update the spec first.
Then review the change with the affected stakeholders, especially frontend developers. After the change is accepted, update the implementation.
The important rule is that the spec remains the source of truth.
Can we generate server stubs from Apidog’s OpenAPI export?
Yes. Export the spec from Apidog as OpenAPI 3.x and use a standard code generator.
Example:
openapi-generator-cli generate \
-i openapi.yaml \
-g spring \
-o ./generated/spring-server
Or for TypeScript:
openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-fetch \
-o ./generated/typescript-client
How should we handle spec versioning?
Use change history for normal iteration.
For major versions that must be maintained in parallel, such as v1 and v2, keep separate projects or branches so each contract can evolve independently.
Conclusion
Design-first API development works best when the spec is easy to create, review, mock, document, and test.
The practical workflow is:
- Define the OpenAPI contract first.
- Review it with the team.
- Generate mocks from the spec.
- Build frontend and backend in parallel.
- Validate the implementation against the contract.
- Update the spec before changing behavior.
The main challenge is discipline. The right tooling reduces that friction. Apidog’s visual editor, instant mocks, documentation preview, testing, and team collaboration features make the design-first workflow easier to adopt and maintain.
Top comments (0)