Update web app plan to use axum -> openapi -> typescript client

This commit is contained in:
Stuart Axelbrooke 2025-07-08 20:31:47 -07:00
parent 07cd3a3e8f
commit d1d1f2c8b6
2 changed files with 45 additions and 31 deletions

View file

@ -10,7 +10,7 @@
- Simplicity is absolutely critical here - Simplicity is absolutely critical here
- Use mithril - Use mithril
- Use typescript - Use typescript
- Rely on client generated from protobuf interface definitions - Rely on client generated from OpenAPI interface definitions
## Minimal Design ## Minimal Design
@ -166,7 +166,7 @@ Polling-based updates with Page Visibility API integration:
- Mithril: ~10KB - Mithril: ~10KB
- Custom code: ~20KB - Custom code: ~20KB
- CSS: ~5KB - CSS: ~5KB
- Protobuf client: ~15KB - OpenAPI client: ~15KB
### Data Flow ### Data Flow
@ -198,7 +198,7 @@ npm run typecheck
This dashboard implementation is broken into 9 incremental, testable chunks: This dashboard implementation is broken into 9 incremental, testable chunks:
### Phase 1: Foundation & Infrastructure ### Phase 1: Foundation & Infrastructure
- **[Chunk 1: TypeScript Client Generation](./webapp_v1/chunk-1-client-generation.md)** - Generate typed client from proto - **[Chunk 1: TypeScript Client Generation](./webapp_v1/chunk-1-client-generation.md)** - Generate typed client from OpenAPI spec
- **[Chunk 2: Hello World App](./webapp_v1/chunk-2-hello-world-app.md)** - Bazel-built TypeScript + Mithril app - **[Chunk 2: Hello World App](./webapp_v1/chunk-2-hello-world-app.md)** - Bazel-built TypeScript + Mithril app
- **[Chunk 3: Routing Framework](./webapp_v1/chunk-3-routing-framework.md)** - Multi-page routing and layout - **[Chunk 3: Routing Framework](./webapp_v1/chunk-3-routing-framework.md)** - Multi-page routing and layout

View file

@ -22,81 +22,95 @@ Generate TypeScript client code from the DataBuild protobuf definitions to provi
## Technical Approach ## Technical Approach
### Proto Analysis ### OpenAPI-Based Generation
Key messages to generate TypeScript for: Generate TypeScript client from OpenAPI specification automatically derived from Build Graph Service:
- `BuildEvent` and related event types
- `PartitionRef`, `JobLabel`, `GraphLabel` Key API endpoints to generate TypeScript client for:
- `BuildRequestStatus`, `PartitionStatus`, `JobStatus` - `POST /api/v1/builds` - Submit build request
- `JobGraph`, `Task`, `JobConfig` - `GET /api/v1/builds/:id` - Get build status
- Service request/response types - `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 Client Structure
```typescript ```typescript
// Generated types // Generated types from OpenAPI spec
interface PartitionRef { interface BuildRequest {
str: string; partitions: string[];
} }
interface BuildStatusResponse { interface BuildStatusResponse {
build_request_id: string; build_request_id: string;
status: BuildRequestStatus; status: string;
requested_partitions: string[]; requested_partitions: string[];
created_at: number; created_at: number;
updated_at: number; updated_at: number;
events: BuildEventSummary[]; events: BuildEventSummary[];
} }
// Client class // Generated client class
class BuildGraphClient { class BuildGraphClient {
constructor(baseUrl: string); constructor(baseUrl: string);
async submitBuild(partitions: string[]): Promise<{build_request_id: string}>; async submitBuild(request: BuildRequest): Promise<{build_request_id: string}>;
async getBuildStatus(id: string): Promise<BuildStatusResponse>; async getBuildStatus(id: string): Promise<BuildStatusResponse>;
async cancelBuild(id: string): Promise<{cancelled: boolean}>; async cancelBuild(id: string): Promise<{cancelled: boolean}>;
async getPartitionStatus(ref: string): Promise<PartitionStatusResponse>; async getPartitionStatus(ref: string): Promise<PartitionStatusResponse>;
async getPartitionEvents(ref: string): Promise<BuildEventSummary[]>; async getPartitionEvents(ref: string): Promise<BuildEventSummary[]>;
async analyzeGraph(partitions: string[]): Promise<{job_graph: JobGraph}>; async analyzeGraph(request: AnalyzeRequest): Promise<AnalyzeResponse>;
} }
``` ```
### Bazel Integration ### Bazel Integration
- Create `//databuild/client:typescript` target - Create `//databuild/client:typescript` target
- Generate TypeScript files from `.proto` sources - Generate OpenAPI spec from Build Graph Service
- Use OpenAPI Generator to create TypeScript client
- Ensure hermetic build process - Ensure hermetic build process
- Output client code to `databuild/client/typescript/` - Output client code to `databuild/client/typescript/`
## Implementation Strategy ## Implementation Strategy
1. **Assess Off-the-Shelf Solutions** 1. **Add OpenAPI Generation to Service**
- Quick evaluation of existing protobuf-to-TypeScript tools - Add `aide` dependency for OpenAPI spec generation
- If complex setup required, proceed with custom implementation - Modify Axum service to use `aide::ApiRouter`
- Add JsonSchema derives to request/response types
- Create OpenAPI spec endpoint
2. **Custom Generator (if needed)** 2. **OpenAPI Spec Extraction**
- Simple Python/Rust script to parse proto and generate TypeScript - Create Bazel rule to run service and extract OpenAPI spec
- Focus only on message types and basic field mapping - Save spec as build artifact (JSON/YAML)
- No complex protobuf features needed
3. **Bazel Rules** 3. **TypeScript Client Generation**
- Create `typescript_proto_library` rule - 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 - Generate client code during build
- Ensure proper dependency management - Ensure proper dependency management
## Deliverables ## Deliverables
- [ ] TypeScript interfaces for all relevant protobuf messages - [ ] OpenAPI spec generation from Build Graph Service
- [ ] TypeScript interfaces for all API request/response types
- [ ] Typed HTTP client for Build Graph Service endpoints - [ ] Typed HTTP client for Build Graph Service endpoints
- [ ] Bazel rules for client generation - [ ] Bazel rules for automated client generation
- [ ] Documentation for using the generated client - [ ] Documentation for using the generated client
## Success Criteria ## Success Criteria
- OpenAPI spec accurately reflects all service endpoints
- Generated TypeScript compiles without errors - Generated TypeScript compiles without errors
- Client provides type safety for all API endpoints - Client provides type safety for all API endpoints
- Bazel build integrates seamlessly - Bazel build integrates seamlessly and generates client automatically
- Ready for use in Chunk 2 (Hello World App) - Ready for use in Chunk 2 (Hello World App)
## Testing ## Testing
- Verify OpenAPI spec generation from service
- Verify generated TypeScript compiles - Verify generated TypeScript compiles
- Test client against running Build Graph Service - Test client against running Build Graph Service
- Validate type safety with TypeScript compiler - Validate type safety with TypeScript compiler
- Ensure build process is hermetic and reproducible