DEV Community

Cover image for How OpenAPI Undermines a Good Developer Experience
D.S.
D.S.

Posted on

How OpenAPI Undermines a Good Developer Experience

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]
Enter fullscreen mode Exit fullscreen mode

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)