SDKs Build Themselves

Why writing a good API spec means you never have to write SDK code again. The client code writes itself.

By: Mr Uprizing

If my API has a good OpenAPI spec, I don't need to write the SDK at all. It can build itself.

The pattern we all recognize

You write an API. It needs a Node.js client. You write it. Then Python. You write it. Then a browser SDK. You write it. Every time you add a field, you update three codebases. Every time you change a parameter, you fix it everywhere. It works. But it's not sustainable.

code-editor

client.ts

// The old way: write the SDK by hand
class UserClient {
  async getUser(id: string) {
    const response = await fetch(`/users/${id}`)
    return response.json()
  }

  async createUser(data: unknown) {
    const response = await fetch('/users', {
      method: 'POST',
      body: JSON.stringify(data)
    })
    return response.json()
  }

  // ... repeat for every endpoint
}

This approach scales poorly. Not because it's hard. But because you're doing the same work multiple times. The contract between server and client is defined in three places instead of one. And they always drift.

The insight: your API is already documented

If you're using OpenAPI (like we discussed before), your API contract is already machine-readable. Every endpoint. Every parameter. Every response. It's all there.

code-editor

openapi.json

// Your OpenAPI spec (generated from Hono)
{
  "openapi": "3.0.0",
  "info": { "title": "User API", "version": "1.0.0" },
  "paths": {
    "/users/{id}": {
      "get": {
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/User" }
              }
            }
          }
        }
      }
    }
  }
}

Now here's the shift: instead of writing an SDK, you generate it. Tools like hey-api/openapi-ts and Speakeasy take your spec and build the entire client for you. Automatically.

The generated SDK is honest

code-editor

generated.ts

// Generated automatically from OpenAPI spec
import { createClient } from '@hey-api/openapi-ts'

const client = createClient({
  baseURL: 'https://api.example.com'
})

// Fully typed. No manual work.
const user = await client.users.getUser({ path: { id: '123' } })

You don't hand-write this. A generator does. And because it reads from your OpenAPI spec, it's always correct. It's always in sync. When you change your API, you regenerate. That's it.

No manual updates. No drift. No confusion about which version of the client matches which version of the server.

Different generators, same idea

Tools like hey-api/openapi-ts generate lightweight clients with minimal dependencies. Speakeasy generates fully-featured SDKs with built-in analytics, retries, and polish. They have different philosophies, but the principle is the same: the spec is the source of truth. The code comes after.

code-editor

setup.ts

// Using Speakeasy or hey-api/openapi-ts
// Point it at your OpenAPI endpoint
const client = new Client({
  apiKey: process.env.API_KEY,
  baseURL: 'https://api.example.com',
  serverURL: 'https://api.example.com/openapi.json'
})

// SDK is generated. Types are perfect. No hand-written code.
const result = await client.users.getUser('user-123')

You pick the tool that matches your taste. But you never hand-write boilerplate again.

What this means for your team

You write one good API. You document it properly (in code, via OpenAPI). Your backend team is done. Your frontend team? They generate a client and move on.

Need a Python SDK for data science? Generate it. Need a Go SDK for infrastructure? Generate it. Need to update the iOS app? Regenerate, ship.

The API is the contract. Everything else flows from it.

It's not magic. It's just honesty at scale.

SDK generators don't create anything you couldn't write by hand. They just do the boring work for you. And they do it perfectly because they read from a single source of truth.

When your API spec is honest, everything else becomes honest too. Your documentation is honest. Your clients are honest. Your types are honest.

That's the real power. Not automation for its own sake. But removing lies from your entire system.