132 lines
3.2 KiB
Bash
132 lines
3.2 KiB
Bash
#!/bin/bash
|
|
# Generate TypeScript API client from OpenAPI spec
|
|
#
|
|
# Usage:
|
|
# ./scripts/generate-client.sh [SPEC_URL]
|
|
#
|
|
# Environment:
|
|
# SPEC_URL - OpenAPI spec URL (default: http://localhost:8080/openapi.json)
|
|
|
|
set -e
|
|
|
|
SPEC_URL="${1:-${SPEC_URL:-http://localhost:8080/openapi.json}}"
|
|
OUTPUT_DIR="packages/api-client/src"
|
|
|
|
echo "Generating TypeScript client from: $SPEC_URL"
|
|
|
|
# Ensure output directory exists
|
|
mkdir -p "$OUTPUT_DIR"
|
|
|
|
# Generate TypeScript types from OpenAPI spec
|
|
npx openapi-typescript "$SPEC_URL" -o "$OUTPUT_DIR/schema.d.ts"
|
|
|
|
echo "Generated: $OUTPUT_DIR/schema.d.ts"
|
|
|
|
# Create client wrapper if it doesn't exist
|
|
if [ ! -f "$OUTPUT_DIR/client.ts" ]; then
|
|
cat > "$OUTPUT_DIR/client.ts" << 'EOF'
|
|
import type { paths } from './schema';
|
|
|
|
export type { paths };
|
|
|
|
/**
|
|
* API Client Configuration
|
|
*/
|
|
export interface ClientConfig {
|
|
baseUrl: string;
|
|
apiKey?: string;
|
|
bearerToken?: string;
|
|
headers?: Record<string, string>;
|
|
onError?: (error: Error) => void;
|
|
}
|
|
|
|
/**
|
|
* Create a typed API client
|
|
*/
|
|
export function createClient(config: ClientConfig) {
|
|
const { baseUrl, apiKey, bearerToken, headers = {}, onError } = config;
|
|
|
|
async function request<T>(
|
|
method: string,
|
|
path: string,
|
|
options: {
|
|
body?: unknown;
|
|
params?: Record<string, string | number | boolean | undefined>;
|
|
headers?: Record<string, string>;
|
|
} = {}
|
|
): Promise<T> {
|
|
const url = new URL(path, baseUrl);
|
|
|
|
// Add query params
|
|
if (options.params) {
|
|
for (const [key, value] of Object.entries(options.params)) {
|
|
if (value !== undefined) {
|
|
url.searchParams.set(key, String(value));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Build headers
|
|
const requestHeaders: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
...headers,
|
|
...options.headers,
|
|
};
|
|
|
|
if (apiKey) {
|
|
requestHeaders['X-API-Key'] = apiKey;
|
|
}
|
|
if (bearerToken) {
|
|
requestHeaders['Authorization'] = `Bearer ${bearerToken}`;
|
|
}
|
|
|
|
const response = await fetch(url.toString(), {
|
|
method,
|
|
headers: requestHeaders,
|
|
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const error = new Error(`API error: ${response.status}`);
|
|
if (onError) {
|
|
onError(error);
|
|
}
|
|
throw error;
|
|
}
|
|
|
|
// Handle no-content responses
|
|
if (response.status === 204) {
|
|
return undefined as T;
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
return {
|
|
get: <T>(path: string, params?: Record<string, string | number | boolean | undefined>) =>
|
|
request<T>('GET', path, { params }),
|
|
post: <T>(path: string, body?: unknown) =>
|
|
request<T>('POST', path, { body }),
|
|
put: <T>(path: string, body?: unknown) =>
|
|
request<T>('PUT', path, { body }),
|
|
patch: <T>(path: string, body?: unknown) =>
|
|
request<T>('PATCH', path, { body }),
|
|
delete: <T>(path: string) =>
|
|
request<T>('DELETE', path),
|
|
};
|
|
}
|
|
EOF
|
|
echo "Created: $OUTPUT_DIR/client.ts"
|
|
fi
|
|
|
|
# Create index if it doesn't exist
|
|
if [ ! -f "$OUTPUT_DIR/index.ts" ]; then
|
|
cat > "$OUTPUT_DIR/index.ts" << 'EOF'
|
|
export * from './client';
|
|
export type { paths, components, operations } from './schema';
|
|
EOF
|
|
echo "Created: $OUTPUT_DIR/index.ts"
|
|
fi
|
|
|
|
echo "Done! Client generated in: $OUTPUT_DIR"
|