An example project demonstrating API contract-first development using TypeSpec to define the contract, with code generation for both a Go server and TypeScript client.
This project showcases a workflow where:
- The API contract is defined in TypeSpec (
contract/main.tsp) - TypeSpec compiles to an OpenAPI 3.0 specification
- Go server code is generated from the OpenAPI spec using
oapi-codegen - TypeScript client is generated from the OpenAPI spec using
@hey-api/openapi-ts
.
├── contract/
│ └── main.tsp # TypeSpec API definition
├── cmd/
│ └── main.go # Go server implementation
├── generated/
│ ├── openapi.yaml # Generated OpenAPI spec
│ ├── api/
│ │ └── api.gen.go # Generated Go server code
│ └── ts-client/ # Generated TypeScript client
├── tspconfig.yaml # TypeSpec configuration
├── oapi-codegen.yaml # Go code generator configuration
├── openapi-ts.config.ts # TypeScript client generator configuration
└── Makefile # Build automation
Install the required dependencies:
make install-depsThis installs:
- TypeSpec compiler and HTTP/OpenAPI libraries
@hey-api/openapi-tsfor TypeScript client generationoapi-codegenfor Go server code generation
Edit contract/main.tsp to define your API. Example:
import "@typespec/http";
using Http;
model Store {
name: string;
address: Address;
}
model Address {
street: string;
city: string;
}
@route("/stores")
interface Stores {
list(@query filter: string): Store[];
read(@path id: string): Store;
@post create(@body store: Store): Store;
}Generate both OpenAPI spec and Go server code:
make generateGenerate only the TypeScript client:
make generate-ts-clientGenerate only the OpenAPI spec:
make openapigo run ./cmd/main.goThe server starts on http://localhost:8080.
Import and use the generated client in your TypeScript project:
import { ApiClient } from './generated/ts-client';
// List stores
const stores = await ApiClient.storesList({ query: { filter: 'coffee' } });
// Create a store
const newStore = await ApiClient.storesCreate({
body: {
name: 'Coffee Shop',
address: {
street: '123 Main St',
city: 'Seattle'
}
}
});
// Get a store by ID
const store = await ApiClient.storesRead({ path: { id: 'store-id' } });Configures TypeSpec to emit OpenAPI 3.0 spec to generated/openapi.yaml.
Configures Go code generation with:
- Echo server handlers
- Strict server interface (request/response objects)
- Model types
Configures TypeScript client generation with the @hey-api/sdk plugin.
Remove all generated files:
make clean- TypeSpec - API definition language
- oapi-codegen - Go code generator for OpenAPI
- @hey-api/openapi-ts - TypeScript client generator
- Echo - Go web framework