databuild/plans/webapp_v1/chunk-1-client-generation.md

4 KiB

Chunk 1: TypeScript Client Generation

Parent: Build Graph Dashboard
Next: Chunk 2: Hello World App

Overview

Generate TypeScript client code from the DataBuild protobuf definitions to provide type-safe API access for the dashboard.

Scope

In Scope

  • Generate TypeScript interfaces from databuild.proto
  • Create typed client for Build Graph Service HTTP API endpoints
  • Set up Bazel rules for protobuf-to-TypeScript generation
  • Implement simple custom protobuf-to-TypeScript tooling (if off-the-shelf solutions are complex)

Out of Scope

  • Full protobuf runtime features (only need type definitions)
  • Complex protobuf features (focus on basic message types)
  • Client-side validation (rely on server-side validation)

Technical Approach

OpenAPI-Based Generation

Generate TypeScript client from OpenAPI specification automatically derived from Build Graph Service:

Key API endpoints to generate TypeScript client for:

  • POST /api/v1/builds - Submit build request
  • GET /api/v1/builds/:id - Get build status
  • DELETE /api/v1/builds/:id - Cancel build request
  • GET /api/v1/partitions/:ref/status - Get partition status
  • GET /api/v1/partitions/:ref/events - Get partition events
  • POST /api/v1/analyze - Analyze build graph

Generated Client Structure

// Generated types from OpenAPI spec
interface BuildRequest {
  partitions: string[];
}

interface BuildStatusResponse {
  build_request_id: string;
  status: string;
  requested_partitions: string[];
  created_at: number;
  updated_at: number;
  events: BuildEventSummary[];
}

// Generated client class
class BuildGraphClient {
  constructor(baseUrl: string);
  
  async submitBuild(request: BuildRequest): Promise<{build_request_id: string}>;
  async getBuildStatus(id: string): Promise<BuildStatusResponse>;
  async cancelBuild(id: string): Promise<{cancelled: boolean}>;
  async getPartitionStatus(ref: string): Promise<PartitionStatusResponse>;
  async getPartitionEvents(ref: string): Promise<BuildEventSummary[]>;
  async analyzeGraph(request: AnalyzeRequest): Promise<AnalyzeResponse>;
}

Bazel Integration

  • Create //databuild/client:typescript target
  • Generate OpenAPI spec from Build Graph Service
  • Use OpenAPI Generator to create TypeScript client
  • Ensure hermetic build process
  • Output client code to databuild/client/typescript/

Implementation Strategy

  1. Add OpenAPI Generation to Service

    • Add aide dependency for OpenAPI spec generation
    • Modify Axum service to use aide::ApiRouter
    • Add JsonSchema derives to request/response types
    • Create OpenAPI spec endpoint
  2. OpenAPI Spec Extraction

    • Create Bazel rule to run service and extract OpenAPI spec
    • Save spec as build artifact (JSON/YAML)
  3. TypeScript Client Generation

    • Add OpenAPI Generator to Bazel build system
    • Create Bazel rule to generate TypeScript client from spec
    • Use typescript-fetch generator for modern fetch-based client
  4. Bazel Rules

    • Create typescript_openapi_library rule
    • Generate client code during build
    • Ensure proper dependency management

Deliverables

  • OpenAPI spec generation from Build Graph Service
  • TypeScript interfaces for all API request/response types
  • Typed HTTP client for Build Graph Service endpoints
  • Bazel rules for automated client generation
  • Documentation for using the generated client

Success Criteria

  • OpenAPI spec accurately reflects all service endpoints
  • Generated TypeScript compiles without errors
  • Client provides type safety for all API endpoints
  • Bazel build integrates seamlessly and generates client automatically
  • Ready for use in Chunk 2 (Hello World App)

Testing

  • Verify OpenAPI spec generation from service
  • Verify generated TypeScript compiles
  • Test client against running Build Graph Service
  • Validate type safety with TypeScript compiler
  • Ensure build process is hermetic and reproducible