Skip to content

Conversation

@webjunkie
Copy link
Contributor

Problem

Frontend types for API responses are manually written in frontend/src/types.ts and scattered across the codebase. These often drift from what the backend actually returns, causing runtime errors and confusion. The correct flow should be: Django serializers → OpenAPI schema → TypeScript types.

Solution

Generate TypeScript types directly from Django serializers using drf-spectacular + orval. ViewSets opt-in by adding @extend_schema(tags=["product"]) decorator, and types are routed to the appropriate product folder.

How it works

  1. ViewSets opt-in via @extend_schema(tags=["product_name"])
  2. ./bin/build-openapi-schema.sh generates OpenAPI JSON
  3. node frontend/bin/generate-openapi-types.mjs slices schema by tag and generates types
  4. Output lands in products/{product}/frontend/api/index.ts or frontend/src/api/index.ts for core

Generated API client functions

As a bonus, orval also generates typed fetch functions wrapping our existing lib/api client. Nice to have, we'll see where it leads - the main value is the types themselves.

CI check

Added check to ensure generated types stay in sync. Generator also reports manual types that match generated ones, suggesting migration path.

Add tooling to generate TypeScript types from backend Django serializers
via OpenAPI schema. Uses orval to produce clean interfaces per product.

Flow:
1. `hogli build:openapi-schema` - generates OpenAPI JSON from drf-spectacular
2. `hogli build:openapi-types` - splits schema by explicit tags and runs orval

Types are routed to product folders based on `@extend_schema(tags=[...])`
decorator. The `x-explicit-tags` extension preserves explicit tags separate
from auto-derived ones.

Includes generated types for desktop_recordings, endpoints, and tasks as
examples.
Add custom orval mutator that wraps the existing `lib/api` module,
ensuring generated API clients use the same HTTP client (with CSRF,
auth, error handling) as the rest of the app.
The error_tracking viewset has scope_object="INTERNAL" which was
excluding it from the schema. Added OPENAPI_INCLUDE_INTERNAL=1 to
the schema generation since these types are for internal frontend use.
Clearer naming since it contains both types and client functions.
Add eslint-disable for console.log statements and show progress during
generation - slicing info, per-product stats (endpoints/schemas), and
final summary.
Show how tags are found (x-explicit-tags from @extend_schema), which
tags matched product folders vs skipped, and guidance on how to get
types generated for your own product.
Ensure generated TypeScript API clients stay in sync with backend
serializers. Runs schema generation + orval type generation and fails
if any files changed.
After generating API types, scan for manually-written types with the
same name in frontend/src. Helps identify types that were manually
added to circumvent lack of generated types and can now be replaced.
Reverse lookup: given manual TypeScript types in types.ts, find Django
serializers that could be tagged to auto-generate those types instead.

Run with: node frontend/bin/find-untagged-serializers.mjs
Add @extend_schema(tags=["product"]) decorators to ~45 ViewSets across
core, EE, and products to enable automatic TypeScript type generation.

Changes:
- Tag core ViewSets (user, cohort, dashboard, plugin, annotation, etc.)
- Tag EE ViewSets (billing, subscription, role, experiments, groups)
- Tag session recording and batch export ViewSets
- Tag product ViewSets (data warehouse, links, user interviews, etc.)
- Update generator to merge multiple tags into single output (core now
  includes session_recordings, hog_functions, billing, max)
- Improve generator output formatting with separators and alignment

Generates 12 API clients with 375+ endpoints total:
- core: 206 endpoints (merged from core, hog_functions, session_recordings)
- Products: batch_exports, data_warehouse, error_tracking, experiments,
  surveys, llm_analytics, endpoints, tasks, etc.
@wiz-7ad640923b
Copy link

wiz-7ad640923b bot commented Nov 27, 2025

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities -
Data Finding Sensitive Data 1 Medium 1 Low
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings -
Total 1 Medium 1 Low

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 27, 2025

Size Change: 0 B

Total Size: 3.41 MB

ℹ️ View Unchanged
Filename Size
frontend/dist/toolbar.js 3.41 MB

compressed-size-action

Separate schemas from functions:
- index.schemas.ts: type definitions only
- index.ts: fetch functions (imports from schemas)

Allows importing just types without pulling in runtime code.
- Exclude frontend/src/api and products/**/frontend/api from tsconfig
  (orval has enum ordering issues causing 'used before declaration' errors)
- Exclude same paths from oxlint (explicit-function-return-type errors)
- Use orval's built-in prettier option
- Use orval's default header
More explicit naming makes ignore patterns self-documenting.
Tag viewsets with product-specific tags instead of generic "core":
- actions → products/actions/frontend/generated/
- persons, elements, column_configuration → products/product_analytics/
- feature_flags → products/feature_flags/
- data_color_themes → products/dashboards/
- conversation → products/max/

Routing logic uses two levels:
1. Tag → product name (via products.json + package.json discovery)
2. Product → output path (products/{name}/frontend/generated/ if ready)

Also adds package.json to batch_exports, cdp, data_warehouse so they
can receive generated types even without manifest.tsx.
- Simplify apiMutator type signature
- Add surveysList usage example in surveysLogic showing generated API
- Regenerate types for data_warehouse, batch_exports, desktop_recordings
- Update openapi.json schema
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants