This repository generates OpenAPI specifications from TypeSpec definitions. It supports multiple provider variants (core, GCP) using a shared codebase with provider-specific type aliases.
Build commands:
npm run build:core # Generate core OpenAPI spec
npm run build:gcp # Generate GCP OpenAPI spec
npm run build:all # Generate all variants with SwaggerValidation workflow:
npm install # Install dependencies
npm run build:core # Build and verify compilation
npm run build:gcp # Build GCP variant
ls -l schemas/*/openapi.yaml # Confirm outputs existThe repo uses a single main.tsp but generates different specs per provider:
// aliases-core.tsp
alias ClusterSpec = Record<unknown>; // Generic
// aliases-gcp.tsp
alias ClusterSpec = GCPClusterSpec; // Provider-specificThe aliases.tsp symlink determines which provider types are active. The build-schema.sh script automatically re-links this during builds.
When adding new models:
- Shared models →
models/ - Provider-specific →
models-{provider}/ - Always update alias files if you introduce provider-specific types
Status endpoints are split:
services/statuses.tsp- GET operations (external clients)services/statuses-internal.tsp- POST operations (internal adapters only)
The split allows generating different API contracts per audience. Only statuses.tsp is imported by default.
Imports first, namespace second:
import "@typespec/http";
import "../models/common/model.tsp";
namespace HyperFleet;Use decorators for HTTP semantics:
@route("/clusters")
interface Clusters {
@get list(): Cluster[] | Error;
@post create(@body cluster: ClusterInput): Cluster | Error;
}Model naming:
- Resources:
Cluster,NodePool(singular) - Inputs:
ClusterInput,NodePoolInput - Provider-specific:
GCPClusterSpec,AWSClusterSpec
models/{resource}/
├── model.tsp # Shared model definitions
└── interfaces.tsp # Optional: shared interfaces
models-{provider}/{resource}/
└── model.tsp # Provider-specific models
services/
└── {resource}.tsp # Service endpoints
DO NOT:
- Modify generated files in
schemas/ortsp-output/directly - Add dependencies without checking TypeSpec version compatibility
- Auto-generate documentation - it degrades agent performance per research
- Use
--swaggerflag unless you need OpenAPI 2.0 for legacy tools - Commit
node_modules/or build artifacts
DO:
- Run
npm run build:allbefore committing schema changes - Test both provider variants when modifying shared models
- Keep TypeSpec files focused (one resource per service file)
- Use semantic versioning for releases (see RELEASING.md)
// services/clusters.tsp
namespace HyperFleet;
@route("/clusters")
interface Clusters {
// ... existing endpoints ...
@get
@route("/{id}/health")
getHealth(@path id: string): HealthStatus | Error;
}- Create model:
// models/health/model.tsp
import "@typespec/http";
model HealthStatus {
id: string;
state: "healthy" | "degraded" | "critical";
lastChecked: utcDateTime;
}- Create service:
// services/health.tsp
import "@typespec/http";
import "../models/health/model.tsp";
import "../models/common/model.tsp";
namespace HyperFleet;
@route("/health")
interface Health {
@get check(): HealthStatus | Error;
}- Import in
main.tsp:
import "./services/health.tsp";- Build:
npm run build:core
// models-gcp/cluster/model.tsp
model GCPClusterSpec {
projectId: string;
region: string;
network?: GCPNetwork;
}
model GCPNetwork {
vpcId: string;
subnetId: string;
}Update alias:
// aliases-gcp.tsp
import "./models-gcp/cluster/model.tsp";
alias ClusterSpec = GCPClusterSpec;Build: npm run build:gcp
Before submitting changes:
- Dependencies installed:
npm install - Core variant builds:
npm run build:core - GCP variant builds:
npm run build:gcp - Schema files generated:
ls schemas/*/openapi.yaml - No TypeSpec compilation errors (check output)
- Changes committed including schema updates
- PR description references related issue
The build-schema.sh script:
- Validates provider parameter (core, gcp, etc.)
- Re-links
aliases.tsp→aliases-{provider}.tsp - Runs
tsp compile main.tsp - Copies output to
schemas/{provider}/openapi.yaml - (Optional) Converts to OpenAPI 2.0 with
--swaggerflag
Output locations:
- TypeSpec:
tsp-output/schema/openapi.yaml(temporary) - Final:
schemas/{provider}/openapi.yaml(committed)
The TypeSpec extension may show false errors:
- Non-active provider models appear undefined (expected)
- Duplicate type warnings from multiple alias files (expected)
Both the CLI and "Emit from TypeSpec" command work correctly despite warnings.
All TypeSpec libraries use version ^1.6.0 for consistency:
@typespec/compiler- Core compiler@typespec/http- HTTP semantics@typespec/openapi- OpenAPI decorators@typespec/openapi3- OpenAPI 3.0 emitter@typespec/rest- REST conventions@typespec/versioning- API versioning support
Adding new TypeSpec libraries:
npm install --save-dev @typespec/library-name@^1.6.0Match the version range to existing dependencies.
Quick reference (see RELEASING.md for details):
# 1. Build schemas
npm run build:all
# 2. Commit and tag
git add schemas/
git commit -m "chore: update schemas for vX.Y.Z"
git tag -a vX.Y.Z -m "Release vX.Y.Z"
# 3. Push tag
git push upstream vX.Y.Z
# 4. Create GitHub Release with schema assets
gh release create vX.Y.Z \
--repo openshift-hyperfleet/hyperfleet-api-spec \
--title "vX.Y.Z" \
schemas/core/openapi.yaml#core-openapi.yaml \
schemas/gcp/openapi.yaml#gcp-openapi.yamlThis repository is part of the HyperFleet project. For broader context:
- Architecture repo: https://github.com/openshift-hyperfleet/architecture
- Main API implementation: https://github.com/openshift-hyperfleet/hyperfleet-api
The API implementation consumes the generated OpenAPI specs for validation and documentation.