How the Proto-First API Contract System Generates TypeScript Clients and OpenAPI Docs in World Monitor
The proto-first API contract system in koala73/worldmonitor uses buf generate with three custom sebuf protoc plugins to transform Protocol Buffer definitions into typed TypeScript clients, server interfaces, and OpenAPI 3.1 specifications from a single source of truth.
The koala73/worldmonitor repository implements a proto-first API contract system that elevates Protocol Buffer schemas to the canonical source for all API artifacts. By defining services, messages, and HTTP bindings in .proto files, the system automatically generates type-safe client libraries and comprehensive API documentation through an automated build pipeline.
The Proto-First Architecture
Single Source of Truth in Proto Definitions
All public API contracts reside in the proto/ directory, following the convention proto/worldmonitor/<service>/v<version>/service.proto. These files contain:
- Message schemas with
buf.validatefield constraints (e.g., latitude ∈ [-90, 90]) that enable automatic request validation - Service definitions declaring RPC methods with their input and output types
Sebuf HTTP Annotations and Validation
The system extends standard protobuf with custom sebuf HTTP annotations (option (sebuf.http) = {...}) that specify:
- HTTP method mappings (typically POST)
- Endpoint paths
- Request/response body schemas
- Example payloads for documentation
These annotations bridge the gap between protobuf's binary RPC model and RESTful HTTP APIs, while buf.validate constraints ensure field-level validation rules propagate to all generated artifacts.
The Generation Pipeline
Build Configuration and Plugins
The generation process centers on proto/buf.gen.yaml, which configures three custom sebuf protoc plugins:
plugins:
- local: protoc-gen-ts-client
out: ../src/generated/client
opt:
- paths=source_relative
- local: protoc-gen-ts-server
out: ../src/generated/server
opt:
- paths=source_relative
- local: protoc-gen-openapiv3
out: ../docs/api
- local: protoc-gen-openapiv3
out: ../docs/api
opt:
- format=json
The first two plugins generate TypeScript source files, while the third produces both YAML and JSON OpenAPI specifications.
Makefile Automation
The Makefile target (lines 55-58) orchestrates the build:
generate: clean ## Generate code from proto definitions
@mkdir -p $(GEN_CLIENT_DIR) $(GEN_SERVER_DIR) $(DOCS_API_DIR)
cd $(PROTO_DIR) && buf generate
@echo "Code generation complete!"
Running make generate executes buf generate, which reads the configuration and invokes the plugin chain to populate:
src/generated/client/– Typed client classessrc/generated/server/– Handler interfacesdocs/api/– OpenAPI specifications
TypeScript Client Generation
Fetch-Based Client Architecture
The protoc-gen-ts-client plugin generates thin, fetch-based client classes that wrap RPC methods. Each generated method:
- Accepts strongly-typed request objects derived from protobuf message schemas
- Serializes the request to the appropriate format
- POSTs to the HTTP endpoint defined by
sebufannotations - Deserializes the response into typed TypeScript objects
Practical Implementation Example
For the Wildfire service defined in proto/worldmonitor/wildfire/v1/service.proto, the generated client resides at src/generated/client/worldmonitor/wildfire/v1/service_client.ts:
import { WildfireServiceClient } from '@/generated/client/worldmonitor/wildfire/v1/service_client';
// Initialise with the global fetch implementation (or a custom wrapper)
const client = new WildfireServiceClient(fetch);
// Call an RPC – listFireDetections returns a typed response object
const resp = await client.listFireDetections({
cursor: '',
region: 'Ukraine',
minConfidence: 'FIRE_CONFIDENCE_HIGH',
});
console.log('Detected fires:', resp.detections);
The listFireDetections method accepts a ListFireDetectionsRequest type and returns Promise<ListFireDetectionsResponse>, ensuring compile-time validation of request parameters and response handling.
OpenAPI Documentation Generation
Dual-Format Specification Output
The protoc-gen-openapiv3 plugin emits OpenAPI 3.1 specifications in two formats:
- YAML (
docs/api/WildfireService.openapi.yaml) for human readability and Swagger UI integration - JSON (
docs/api/WildfireService.openapi.json) for machine consumption and automated tooling
Both formats derive from the same sebuf HTTP annotations and protobuf schemas, ensuring documentation accuracy.
OpenAPI Schema Structure
The generated specifications map protobuf services to RESTful paths with complete schema definitions:
openapi: 3.1.0
info:
title: WildfireService API
version: 1.0.0
paths:
/api/wildfire/v1/list-fire-detections:
post:
summary: ListFireDetections
operationId: ListFireDetections
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ListFireDetectionsRequest'
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListFireDetectionsResponse'
components:
schemas:
ListFireDetectionsRequest:
type: object
properties:
cursor:
type: string
region:
type: string
minConfidence:
type: string
enum:
- FIRE_CONFIDENCE_UNSPECIFIED
- FIRE_CONFIDENCE_LOW
- FIRE_CONFIDENCE_NOMINAL
- FIRE_CONFIDENCE_HIGH
Because these files live under version control in docs/api/, consumers can access accurate, up-to-date documentation without additional build steps.
Contract Safety and Validation
The repository maintains API integrity through automated validation tooling. The buf lint command enforces protobuf style conventions, while buf breaking (invoked via make breaking) analyzes changes against the main branch to detect backward-incompatible modifications—such as field number changes or type alterations—before they merge.
This validation ensures that the proto-first API contract system never silently breaks consumer contracts. When combined with version-controlled generated artifacts, the system guarantees that TypeScript clients, server interfaces, and OpenAPI documentation reflect exactly the same contract state.
Quick Implementation Guide
For developers consuming the API, integration requires only three steps:
import { TradeServiceClient } from '@/generated/client/worldmonitor/trade/v1/service_client';
// 1️⃣ Create the client
const tradeClient = new TradeServiceClient(fetch);
// 2️⃣ Call an RPC (example: GetTariffTrends)
const trends = await tradeClient.getTariffTrends({
reportingCountry: '840', // US ISO‑numeric
productSector: '01', // HS chapter
years: 5,
});
// 3️⃣ Use the typed response
console.log('Tariff trend points:', trends.datapoints);
This pattern applies identically across all World Monitor services, from Wildfire detection to Trade analytics, ensuring consistent developer experience throughout the koala73/worldmonitor ecosystem.
Summary
- The proto-first API contract system treats Protocol Buffer schemas as the canonical source for all API artifacts in koala73/worldmonitor.
- Three custom
sebufprotoc plugins (protoc-gen-ts-client,protoc-gen-ts-server,protoc-gen-openapiv3) generate TypeScript clients, server interfaces, and OpenAPI 3.1 specifications viabuf generate. - Generated TypeScript clients reside in
src/generated/client/and provide thin, fetch-based wrappers with compile-time type safety for RPC methods defined in.protofiles likeproto/worldmonitor/wildfire/v1/service.proto. - OpenAPI documentation generates as both YAML and JSON to
docs/api/, remaining synchronized with the implementation because all artifacts derive from the same protobuf contracts. - Automated tooling (
buf lint,buf breaking) enforces contract safety, while version-controlled generated artifacts prevent drift between documentation and implementation.
Frequently Asked Questions
What is a proto-first API contract system?
A proto-first API contract system is an architectural pattern where Protocol Buffer (protobuf) definitions serve as the single source of truth for all API-related artifacts. In koala73/worldmonitor, .proto files containing service definitions, message schemas, and HTTP annotations automatically generate TypeScript client libraries, server handler interfaces, and OpenAPI documentation through the buf generate pipeline, ensuring perfect synchronization between code and documentation.
How does buf generate TypeScript clients from protobuf definitions?
The buf generate command reads proto/buf.gen.yaml to invoke the custom protoc-gen-ts-client plugin. This plugin processes the protobuf service definitions and sebuf HTTP annotations to emit fetch-based TypeScript classes to src/generated/client/. Each RPC method becomes a typed class method that serializes protobuf messages, POSTs to the annotated HTTP endpoint, and deserializes responses into TypeScript types, as implemented in files like src/generated/client/worldmonitor/wildfire/v1/service_client.ts.
What are sebuf HTTP annotations used for?
sebuf HTTP annotations are custom protobuf options that map RPC methods to RESTful HTTP endpoints. Defined within .proto files using option (sebuf.http) = {...}, these annotations specify HTTP methods (typically POST), URL paths, request/response body schemas, and example payloads. The sebuf protoc plugins read these annotations to generate HTTP-compatible TypeScript clients and OpenAPI 3.1 specifications, effectively bridging protobuf's binary protocol with web-based REST APIs.
How are breaking changes detected in the API contracts?
The repository employs buf breaking, executed via make breaking, to compare proposed changes against the main branch before merging. This command analyzes .proto files for backward-incompatible modifications such as field number changes, type alterations, or required field additions that would break existing clients. Combined with buf lint for style enforcement, this validation ensures that the proto-first API contract system maintains backward compatibility or explicitly versions breaking changes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →