6.6 KiB
Chunk 1: TypeScript Client Generation
Parent: Build Graph Dashboard
Next: Chunk 2: Hello World App
Overview
Generate TypeScript client code from the DataBuild Build Graph Service OpenAPI specification to provide type-safe API access for the dashboard.
Scope
In Scope
- Generate OpenAPI specification from Build Graph Service using aide
- Create typed TypeScript client from OpenAPI spec using OpenAPI Generator
- Set up Bazel rules for OpenAPI-to-TypeScript generation
- Implement path parameter structs for proper aide OpenAPI generation
- CLI-based OpenAPI spec extraction
Out of Scope
- HTTP-based spec extraction (use CLI flag instead)
- External Bazel modules (use OpenAPI Generator JAR directly)
- Custom operation IDs (use auto-generated method names)
- 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 requestGET /api/v1/builds/:id- Get build statusDELETE /api/v1/builds/:id- Cancel build requestGET /api/v1/partitions/:ref/status- Get partition statusGET /api/v1/partitions/:ref/events- Get partition eventsPOST /api/v1/analyze- Analyze build graph
Generated Client Structure
// Generated types from OpenAPI spec (auto-generated models)
export * from './AnalyzeRequest';
export * from './BuildRequest';
export * from './BuildStatusResponse';
export * from './PartitionStatusResponse';
// ... all other model types
// Generated client API with auto-generated method names
export class DefaultApi {
constructor(configuration?: Configuration);
// Auto-generated method names from OpenAPI paths
async apiV1BuildsPost(requestParameters: ApiV1BuildsPostRequest): Promise<BuildRequestResponse>;
async apiV1BuildsIdGet(requestParameters: ApiV1BuildsIdGetRequest): Promise<BuildStatusResponse>;
async apiV1BuildsIdDelete(requestParameters: ApiV1BuildsIdDeleteRequest): Promise<any>;
async apiV1PartitionsRefStatusGet(requestParameters: ApiV1PartitionsRefStatusGetRequest): Promise<PartitionStatusResponse>;
async apiV1PartitionsRefEventsGet(requestParameters: ApiV1PartitionsRefEventsGetRequest): Promise<PartitionEventsResponse>;
async apiV1AnalyzePost(requestParameters: ApiV1AnalyzePostRequest): Promise<AnalyzeResponse>;
}
// Type-safe request parameter interfaces
export interface ApiV1BuildsPostRequest {
buildRequest: BuildRequest;
}
export interface ApiV1BuildsIdGetRequest {
id: string;
}
Bazel Integration
- Create
//databuild/client:typescripttarget - Extract OpenAPI spec using CLI flag
--print-openapi-spec - Use OpenAPI Generator JAR to create TypeScript client
- Ensure hermetic build process with JAR download
- Output client code to
databuild/client/typescript_generated/
Path Parameter Requirements
For aide to properly generate OpenAPI path parameters, all path parameters must be wrapped in structs:
#[derive(Deserialize, JsonSchema)]
pub struct BuildStatusRequest {
pub id: String,
}
pub async fn get_build_status(
Path(request): Path<BuildStatusRequest>
) -> Result<Json<BuildStatusResponse>, ...> {
// Use request.id instead of direct string
}
Implementation Strategy
-
✅ Add OpenAPI Generation to Service
- ✅ Add
aidedependency for OpenAPI spec generation - ✅ Modify Axum service to use
aide::ApiRouter - ✅ Add JsonSchema derives to request/response types
- ✅ Add path parameter structs for proper aide integration
- ✅ Create CLI flag
--print-openapi-specfor spec generation
- ✅ Add
-
✅ OpenAPI Spec Extraction
- ✅ Create Bazel rule using CLI flag instead of HTTP endpoint
- ✅ Extract spec using
build_graph_service --print-openapi-spec - ✅ Save spec as build artifact (JSON)
-
✅ TypeScript Client Generation
- ✅ Use OpenAPI Generator JAR directly (not Bazel module)
- ✅ Create Bazel rule to generate TypeScript client from spec
- ✅ Use
typescript-fetchgenerator for modern fetch-based client - ✅ Configure with camelCase naming and single request parameters
-
✅ Bazel Rules
- ✅ Create
//databuild/client:typescript_clienttarget - ✅ Generate client code during build with proper file copying
- ✅ Ensure hermetic build with JAR download
- ✅ Create
Deliverables
- OpenAPI spec generation from Build Graph Service via CLI flag
- TypeScript interfaces for all API request/response types (auto-generated)
- Typed HTTP client for Build Graph Service endpoints with fetch API
- Bazel rules for automated client generation using OpenAPI Generator JAR
- Path parameter struct implementation for aide compatibility
Success Criteria
- ✅ OpenAPI spec accurately reflects all service endpoints with proper path parameters
- ✅ Generated TypeScript compiles without errors using
typescript-fetchgenerator - ✅ Client provides type safety for all API endpoints with auto-generated method names
- ✅ Bazel build integrates seamlessly and generates client automatically
- ✅ Path parameter structs enable proper aide OpenAPI generation
- ✅ Ready for use in Chunk 2 (Hello World App)
Testing
- ✅ Verify OpenAPI spec generation from service using CLI flag
- ✅ Verify generated TypeScript compiles without errors
- ✅ Validate OpenAPI spec passes OpenAPI Generator validation
- ✅ Ensure build process is hermetic and reproducible with JAR download
- ✅ Verify all API endpoints generate proper TypeScript method signatures
- ✅ Confirm path parameters are properly typed in generated client
Implementation Notes
Lessons Learned
-
aide Path Parameter Requirements: aide requires path parameters to be wrapped in structs with
JsonSchemaderives, not simplePath<String>extractors. -
OpenAPI Generator Bazel Integration: The official Bazel module was not available in registry, so we used the JAR directly via genrule for better reliability.
-
CLI vs HTTP Extraction: Using a CLI flag for spec extraction is simpler and more reliable than starting an HTTP server.
-
Auto-generated Method Names: Without custom operationIds, OpenAPI Generator creates method names like
apiV1BuildsPost. This can be improved in future iterations.
Build Targets
//databuild/client:extract_openapi_spec- Extracts OpenAPI spec JSON//databuild/client:typescript_client- Generates TypeScript client//databuild/client:typescript- Main target for consuming the client