
Specification-Driven Development with OpenAPI
In a current real-world project, I follow a specification-first approach. An OpenAPI YAML spec acts as the single source of truth for both the implementation and the documentation. From this spec, I auto-generate:
- Java backend API controller interfaces and Data Transfer Objects (DTOs)
- TypeScript frontend API clients and models
- API documentation

The benefit of this setup groups into three main points:
- Clearer Design
- Automatic Sync
- Component Reuse
1. Clearer Design
By defining schemas, status codes, and validations upfront, the API becomes more robust and user-friendly. It encourages thinking from the user’s perspective early on—favoring top-down design over bottom-up.
2. Automatic Sync
Changes in the spec automatically update all generated code. Humans tend to forget some of the steps needed to make a change and may overlook updating a field or annotation… While checklists help, automation is both faster and more reliable for keeping everything in sync.
3. Component Reuse
Shared schemas and parameters in the spec are actually shared, always!
If you’ve ever worked with a third-party financial data provider, you’ve probably run into inconsistent representations across endpoints. One endpoint might return a percentage as “28.42%”, another as “0.2842”. This kind of inconsistency not only creates a poor developer experience—it can break consuming applications.
To prevent this, reusable components and parameters are centrally defined in a shared YAML spec. For instance, instead of duplicating domain models like Money and Currency, they are shared in a single spec for consistency across endpoints:
components:
parameters:
Currency:
name: currency
in: query
required: false
schema:
$ref: '#/components/schemas/Currency'
...
schemas:
Currency:
type: string
pattern: '^[A-Z]{3}$'
default: USD
Money:
type: object
required: [currency, amount]
properties:
currency:
$ref: '#/components/schemas/Currency'
amount:
type: number
...
More generic components should also be reused—such as BaseCollection, ErrorCode, or an RFC 7807-compliant ProblemDetail. Common responses like NotFound, Unauthorized, Forbidden, and TooManyRequests should also be shared.
Conclusion
In this architecture, the specification acts as the single source of truth. All downstream artifacts—code, documentation, other resources—derive from it.
I’m a big proponent of specification-driven and other top-down development approaches because they naturally promote higher code quality, clearer communication with stakeholders, and are massive time savers. It’s the next natural step in the evolution of software development. Think about it—how many people do you know who still write assembly professionally? The level of abstraction will just continue to rise over time.