In the JavaScript/TypeScript ecosystem, tools like tRPC and oRPC are gaining traction. This isn’t by chance, it signals a growing need in the JS world: moving beyond the Developer Experience imposed by OpenAPI’s schema-first approach. But why?
All OpenAPI Code Generators Are Broken
With the help of Gen-AI, I'm building a tool to generate TypeScript code from OpenAPI specs. Fighting against the standard, I uncovered a systemic issue:
All existing code generators are unreliable, and it couldn’t be otherwise.
OpenAPI specs are unnecessarily complex, creating a chaotic mess for anyone trying to automate code generation. Here’s why.
Error Handling Chaos
Error handling in OpenAPI requires a sisyphean effort. You must manually map different layers: network errors (failed fetch
), server errors (5xx
), client errors (4xx
), and payload serialization/deserialization issues.
Each status code - (ie. 404
returning nothing, 429
providing retry parameters, 400
delivering unpredictable serialization errors, ...) may (or not) come with a payload in wildly different formats with disconnected meanings.
Therefore, a client generator cannot merely "implement retries": users must handle all this logic themselves by interpreting the returned data.
Serialization Nightmare
Take parameter serialization (ie. style
and explode
). You can send textual data to an endpoint in seven different ways with the same outcome. This redundancy is there for legacy reasons, pointless and breeds ambiguity everywhere.
JSON Schema Quirks
JSON Schema is a minefield of edge cases. For example, you can have an allOf intersection with and empty object that specifies a list of required fields without any schema attached.
SomeSchema:
allOf:
- $ref: "#/components/schemas/SomeOtherSchema"
- $ref: "#/components/schemas/SomeOtherSchemaAgain"
- type: object
required: [foo]
The generator implementation must traverse all fields of all objects in the intersection, only to mark as required - if any - those referenced by this empty object. Guess what? No know tool handles this.
Wildcard Complexity
Generators must handle vague cases like range status codes (e.g., 4XX
, 5XX
, ...) alongside the "default
" case, adding yet another layer of complexity that’s nearly impossible to manage keeping a good DX.
A Challenge
With so many intersections and details, no tool can handle every scenario. TypeScript developers today are working with tools that are merely "good enough," if that’s even sufficient.
What’s the point of a spec if its core purpose - automatic code generation - is inherently flawed?
All existing TypeScript generators are approximate at best. You can verify this yourself against a valid OpenAPI spec.
Try find a generator that correctly handles:
- Different schemas for multiple
2xx
responses - Different schemas per content type
- Default responses
- Range status codes
- Intersections with empty objects
- Self references
Time to Rethink the Paradigm
Recently, I came across the Cap'n Web protocol from Cloudflare, and it clearly demonstrates a unified approach that delivers a DX unthinkable with OpenAPI.
OpenAPI solves problems that shouldn’t exist in the first place. The schema-first approach is doomed to deliver a subpar DX. It's so poor that Microsoft decided to implement its own alternative DSL just to produce OpenAPI specs. Entire commercial companies have their core product built around being a decent OpenAPI code generator (!).
For a new project - especially internal services - I would rather lean towards DX-friendly alternatives like modern RPC protocols or a code-first approach where the API specification is generated directly from the source code.
Are you using OpenAPI for internal APIs, or have you switched to something more streamlined?
Top comments (0)