feat(api): generate TypeScript API client from OpenAPI specification

Create type-safe TypeScript API client automatically generated from the
OpenAPI specification. Includes generated schema types and documented client
wrapper for type-safe backend communication.

Ref: T008 (specs/001-modbus-relay-control)
This commit is contained in:
2026-01-01 23:29:31 +01:00
parent 837a49fc58
commit 8e4433ceaa
6 changed files with 498 additions and 38 deletions

61
src/api/README.md Normal file
View File

@@ -0,0 +1,61 @@
# API Client
This directory contains the auto-generated TypeScript API client for the STA backend.
## Files
- `schema.ts` - Auto-generated OpenAPI type definitions (do not edit manually)
- `client.ts` - API client instance with type-safe methods
## Regenerating the Client
To regenerate the TypeScript client after backend API changes:
1. Start the backend server:
```bash
cargo run
```
2. Download the OpenAPI spec:
```bash
curl http://localhost:3100/specs > openapi.yaml
```
3. Generate TypeScript types:
```bash
pnpm exec openapi-typescript openapi.yaml -o src/api/schema.ts
```
## Usage Example
```typescript
import { apiClient } from '@/api/client';
// GET request
const { data, error } = await apiClient.GET('/api/health');
if (error) {
console.error('Health check failed:', error);
} else {
console.log('Server is healthy');
}
// GET request with response data
const { data: meta, error: metaError } = await apiClient.GET('/api/meta');
if (metaError) {
console.error('Failed to get metadata:', metaError);
} else {
console.log('App name:', meta.name);
console.log('App version:', meta.version);
}
```
## Configuration
The API base URL can be configured via the `VITE_API_BASE_URL` environment variable.
Create a `.env` file in the project root:
```env
VITE_API_BASE_URL=http://localhost:3100
```
For production builds, set the environment variable to point to your deployed backend.

31
src/api/client.ts Normal file
View File

@@ -0,0 +1,31 @@
/**
* API client for the STA backend.
*
* This client is generated from the OpenAPI specification and provides
* type-safe access to all backend endpoints.
*
* Usage:
* ```typescript
* import { apiClient } from '@/api/client';
*
* const { data, error } = await apiClient.GET('/api/health');
* ```
*/
import createClient from 'openapi-fetch';
import type { paths } from './schema';
// Get the API base URL from environment variables or default to localhost
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3100';
/**
* Typed API client instance.
*
* All requests are type-checked against the OpenAPI schema.
*/
export const apiClient = createClient<paths>({ baseUrl: API_BASE_URL });
/**
* Re-export the types for convenience
*/
export type { paths, components } from './schema';

106
src/api/schema.ts Normal file
View File

@@ -0,0 +1,106 @@
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
"/api/health": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Success */
200: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Too Many Requests - rate limit exceeded */
429: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/meta": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Success */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json; charset=utf-8": components["schemas"]["Meta"];
};
};
/** @description Too Many Requests - rate limit exceeded */
429: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
/** Meta */
Meta: {
version: string;
name: string;
};
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export type operations = Record<string, never>;