In ShieldedStack, the Control Plane frontend doesn’t manually define API calls. Instead, it consumes a fully generated, strongly typed TypeScript client. Built directly from the backend’s OpenAPI specification using Kiota.

This approach keeps the frontend and backend in lockstep, eliminates drift, and removes a whole class of runtime errors caused by mismatched contracts.

Build-Time: Generating the Client

The process starts in the backend project (API). During the build, the API emits an OpenAPI document:

  • ShieldedStack.ControlPlane.API.json

Immediately after, a post-build step runs Kiota to regenerate the frontend client:

  • Output goes to: src/client in the frontend project
  • The --clean-output flag ensures no stale files survive between builds

Here’s the relevant MSBuild target:

<Target Name="GenerateTypeScriptClient" AfterTargets="Build">
  <Exec Command="~/.dotnet/tools/kiota generate -l TypeScript -d ShieldedStack.ControlPlane.API.json -o ../ShieldedStack.ControlPlane.Frontend/src/client --clean-output" />
</Target>

This guarantees that every backend build produces a frontend client that exactly matches the current API contract. No manual sync, no guessing.

Runtime: Wiring the Client

At runtime, the frontend initializes the generated client using Kiota’s FetchRequestAdapter.

This adapter is extended with custom behavior:

  • Injects bearer authentication tokens
  • Adds workspace and tenant context headers
  • Resolves the API base URL from runtime or build configuration

Developer Experience: Fluent and Typed

From a developer’s perspective, the generated client provides a fluent, strongly typed interface.

For example:

  • Fetching outdated package reports:
    apiClient.packages.reports.outdated.get(...)
  • Updating a workspace:
    apiClient.workspaces.byId(id).put(...)

Both query parameters and request bodies are fully typed based on the OpenAPI schema, which means:

  • Autocomplete works out of the box
  • Invalid shapes are caught at compile time
  • Refactoring is safer and more predictable

Request-level options can also be passed to customize behavior; for example, controlling toast notifications per call.