diff --git a/.changeset/true-lemons-think.md b/.changeset/true-lemons-think.md
new file mode 100644
index 0000000..7b9c539
--- /dev/null
+++ b/.changeset/true-lemons-think.md
@@ -0,0 +1,24 @@
+---
+"typed-openapi": minor
+---
+
+Add comprehensive type-safe error handling and configurable status codes
+
+- **Type-safe error handling**: Added discriminated unions for API responses with `SafeApiResponse` and `TypedApiResponse` types that distinguish between success and error responses based on HTTP status codes
+- **withResponse parameter**: Enhanced API clients to optionally return both the parsed data and the original Response object for advanced use cases
+- **TanStack Query integration**: Added complete TanStack Query client generation with:
+ - Advanced mutation options supporting `withResponse` and `selectFn` parameters
+ - Automatic error type inference based on OpenAPI error schemas instead of generic Error type
+ - Type-safe error handling with discriminated unions for mutations
+ - Response-like error objects that extend Response with additional `data` property for consistency
+- **Configurable status codes**: Made success and error status codes fully configurable:
+ - New `--success-status-codes` and `--error-status-codes` CLI options
+ - `GeneratorOptions` now accepts `successStatusCodes` and `errorStatusCodes` arrays
+ - Default error status codes cover comprehensive 4xx and 5xx ranges
+- **Enhanced CLI options**: Added new command-line options for better control:
+ - `--include-client` to control whether to generate API client types and implementation
+ - `--include-client=false` to only generate the schemas and endpoints
+- **Enhanced types**: Renamed `StatusCode` to `TStatusCode` and added reusable `ErrorStatusCode` type
+- **Comprehensive documentation**: Added detailed examples and guides for error handling patterns
+
+This release significantly improves the type safety and flexibility of generated API clients, especially for error handling scenarios.
diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml
index 3fda180..60f19ed 100644
--- a/.github/workflows/build-and-test.yaml
+++ b/.github/workflows/build-and-test.yaml
@@ -25,3 +25,6 @@ jobs:
- name: Test
run: pnpm test
+
+ - name: Release package
+ run: pnpm dlx pkg-pr-new publish './packages/typed-openapi'
diff --git a/README.md b/README.md
index bb5b319..48b5ca2 100644
--- a/README.md
+++ b/README.md
@@ -6,10 +6,14 @@ See [the online playground](https://typed-openapi-astahmer.vercel.app/)

+[](https://pkg.pr.new/~/astahmer/typed-openapi)
+
## Features
- Headless API client, bring your own fetcher ! (fetch, axios, ky, etc...)
- Generates a fully typesafe API client with just types by default (instant suggestions)
+- **Type-safe error handling** with discriminated unions and configurable success status codes
+- **TanStack Query integration** with `withResponse` and `selectFn` options for advanced error handling
- Or you can also generate a client with runtime validation using one of the following runtimes:
- [zod](https://zod.dev/)
- [typebox](https://github.com/sinclairzx81/typebox)
@@ -37,17 +41,26 @@ npx typed-openapi -h
```
```sh
-typed-openapi/0.1.3
+typed-openapi/1.5.0
-Usage: $ typed-openapi
+Usage:
+ $ typed-openapi
-Commands: Generate
+Commands:
+ Generate
-For more info, run any command with the `--help` flag: $ typed-openapi --help
+For more info, run any command with the `--help` flag:
+ $ typed-openapi --help
-Options: -o, --output Output path for the api client ts file (defaults to `..ts`) -r, --runtime
- Runtime to use for validation; defaults to `none`; available: 'none' | 'arktype' | 'io-ts' | 'typebox' |
-'valibot' | 'yup' | 'zod' (default: none) -h, --help Display this message -v, --version Display version number
+Options:
+ -o, --output Output path for the api client ts file (defaults to `..ts`)
+ -r, --runtime Runtime to use for validation; defaults to `none`; available: Type<"arktype" | "io-ts" | "none" | "typebox" | "valibot" | "yup" | "zod"> (default: none)
+ --schemas-only Only generate schemas, skipping client generation (defaults to false) (default: false)
+ --include-client Include API client types and implementation (defaults to true) (default: true)
+ --success-status-codes Comma-separated list of success status codes for type-safe error handling (defaults to 2xx and 3xx ranges)
+ --tanstack [name] Generate tanstack client with withResponse support for error handling, defaults to false, can optionally specify a name for the generated file
+ -h, --help Display this message
+ -v, --version Display version number
```
## Non-goals
@@ -65,6 +78,247 @@ Options: -o, --output Output path for the api client ts file (defaults to
Basically, let's focus on having a fast and typesafe API client generation instead.
+## Usage Examples
+
+### API Client Setup
+
+The generated client is headless - you need to provide your own fetcher. Here are ready-to-use examples:
+
+- **[Basic API Client](packages/typed-openapi/API_CLIENT_EXAMPLES.md#basic-api-client-api-client-examplets)** - Simple, dependency-free wrapper
+- **[Validating API Client](packages/typed-openapi/API_CLIENT_EXAMPLES.md#validating-api-client-api-client-with-validationts)** - With request/response validation
+
+### Type-Safe Error Handling
+
+The generated client supports two response modes:
+
+```typescript
+// Default: Direct data return (simpler, but no error details)
+const user = await api.get("/users/{id}", {
+ path: { id: "123" }
+}); // user is directly typed as User object
+
+// WithResponse: Full Response object with typed ok/status and data
+const result = await api.get("/users/{id}", {
+ path: { id: "123" },
+ withResponse: true
+});
+
+// result is the actual Response object with typed ok/status overrides plus data access
+if (result.ok) {
+ // Access data directly (already parsed)
+ const user = result.data; // Type: User
+ console.log("User:", user.name);
+
+ // Or use json() method for compatibility
+ const userFromJson = await result.json(); // Same as result.data
+ console.log("User from json():", userFromJson.name);
+
+ console.log("Status:", result.status); // Typed as success status codes
+ console.log("Headers:", result.headers); // Access to all Response properties
+} else {
+ // Access error data directly
+ const error = result.data; // Type based on status code
+ if (result.status === 404) {
+ console.log("User not found:", error.message);
+ } else if (result.status === 401) {
+ console.log("Unauthorized:", error.details);
+ }
+}
+```### Success Response Type-Narrowing
+
+When endpoints have multiple success responses (200, 201, etc.), the type is automatically narrowed based on status:
+
+```typescript
+const result = await api.post("/users", {
+ body: { name: "John" },
+ withResponse: true
+});
+
+if (result.ok) {
+ if (result.status === 201) {
+ // result.data typed as CreateUserResponse (201)
+ console.log("Created user:", result.data.id);
+ } else if (result.status === 200) {
+ // result.data typed as ExistingUserResponse (200)
+ console.log("Existing user:", result.data.email);
+ }
+}
+```
+
+### Generic Request Method
+
+For dynamic endpoint calls or when you need more control:
+
+```typescript
+// Type-safe generic request method
+const response = await api.request("GET", "/users/{id}", {
+ path: { id: "123" },
+ query: { include: ["profile", "settings"] }
+});
+
+const user = await response.json(); // Fully typed based on endpoint
+```
+
+### TanStack Query Integration
+
+Generate TanStack Query wrappers for your endpoints:
+
+```bash
+npx typed-openapi api.yaml --runtime zod --tanstack
+```
+
+## useQuery / fetchQuery / ensureQueryData
+
+```ts
+// Basic query
+const accessiblePagesQuery = useQuery(
+ tanstackApi.get('/authorization/accessible-pages').queryOptions
+);
+
+// Query with query parameters
+const membersQuery = useQuery(
+ tanstackApi.get('/authorization/organizations/:organizationId/members/search', {
+ path: { organizationId: 'org123' },
+ query: { searchQuery: 'john' }
+ }).queryOptions
+);
+
+// With additional query options
+const departmentCostsQuery = useQuery({
+ ...tanstackApi.get('/organizations/:organizationId/department-costs', {
+ path: { organizationId: params.orgId },
+ query: { period: selectedPeriod },
+ }).queryOptions,
+ staleTime: 30 * 1000,
+ // placeholderData: keepPreviousData,
+ // etc
+});
+```
+
+or if you need it in a router `beforeLoad` / `loader`:
+
+```ts
+import { tanstackApi } from '#api';
+
+await queryClient.fetchQuery(
+ tanstackApi.get('/:organizationId/remediation/accounting-lines/metrics', {
+ path: { organizationId: params.orgId },
+ }).queryOptions,
+);
+```
+
+## useMutation
+
+The mutation API supports both basic usage and advanced error handling with `withResponse` and custom transformations with `selectFn`. **Note**: All mutation errors are Response-like objects with type-safe error inference based on your OpenAPI error schemas.
+
+```ts
+// Basic mutation (returns data only)
+const basicMutation = useMutation({
+ ...tanstackApi.mutation("post", '/authorization/organizations/:organizationId/invitations').mutationOptions,
+ onError: (error) => {
+ // error is a Response-like object with typed data based on OpenAPI spec
+ console.log(error instanceof Response); // true
+ console.log(error.status); // 400, 401, etc. (properly typed)
+ console.log(error.data); // Typed error response body
+ }
+});
+
+// With error handling using withResponse
+const mutationWithErrorHandling = useMutation(
+ tanstackApi.mutation("post", '/users', {
+ withResponse: true
+ }).mutationOptions
+);
+
+// With custom response transformation
+const customMutation = useMutation(
+ tanstackApi.mutation("post", '/users', {
+ selectFn: (user) => ({ userId: user.id, userName: user.name })
+ }).mutationOptions
+);
+
+// Advanced: withResponse + selectFn for comprehensive error handling
+const advancedMutation = useMutation(
+ tanstackApi.mutation("post", '/users', {
+ withResponse: true,
+ selectFn: (response) => ({
+ success: response.ok,
+ user: response.ok ? response.data : null,
+ error: response.ok ? null : response.data,
+ statusCode: response.status
+ })
+ }).mutationOptions
+);
+```
+
+### Usage Examples:
+
+```ts
+// Basic usage
+basicMutation.mutate({
+ body: {
+ emailAddress: 'user@example.com',
+ department: 'engineering',
+ roleName: 'admin'
+ }
+});
+
+// With error handling
+mutationWithErrorHandling.mutate(
+ { body: userData },
+ {
+ onSuccess: (response) => {
+ if (response.ok) {
+ toast.success(`User ${response.data.name} created!`);
+ } else {
+ if (response.status === 400) {
+ toast.error(`Validation error: ${response.data.message}`);
+ } else if (response.status === 409) {
+ toast.error('User already exists');
+ }
+ }
+ }
+ }
+);
+
+// Advanced usage with custom transformation
+advancedMutation.mutate(
+ { body: userData },
+ {
+ onSuccess: (result) => {
+ if (result.success) {
+ console.log('Created user:', result.user.name);
+ } else {
+ console.error(`Error ${result.statusCode}:`, result.error);
+ }
+ }
+ }
+);
+```
+
+## useMutation without the tanstack api
+
+If you need to make a custom mutation you could use the `api` directly:
+
+```ts
+const { mutate: login, isPending } = useMutation({
+ mutationFn: async (type: 'google' | 'microsoft') => {
+ return api.post(`/authentication/${type}`, { body: { redirectUri: search.redirect } });
+ },
+ onSuccess: (data) => {
+ window.location.replace(data.url);
+ },
+ onError: (error, type) => {
+ console.error(error);
+ toast({
+ title: t(`toast.login.${type}.error`),
+ icon: 'warning',
+ variant: 'critical',
+ });
+ },
+});
+```
+
## Alternatives
[openapi-zod-client](https://github.com/astahmer/openapi-zod-client), which generates a
diff --git a/packages/typed-openapi/API_CLIENT_EXAMPLES.md b/packages/typed-openapi/API_CLIENT_EXAMPLES.md
new file mode 100644
index 0000000..699850d
--- /dev/null
+++ b/packages/typed-openapi/API_CLIENT_EXAMPLES.md
@@ -0,0 +1,202 @@
+# API Client Examples
+
+These are production-ready API client wrappers for your generated typed-openapi code. Copy the one that fits your needs and customize it.
+
+## Basic API Client (`api-client-example.ts`)
+
+A simple, dependency-free client that handles:
+- Path parameter replacement (`{id}` and `:id` formats)
+- Query parameter serialization (including arrays)
+- JSON request/response handling
+- Custom headers
+- Basic error handling
+
+### Setup
+
+1. Copy the file to your project
+2. Update the import path to your generated API file:
+ ```typescript
+ import { type EndpointParameters, type Fetcher, createApiClient } from './generated/api';
+ ```
+3. Set your API base URL:
+ ```typescript
+ const API_BASE_URL = process.env['API_BASE_URL'] || 'https://your-api.com';
+ ```
+4. Uncomment the client creation:
+ ```typescript
+ export const api = createApiClient(fetcher, API_BASE_URL);
+ ```
+
+### Usage
+
+```typescript
+// GET request with query params
+const users = await api.get('/users', {
+ query: { page: 1, limit: 10, tags: ['admin', 'user'] }
+});
+
+// POST request with body
+const newUser = await api.post('/users', {
+ body: { name: 'John', email: 'john@example.com' }
+});
+
+// With path parameters
+const user = await api.get('/users/{id}', {
+ path: { id: '123' }
+});
+
+// With custom headers
+const result = await api.get('/protected', {
+ header: { Authorization: 'Bearer your-token' }
+});
+```
+
+## Validating API Client (`api-client-with-validation.ts`)
+
+Extends the basic client with schema validation for:
+- Request body validation before sending
+- Response validation after receiving
+- Type-safe validation error handling
+
+### Setup
+
+1. Follow the basic client setup steps above
+2. Import your validation library and schemas:
+ ```typescript
+ // For Zod
+ import { z } from 'zod';
+ import { EndpointByMethod } from './generated/api';
+
+ // For Yup
+ import * as yup from 'yup';
+ import { EndpointByMethod } from './generated/api';
+ ```
+3. Implement the validation logic in the marked TODO sections
+4. Configure validation settings:
+ ```typescript
+ const VALIDATE_REQUESTS = true; // Validate request bodies
+ const VALIDATE_RESPONSES = true; // Validate response data
+ ```
+
+### Validation Implementation Example (Zod)
+
+```typescript
+// Request validation
+if (VALIDATE_REQUESTS && params?.body) {
+ const endpoint = EndpointByMethod[method as keyof typeof EndpointByMethod];
+ const pathSchema = endpoint?.[actualUrl as keyof typeof endpoint];
+ if (pathSchema?.body) {
+ pathSchema.body.parse(params.body); // Throws if invalid
+ }
+}
+
+// Response validation
+const responseData = await responseClone.json();
+const endpoint = EndpointByMethod[method as keyof typeof EndpointByMethod];
+const pathSchema = endpoint?.[actualUrl as keyof typeof endpoint];
+const statusSchema = pathSchema?.responses?.[response.status];
+if (statusSchema) {
+ statusSchema.parse(responseData); // Throws if invalid
+}
+```
+
+### Error Handling
+
+```typescript
+try {
+ const result = await api.post('/users', {
+ body: { name: 'John', email: 'invalid-email' }
+ });
+} catch (error) {
+ if (error instanceof ValidationError) {
+ if (error.type === 'request') {
+ console.error('Invalid request data:', error.validationErrors);
+ } else {
+ console.error('Invalid response data:', error.validationErrors);
+ }
+ } else {
+ console.error('Network or HTTP error:', error);
+ }
+}
+```
+
+## Customization Ideas
+
+- **Authentication**: Add token handling, refresh logic, or auth headers
+- **Retries**: Implement retry logic for failed requests
+- **Caching**: Add response caching with TTL
+- **Logging**: Add request/response logging for debugging
+- **Rate limiting**: Implement client-side rate limiting
+- **Metrics**: Add performance monitoring and error tracking
+- **Base URL per environment**: Different URLs for dev/staging/prod
+
+## Error Handling Enhancement
+
+You can enhance error handling by creating custom error classes:
+
+```typescript
+class ApiError extends Error {
+ constructor(
+ public readonly status: number,
+ public readonly statusText: string,
+ public readonly response: Response
+ ) {
+ super(`HTTP ${status}: ${statusText}`);
+ this.name = 'ApiError';
+ }
+}
+
+// In your fetcher:
+if (!response.ok) {
+ throw new ApiError(response.status, response.statusText, response);
+}
+```
+
+## Error Handling with withResponse
+
+For type-safe error handling without exceptions, use the `withResponse: true` option:
+
+```typescript
+// Example with both data access methods
+const result = await api.get("/users/{id}", {
+ path: { id: "123" },
+ withResponse: true
+});
+
+if (result.ok) {
+ // Access data directly (already parsed)
+ const user = result.data; // Type: User
+ console.log("User:", user.name);
+
+ // Or use json() method for compatibility
+ const userFromJson = await result.json(); // Same as result.data
+ console.log("Same user:", userFromJson.name);
+
+ // Access other Response properties
+ console.log("Status:", result.status);
+ console.log("Headers:", result.headers.get("content-type"));
+} else {
+ // Handle errors with proper typing
+ const error = result.data; // Type based on status code
+
+ if (result.status === 404) {
+ console.error("Not found:", error.message);
+ } else if (result.status === 401) {
+ console.error("Unauthorized:", error.details);
+ } else {
+ console.error("Unknown error:", error);
+ }
+}
+```
+
+## TanStack Query Integration
+
+For React applications using TanStack Query, see:
+- [TANSTACK_QUERY_EXAMPLES.md](./TANSTACK_QUERY_EXAMPLES.md) for usage patterns with `withResponse` and `selectFn`
+- [TANSTACK_QUERY_ERROR_HANDLING.md](./TANSTACK_QUERY_ERROR_HANDLING.md) for type-safe error handling based on OpenAPI error schemas
+
+Key features:
+- Type-safe mutations with `withResponse` option
+- Custom response transformation with `selectFn`
+- Automatic error type inference from OpenAPI specs
+- Full type inference for all scenarios
diff --git a/packages/typed-openapi/TANSTACK_QUERY_ERROR_HANDLING.md b/packages/typed-openapi/TANSTACK_QUERY_ERROR_HANDLING.md
new file mode 100644
index 0000000..a096da7
--- /dev/null
+++ b/packages/typed-openapi/TANSTACK_QUERY_ERROR_HANDLING.md
@@ -0,0 +1,252 @@
+# TanStack Query Error Handling Examples
+
+This document demonstrates how the generated TanStack Query client provides type-safe error handling based on OpenAPI error schemas.
+
+## Error Type Inference
+
+The TanStack Query client automatically infers error types from your OpenAPI spec's error responses (status codes 400-511).
+
+### OpenAPI Spec Example
+
+```yaml
+paths:
+ /users:
+ post:
+ responses:
+ '201':
+ description: Created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ '400':
+ description: Validation Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ValidationError'
+ '409':
+ description: Conflict
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ConflictError'
+ '500':
+ description: Server Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ServerError'
+
+components:
+ schemas:
+ User:
+ type: object
+ properties:
+ id: { type: string }
+ name: { type: string }
+ email: { type: string }
+
+ ValidationError:
+ type: object
+ properties:
+ message: { type: string }
+ fields:
+ type: array
+ items: { type: string }
+
+ ConflictError:
+ type: object
+ properties:
+ message: { type: string }
+ existingId: { type: string }
+
+ ServerError:
+ type: object
+ properties:
+ message: { type: string }
+ code: { type: string }
+```
+
+## Generated Error Types
+
+For the above spec, the TanStack Query client generates:
+
+```typescript
+// Error type is automatically inferred as:
+type CreateUserError =
+ | Omit & { status: 400; data: ValidationError }
+ | Omit & { status: 409; data: ConflictError }
+ | Omit & { status: 500; data: ServerError }
+```
+
+## Usage Examples
+
+### Basic Usage with Type-Safe Error Handling
+
+```typescript
+import { useMutation } from '@tanstack/react-query';
+import { tanstackApi } from './generated/tanstack-query-client';
+
+function CreateUserForm() {
+ const createUser = useMutation({
+ ...tanstackApi.mutation("post", "/users").mutationOptions,
+ onError: (error) => {
+ // error is fully typed based on your OpenAPI spec!
+ // error is also a Response instance with additional data property
+ console.log(error instanceof Response); // true
+
+ if (error.status === 400) {
+ // error.data is typed as ValidationError
+ console.error('Validation failed:', error.data.message);
+ console.error('Invalid fields:', error.data.fields);
+ } else if (error.status === 409) {
+ // error.data is typed as ConflictError
+ console.error('User already exists:', error.data.existingId);
+ } else if (error.status === 500) {
+ // error.data is typed as ServerError
+ console.error('Server error:', error.data.code, error.data.message);
+ }
+ },
+ onSuccess: (user) => {
+ // user is typed as User
+ console.log('Created user:', user.name);
+ }
+ });
+
+ return (
+
+ );
+}
+```
+
+### Advanced Usage with withResponse
+
+```typescript
+function AdvancedCreateUserForm() {
+ const createUser = useMutation({
+ ...tanstackApi.mutation("post", "/users", {
+ withResponse: true,
+ selectFn: (response) => ({
+ success: response.ok,
+ user: response.ok ? response.data : null,
+ error: response.ok ? null : response.data,
+ statusCode: response.status,
+ headers: response.headers
+ })
+ }).mutationOptions,
+ onError: (error) => {
+ // Same typed error handling as above
+ // error is also a Response instance
+ console.log(error.ok); // false
+ console.log(error.headers); // Response headers
+
+ switch (error.status) {
+ case 400:
+ toast.error(`Validation: ${error.data.fields.join(', ')}`);
+ break;
+ case 409:
+ toast.error('Email already taken');
+ break;
+ case 500:
+ toast.error(`Server error: ${error.data.code}`);
+ break;
+ }
+ },
+ onSuccess: (result) => {
+ if (result.success) {
+ toast.success(`Welcome ${result.user!.name}!`);
+ // Access response headers
+ const rateLimit = result.headers.get('x-rate-limit-remaining');
+ }
+ }
+ });
+
+ // ... rest of component
+}
+```
+
+### Error Type Discrimination in Action
+
+```typescript
+// The error parameter is automatically discriminated based on status
+const handleError = (error: CreateUserError) => {
+ switch (error.status) {
+ case 400:
+ // TypeScript knows error.data is ValidationError
+ return {
+ title: 'Validation Failed',
+ message: error.data.message,
+ details: error.data.fields.map(field => `${field} is invalid`)
+ };
+
+ case 409:
+ // TypeScript knows error.data is ConflictError
+ return {
+ title: 'User Exists',
+ message: `User already exists with ID: ${error.data.existingId}`,
+ action: 'login'
+ };
+
+ case 500:
+ // TypeScript knows error.data is ServerError
+ return {
+ title: 'Server Error',
+ message: `Internal error (${error.data.code}): ${error.data.message}`,
+ action: 'retry'
+ };
+ }
+};
+```
+
+## Benefits
+
+- **Full Type Safety**: Error types are automatically inferred from your OpenAPI spec
+- **No Manual Type Definitions**: Types are generated, not hand-written
+- **Discriminated Unions**: TypeScript can narrow error types based on status codes
+- **IDE Support**: Full autocomplete and type checking for error properties
+- **Runtime Safety**: Errors are thrown with consistent structure: `{ status, data }`
+
+## Error Structure
+
+All errors thrown by TanStack Query mutations are **Response-like objects** that extend the native Response with additional type safety:
+
+```typescript
+interface ApiError extends Omit {
+ status: number; // HTTP status code (400-511) - properly typed
+ data: TData; // Typed error response body
+ // All other Response properties are available:
+ // ok: boolean
+ // headers: Headers
+ // url: string
+ // etc.
+}
+```
+
+### Key Benefits of Response-like Errors
+
+- **instanceof Response**: Error objects are proper Response instances
+- **Consistent API**: Both success and error responses follow the same Response pattern
+- **Full Response Access**: Access to headers, URL, and other Response properties
+- **Type Safety**: The `status` property is properly typed based on configured error status codes
+
+### Example Usage
+
+```typescript
+try {
+ await mutation.mutationFn(params);
+} catch (error) {
+ console.log(error instanceof Response); // true
+ console.log(error.ok); // false
+ console.log(error.status); // 400, 401, etc. (properly typed)
+ console.log(error.data); // Typed error response body
+ console.log(error.headers.get('content-type')); // Response headers
+ console.log(error.url); // Request URL
+}
+```
+
+This makes error handling predictable and type-safe across your entire application while maintaining consistency with the Response API.
diff --git a/packages/typed-openapi/TANSTACK_QUERY_EXAMPLES.md b/packages/typed-openapi/TANSTACK_QUERY_EXAMPLES.md
new file mode 100644
index 0000000..9e73e3d
--- /dev/null
+++ b/packages/typed-openapi/TANSTACK_QUERY_EXAMPLES.md
@@ -0,0 +1,178 @@
+# TanStack Query Integration Examples
+
+This document shows how to use the generated TanStack Query client with the new `withResponse` and `selectFn` options.
+
+## Basic Setup
+
+```typescript
+import { TanstackQueryApiClient } from './generated/tanstack-query-client';
+import { createApiClient } from './generated/api-client';
+
+// Create the API client and TanStack Query wrapper
+const apiClient = createApiClient(fetch);
+const queryClient = new TanstackQueryApiClient(apiClient);
+```
+
+## Usage Patterns
+
+### 1. Basic Usage (Data Only)
+
+```typescript
+const basicMutation = queryClient.mutation("post", "/users");
+// Type: { mutationFn: (params) => Promise }
+
+// In React component
+const createUser = useMutation(basicMutation.mutationOptions);
+```
+
+### 2. With Response Object for Error Handling
+
+```typescript
+const withResponseMutation = queryClient.mutation("post", "/users", {
+ withResponse: true
+});
+// Type: { mutationFn: (params) => Promise> }
+
+// Usage with error handling
+const createUser = useMutation({
+ ...withResponseMutation.mutationOptions,
+ onSuccess: (response) => {
+ if (response.ok) {
+ console.log('User created:', response.data);
+ console.log('Status:', response.status);
+ console.log('Headers:', response.headers.get('location'));
+ } else {
+ if (response.status === 400) {
+ console.error('Validation error:', response.data);
+ } else if (response.status === 409) {
+ console.error('User already exists:', response.data);
+ }
+ }
+ }
+});
+```
+
+### 3. Custom Response Transformation
+
+```typescript
+// Transform response data without withResponse
+const customSelectMutation = queryClient.mutation("post", "/users", {
+ selectFn: (user) => ({
+ userId: user.id,
+ userName: user.name,
+ isActive: true
+ })
+});
+// Type: { mutationFn: (params) => Promise<{ userId: string, userName: string, isActive: boolean }> }
+```
+
+### 4. Advanced: Response Object + Custom Transformation
+
+```typescript
+const advancedMutation = queryClient.mutation("post", "/users", {
+ withResponse: true,
+ selectFn: (response) => {
+ if (response.ok) {
+ return {
+ success: true,
+ user: response.data,
+ timestamp: new Date().toISOString()
+ };
+ } else {
+ return {
+ success: false,
+ error: response.data,
+ statusCode: response.status
+ };
+ }
+ }
+});
+// Type: { mutationFn: (params) => Promise<{ success: boolean, user?: User, error?: ErrorType, statusCode?: number, timestamp?: string }> }
+```
+
+## Complete React Example
+
+```typescript
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { TanstackQueryApiClient } from './generated/tanstack-query-client';
+
+function UserForm() {
+ const queryClient = useQueryClient();
+
+ // Mutation with error handling
+ const createUserMutation = queryClient.mutation("post", "/users", {
+ withResponse: true,
+ selectFn: (response) => ({
+ success: response.ok,
+ user: response.ok ? response.data : null,
+ error: response.ok ? null : response.data,
+ statusCode: response.status
+ })
+ });
+
+ const createUser = useMutation({
+ ...createUserMutation.mutationOptions,
+ onSuccess: (result) => {
+ if (result.success) {
+ // Invalidate and refetch users list
+ queryClient.invalidateQueries(['users']);
+ toast.success(`User ${result.user.name} created successfully!`);
+ } else {
+ if (result.statusCode === 400) {
+ toast.error(`Validation error: ${result.error.message}`);
+ } else if (result.statusCode === 409) {
+ toast.error('A user with this email already exists');
+ } else {
+ toast.error('An unexpected error occurred');
+ }
+ }
+ },
+ onError: (error) => {
+ // Type-safe error handling - error is a Response-like object with data property
+ console.log(error instanceof Response); // true
+ console.log(error.ok); // false
+
+ if (error.status === 400) {
+ toast.error(`Validation failed: ${error.data.message}`);
+ } else if (error.status === 500) {
+ toast.error('Server error occurred');
+ } else {
+ toast.error('Network error occurred');
+ }
+ }
+ });
+
+ const handleSubmit = (userData: { name: string; email: string }) => {
+ createUser.mutate({ body: userData });
+ };
+
+ return (
+
+ );
+}
+```
+
+## Error Handling
+
+The TanStack Query client provides automatic error type inference based on your OpenAPI error schemas. For detailed examples, see [TANSTACK_QUERY_ERROR_HANDLING.md](./TANSTACK_QUERY_ERROR_HANDLING.md).
+
+Key features:
+- **Type-safe errors**: Errors are typed as `{ status: number, data: ErrorSchemaType }`
+- **Status code discrimination**: Different error types based on HTTP status codes
+- **Full IDE support**: Autocomplete and type checking for error properties
+
+## Type Safety Benefits
+
+- **Full type inference**: All parameters and return types are automatically inferred
+- **Error type discrimination**: Different error types based on status codes with full type safety
+- **Response object access**: Headers, status, and other Response properties when needed
+- **Custom transformations**: Type-safe data transformations with `selectFn`
+- **Zero runtime overhead**: All type checking happens at compile time
diff --git a/packages/typed-openapi/src/api-client-example.ts b/packages/typed-openapi/src/api-client-example.ts
new file mode 100644
index 0000000..38e2667
--- /dev/null
+++ b/packages/typed-openapi/src/api-client-example.ts
@@ -0,0 +1,108 @@
+/**
+ * Generic API Client for typed-openapi generated code
+ *
+ * This is a simple, production-ready wrapper that you can copy and customize.
+ * It handles:
+ * - Path parameter replacement
+ * - Query parameter serialization
+ * - JSON request/response handling
+ * - Basic error handling
+ *
+ * Usage:
+ * 1. Replace './generated/api' with your actual generated file path
+ * 2. Set your API_BASE_URL
+ * 3. Customize error handling and headers as needed
+ */
+
+// TODO: Replace with your generated API client imports
+// import { type EndpointParameters, type Fetcher, createApiClient } from './generated/api';
+
+// Basic configuration
+const API_BASE_URL = process.env["API_BASE_URL"] || "https://api.example.com";
+
+// Generic types for when you haven't imported the generated types yet
+type EndpointParameters = {
+ body?: unknown;
+ query?: Record;
+ header?: Record;
+ path?: Record;
+};
+
+type Fetcher = (method: string, url: string, params?: EndpointParameters) => Promise;
+
+/**
+ * Simple fetcher implementation without external dependencies
+ */
+const fetcher: Fetcher = async (method, apiUrl, params) => {
+ const headers = new Headers();
+
+ // Replace path parameters (supports both {param} and :param formats)
+ const actualUrl = replacePathParams(apiUrl, (params?.path ?? {}) as Record);
+ const url = new URL(actualUrl);
+
+ // Handle query parameters
+ if (params?.query) {
+ const searchParams = new URLSearchParams();
+ Object.entries(params.query).forEach(([key, value]) => {
+ if (value != null) {
+ // Skip null/undefined values
+ if (Array.isArray(value)) {
+ value.forEach((val) => val != null && searchParams.append(key, String(val)));
+ } else {
+ searchParams.append(key, String(value));
+ }
+ }
+ });
+ url.search = searchParams.toString();
+ }
+
+ // Handle request body for mutation methods
+ const body = ["post", "put", "patch", "delete"].includes(method.toLowerCase())
+ ? JSON.stringify(params?.body)
+ : undefined;
+
+ if (body) {
+ headers.set("Content-Type", "application/json");
+ }
+
+ // Add custom headers
+ if (params?.header) {
+ Object.entries(params.header).forEach(([key, value]) => {
+ if (value != null) {
+ headers.set(key, String(value));
+ }
+ });
+ }
+
+ const response = await fetch(url, {
+ method: method.toUpperCase(),
+ ...(body && { body }),
+ headers,
+ });
+
+ if (!response.ok) {
+ // You can customize error handling here
+ const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
+ (error as any).response = response;
+ (error as any).status = response.status;
+ throw error;
+ }
+
+ return response;
+};
+
+/**
+ * Replace path parameters in URL
+ * Supports both OpenAPI format {param} and Express format :param
+ */
+function replacePathParams(url: string, params: Record): string {
+ return url
+ .replace(/{(\w+)}/g, (_, key: string) => params[key] || `{${key}}`)
+ .replace(/:([a-zA-Z0-9_]+)/g, (_, key: string) => params[key] || `:${key}`);
+}
+
+// TODO: Uncomment and replace with your generated createApiClient
+// export const api = createApiClient(fetcher, API_BASE_URL);
+
+// Example of how to create the client once you have the generated code:
+// export const api = createApiClient(fetcher, API_BASE_URL);
diff --git a/packages/typed-openapi/src/api-client-with-validation.ts b/packages/typed-openapi/src/api-client-with-validation.ts
new file mode 100644
index 0000000..f5dbbc7
--- /dev/null
+++ b/packages/typed-openapi/src/api-client-with-validation.ts
@@ -0,0 +1,184 @@
+/**
+ * Validating API Client for typed-openapi generated code
+ *
+ * This version includes input/output validation using the generated schemas.
+ * It validates:
+ * - Request body against schema before sending
+ * - Response data against schema after receiving
+ * - Provides type-safe error handling with schema validation errors
+ *
+ * Usage:
+ * 1. Replace './generated/api' with your actual generated file path
+ * 2. Set your API_BASE_URL
+ * 3. Choose your validation runtime (zod, yup, etc.)
+ * 4. Customize error handling as needed
+ */
+
+// TODO: Replace with your generated API client imports
+// import { type EndpointParameters, type Fetcher, createApiClient } from './generated/api';
+
+// For validation - import your chosen runtime's types and schemas
+// Example for Zod:
+// import { z } from 'zod';
+// import { EndpointByMethod } from './generated/api';
+
+// Basic configuration
+const API_BASE_URL = process.env["API_BASE_URL"] || "https://api.example.com";
+const VALIDATE_REQUESTS = true; // Set to false to skip request validation
+const VALIDATE_RESPONSES = true; // Set to false to skip response validation
+
+// Generic types for when you haven't imported the generated types yet
+type EndpointParameters = {
+ body?: unknown;
+ query?: Record;
+ header?: Record;
+ path?: Record;
+};
+
+type Fetcher = (method: string, url: string, params?: EndpointParameters) => Promise;
+
+// Validation error class
+class ValidationError extends Error {
+ constructor(
+ message: string,
+ public readonly type: "request" | "response",
+ public readonly validationErrors: unknown,
+ ) {
+ super(message);
+ this.name = "ValidationError";
+ }
+}
+
+/**
+ * Validating fetcher implementation
+ *
+ * This example shows the structure for validation.
+ * You'll need to adapt it based on your chosen validation library.
+ */
+const validatingFetcher: Fetcher = async (method, apiUrl, params) => {
+ const headers = new Headers();
+
+ // Replace path parameters (supports both {param} and :param formats)
+ const actualUrl = replacePathParams(apiUrl, (params?.path ?? {}) as Record);
+ const url = new URL(actualUrl);
+
+ // Handle query parameters
+ if (params?.query) {
+ const searchParams = new URLSearchParams();
+ Object.entries(params.query).forEach(([key, value]) => {
+ if (value != null) {
+ // Skip null/undefined values
+ if (Array.isArray(value)) {
+ value.forEach((val) => val != null && searchParams.append(key, String(val)));
+ } else {
+ searchParams.append(key, String(value));
+ }
+ }
+ });
+ url.search = searchParams.toString();
+ }
+
+ // Handle request body for mutation methods
+ let body: string | undefined;
+ if (["post", "put", "patch", "delete"].includes(method.toLowerCase()) && params?.body) {
+ // TODO: Add request validation here
+ if (VALIDATE_REQUESTS) {
+ try {
+ // Example for Zod validation:
+ // const endpoint = EndpointByMethod[method as keyof typeof EndpointByMethod];
+ // const pathSchema = endpoint?.[actualUrl as keyof typeof endpoint];
+ // if (pathSchema?.body) {
+ // pathSchema.body.parse(params.body);
+ // }
+
+ // For now, just log that validation would happen here
+ console.debug("Request validation would happen here for:", method, actualUrl);
+ } catch (error) {
+ throw new ValidationError("Request body validation failed", "request", error);
+ }
+ }
+
+ body = JSON.stringify(params.body);
+ headers.set("Content-Type", "application/json");
+ }
+
+ // Add custom headers
+ if (params?.header) {
+ Object.entries(params.header).forEach(([key, value]) => {
+ if (value != null) {
+ headers.set(key, String(value));
+ }
+ });
+ }
+
+ const response = await fetch(url, {
+ method: method.toUpperCase(),
+ ...(body && { body }),
+ headers,
+ });
+
+ if (!response.ok) {
+ // You can customize error handling here
+ const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
+ (error as any).response = response;
+ (error as any).status = response.status;
+ throw error;
+ }
+
+ // TODO: Add response validation here
+ if (VALIDATE_RESPONSES) {
+ try {
+ // Clone response for validation (since response can only be read once)
+ const responseClone = response.clone();
+ const responseData = await responseClone.json();
+
+ // Example for Zod validation:
+ // const endpoint = EndpointByMethod[method as keyof typeof EndpointByMethod];
+ // const pathSchema = endpoint?.[actualUrl as keyof typeof endpoint];
+ // const statusSchema = pathSchema?.responses?.[response.status as keyof typeof pathSchema.responses];
+ // if (statusSchema) {
+ // statusSchema.parse(responseData);
+ // }
+
+ // For now, just log that validation would happen here
+ console.debug("Response validation would happen here for:", method, actualUrl, response.status);
+ } catch (error) {
+ throw new ValidationError("Response validation failed", "response", error);
+ }
+ }
+
+ return response;
+};
+
+/**
+ * Replace path parameters in URL
+ * Supports both OpenAPI format {param} and Express format :param
+ */
+function replacePathParams(url: string, params: Record): string {
+ return url
+ .replace(/{(\w+)}/g, (_, key: string) => params[key] || `{${key}}`)
+ .replace(/:([a-zA-Z0-9_]+)/g, (_, key: string) => params[key] || `:${key}`);
+}
+
+// TODO: Uncomment and replace with your generated createApiClient
+// export const api = createApiClient(validatingFetcher, API_BASE_URL);
+
+// Export the validation error for error handling
+export { ValidationError };
+
+// Example usage with error handling:
+/*
+try {
+ const result = await api.post('/users', {
+ body: { name: 'John', email: 'john@example.com' }
+ });
+ const user = await result.json();
+ console.log('Created user:', user);
+} catch (error) {
+ if (error instanceof ValidationError) {
+ console.error(`${error.type} validation failed:`, error.validationErrors);
+ } else {
+ console.error('API error:', error);
+ }
+}
+*/
diff --git a/packages/typed-openapi/src/cli.ts b/packages/typed-openapi/src/cli.ts
index a54be68..7ca8509 100644
--- a/packages/typed-openapi/src/cli.ts
+++ b/packages/typed-openapi/src/cli.ts
@@ -1,5 +1,4 @@
import { cac } from "cac";
-
import { readFileSync } from "fs";
import { generateClientFiles } from "./generate-client-files.ts";
import { allowedRuntimes } from "./generator.ts";
@@ -11,16 +10,22 @@ cli
.command("", "Generate")
.option("-o, --output ", "Output path for the api client ts file (defaults to `..ts`)")
.option(
- "-r, --runtime ",
+ "-r, --runtime ",
`Runtime to use for validation; defaults to \`none\`; available: ${allowedRuntimes.toString()}`,
{ default: "none" },
)
.option("--schemas-only", "Only generate schemas, skipping client generation (defaults to false)", { default: false })
+ .option("--include-client", "Include API client types and implementation (defaults to true)", { default: true })
+ .option(
+ "--success-status-codes ",
+ "Comma-separated list of success status codes (defaults to 2xx and 3xx ranges)",
+ )
+ .option("--error-status-codes ", "Comma-separated list of error status codes (defaults to 4xx and 5xx ranges)")
.option(
"--tanstack [name]",
"Generate tanstack client, defaults to false, can optionally specify a name for the generated file",
)
- .action(async (input, _options) => {
+ .action(async (input: string, _options: any) => {
return generateClientFiles(input, _options);
});
diff --git a/packages/typed-openapi/src/generate-client-files.ts b/packages/typed-openapi/src/generate-client-files.ts
index e8c8275..0900960 100644
--- a/packages/typed-openapi/src/generate-client-files.ts
+++ b/packages/typed-openapi/src/generate-client-files.ts
@@ -3,7 +3,12 @@ import type { OpenAPIObject } from "openapi3-ts/oas31";
import { basename, join, dirname } from "pathe";
import { type } from "arktype";
import { mkdir, writeFile } from "fs/promises";
-import { allowedRuntimes, generateFile } from "./generator.ts";
+import {
+ allowedRuntimes,
+ generateFile,
+ DEFAULT_SUCCESS_STATUS_CODES,
+ DEFAULT_ERROR_STATUS_CODES,
+} from "./generator.ts";
import { mapOpenApiEndpoints } from "./map-openapi-endpoints.ts";
import { generateTanstackQueryFile } from "./tanstack-query.generator.ts";
import { prettify } from "./format.ts";
@@ -24,6 +29,9 @@ export const optionsSchema = type({
runtime: allowedRuntimes,
tanstack: "boolean | string",
schemasOnly: "boolean",
+ "includeClient?": "boolean | 'true' | 'false'",
+ "successStatusCodes?": "string",
+ "errorStatusCodes?": "string",
});
export async function generateClientFiles(input: string, options: typeof optionsSchema.infer) {
@@ -32,13 +40,30 @@ export async function generateClientFiles(input: string, options: typeof options
const ctx = mapOpenApiEndpoints(openApiDoc);
console.log(`Found ${ctx.endpointList.length} endpoints`);
- const content = await prettify(
- generateFile({
- ...ctx,
- runtime: options.runtime,
- schemasOnly: options.schemasOnly,
- }),
- );
+ // Parse success status codes if provided
+ const successStatusCodes = options.successStatusCodes
+ ? (options.successStatusCodes.split(",").map((code) => parseInt(code.trim(), 10)) as readonly number[])
+ : undefined;
+
+ // Parse error status codes if provided
+ const errorStatusCodes = options.errorStatusCodes
+ ? (options.errorStatusCodes.split(",").map((code) => parseInt(code.trim(), 10)) as readonly number[])
+ : undefined;
+
+ // Convert string boolean to actual boolean
+ const includeClient =
+ options.includeClient === "false" ? false : options.includeClient === "true" ? true : options.includeClient;
+
+ const generatorOptions = {
+ ...ctx,
+ runtime: options.runtime,
+ schemasOnly: options.schemasOnly,
+ includeClient: includeClient ?? true,
+ successStatusCodes: successStatusCodes ?? DEFAULT_SUCCESS_STATUS_CODES,
+ errorStatusCodes: errorStatusCodes ?? DEFAULT_ERROR_STATUS_CODES,
+ };
+
+ const content = await prettify(generateFile(generatorOptions));
const outputPath = join(
cwd,
options.output ?? input + `.${options.runtime === "none" ? "client" : options.runtime}.ts`,
@@ -50,7 +75,7 @@ export async function generateClientFiles(input: string, options: typeof options
if (options.tanstack) {
const tanstackContent = await generateTanstackQueryFile({
- ...ctx,
+ ...generatorOptions,
relativeApiClientPath: "./" + basename(outputPath),
});
const tanstackOutputPath = join(
diff --git a/packages/typed-openapi/src/generator.ts b/packages/typed-openapi/src/generator.ts
index 7b1ede8..9491435 100644
--- a/packages/typed-openapi/src/generator.ts
+++ b/packages/typed-openapi/src/generator.ts
@@ -7,9 +7,25 @@ import { match } from "ts-pattern";
import { type } from "arktype";
import { wrapWithQuotesIfNeeded } from "./string-utils.ts";
+// Default success status codes (2xx and 3xx ranges)
+export const DEFAULT_SUCCESS_STATUS_CODES = [
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308,
+] as const;
+
+// Default error status codes (4xx and 5xx ranges)
+export const DEFAULT_ERROR_STATUS_CODES = [
+ 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 421, 422, 423, 424,
+ 425, 426, 428, 429, 431, 451, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511,
+] as const;
+
+export type ErrorStatusCode = (typeof DEFAULT_ERROR_STATUS_CODES)[number];
+
type GeneratorOptions = ReturnType & {
runtime?: "none" | keyof typeof runtimeValidationGenerator;
schemasOnly?: boolean;
+ successStatusCodes?: readonly number[];
+ errorStatusCodes?: readonly number[];
+ includeClient?: boolean;
};
type GeneratorContext = Required;
@@ -60,11 +76,18 @@ const replacerByRuntime = {
};
export const generateFile = (options: GeneratorOptions) => {
- const ctx = { ...options, runtime: options.runtime ?? "none" } as GeneratorContext;
+ const ctx = {
+ ...options,
+ runtime: options.runtime ?? "none",
+ successStatusCodes: options.successStatusCodes ?? DEFAULT_SUCCESS_STATUS_CODES,
+ errorStatusCodes: options.errorStatusCodes ?? DEFAULT_ERROR_STATUS_CODES,
+ includeClient: options.includeClient ?? true,
+ } as GeneratorContext;
const schemaList = generateSchemaList(ctx);
const endpointSchemaList = options.schemasOnly ? "" : generateEndpointSchemaList(ctx);
- const apiClient = options.schemasOnly ? "" : generateApiClient(ctx);
+ const endpointByMethod = options.schemasOnly ? "" : generateEndpointByMethod(ctx);
+ const apiClient = options.schemasOnly || !ctx.includeClient ? "" : generateApiClient(ctx);
const transform =
ctx.runtime === "none"
@@ -96,6 +119,7 @@ export const generateFile = (options: GeneratorOptions) => {
const file = `
${transform(schemaList + endpointSchemaList)}
+ ${endpointByMethod}
${apiClient}
`;
@@ -151,6 +175,24 @@ const responseHeadersObjectToString = (responseHeaders: Record,
return str + "}";
};
+const generateResponsesObject = (responses: Record, ctx: GeneratorContext) => {
+ let str = "{";
+ for (const [statusCode, responseType] of Object.entries(responses)) {
+ const value =
+ ctx.runtime === "none"
+ ? responseType.recompute((box) => {
+ if (Box.isReference(box) && !box.params.generics && box.value !== "null") {
+ box.value = `Schemas.${box.value}`;
+ }
+
+ return box;
+ }).value
+ : responseType.value;
+ str += `${wrapWithQuotesIfNeeded(statusCode)}: ${value},\n`;
+ }
+ return str + "}";
+};
+
const generateEndpointSchemaList = (ctx: GeneratorContext) => {
let file = `
${ctx.runtime === "none" ? "export namespace Endpoints {" : ""}
@@ -197,6 +239,7 @@ const generateEndpointSchemaList = (ctx: GeneratorContext) => {
}).value
: endpoint.response.value
},
+ ${endpoint.responses ? `responses: ${generateResponsesObject(endpoint.responses, ctx)},` : ""}
${
endpoint.responseHeaders
? `responseHeaders: ${responseHeadersObjectToString(endpoint.responseHeaders, ctx)},`
@@ -225,9 +268,11 @@ const generateEndpointByMethod = (ctx: GeneratorContext) => {
${Object.entries(byMethods)
.map(([method, list]) => {
return `${method}: {
- ${list.map(
- (endpoint) => `"${endpoint.path}": ${ctx.runtime === "none" ? "Endpoints." : ""}${endpoint.meta.alias}`,
- )}
+ ${list
+ .map(
+ (endpoint) => `"${endpoint.path}": ${ctx.runtime === "none" ? "Endpoints." : ""}${endpoint.meta.alias}`,
+ )
+ .join(",\n")}
}`;
})
.join(",\n")}
@@ -249,9 +294,19 @@ const generateEndpointByMethod = (ctx: GeneratorContext) => {
};
const generateApiClient = (ctx: GeneratorContext) => {
+ if (!ctx.includeClient) {
+ return "";
+ }
+
const { endpointList } = ctx;
const byMethods = groupBy(endpointList, "method");
- const endpointSchemaList = generateEndpointByMethod(ctx);
+
+ // Generate the StatusCode type from the configured success status codes
+ const generateStatusCodeType = (statusCodes: readonly number[]) => {
+ return statusCodes.join(" | ");
+ };
+
+ const statusCodeType = generateStatusCodeType(ctx.successStatusCodes);
const apiClientTypes = `
//
@@ -270,6 +325,7 @@ type RequestFormat = "json" | "form-data" | "form-url" | "binary" | "text";
export type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: unknown;
+ responses?: Record;
responseHeaders?: Record;
};
@@ -285,11 +341,76 @@ export type Endpoint = {
areParametersRequired: boolean;
};
response: TConfig["response"];
+ responses?: TConfig["responses"];
responseHeaders?: TConfig["responseHeaders"]
};
export type Fetcher = (method: Method, url: string, parameters?: EndpointParameters | undefined) => Promise;
+// Status code type for success responses
+export type SuccessStatusCode = ${statusCodeType};
+
+// Error handling types
+export type TypedApiResponse = {}> =
+ (keyof TAllResponses extends never
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : {
+ [K in keyof TAllResponses]: K extends string
+ ? K extends \`\${infer TStatusCode extends number}\`
+ ? TStatusCode extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: TStatusCode;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: TStatusCode;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never
+ : K extends number
+ ? K extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: K;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: K;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never;
+ }[keyof TAllResponses]);
+
+export type SafeApiResponse = TEndpoint extends { response: infer TSuccess; responses: infer TResponses }
+ ? TResponses extends Record
+ ? TypedApiResponse
+ : Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : TEndpoint extends { response: infer TSuccess }
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : never;
+
type RequiredKeys = {
[P in keyof T]-?: undefined extends T[P] ? never : P;
}[keyof T];
@@ -331,16 +452,58 @@ export class ApiClient {
...params: MaybeOptionalArg<${match(ctx.runtime)
.with("zod", "yup", () => infer(`TEndpoint["parameters"]`))
.with("arktype", "io-ts", "typebox", "valibot", () => infer(`TEndpoint`) + `["parameters"]`)
- .otherwise(() => `TEndpoint["parameters"]`)}>
+ .otherwise(() => `TEndpoint["parameters"]`)} & { withResponse?: false }>
): Promise<${match(ctx.runtime)
.with("zod", "yup", () => infer(`TEndpoint["response"]`))
.with("arktype", "io-ts", "typebox", "valibot", () => infer(`TEndpoint`) + `["response"]`)
- .otherwise(() => `TEndpoint["response"]`)}> {
- return this.fetcher("${method}", this.baseUrl + path, params[0])
- .then(response => this.parseResponse(response))${match(ctx.runtime)
- .with("zod", "yup", () => `as Promise<${infer(`TEndpoint["response"]`)}>`)
- .with("arktype", "io-ts", "typebox", "valibot", () => `as Promise<${infer(`TEndpoint`) + `["response"]`}>`)
- .otherwise(() => `as Promise`)};
+ .otherwise(() => `TEndpoint["response"]`)}>;
+
+ ${method}(
+ path: Path,
+ ...params: MaybeOptionalArg<${match(ctx.runtime)
+ .with("zod", "yup", () => infer(`TEndpoint["parameters"]`))
+ .with("arktype", "io-ts", "typebox", "valibot", () => infer(`TEndpoint`) + `["parameters"]`)
+ .otherwise(() => `TEndpoint["parameters"]`)} & { withResponse: true }>
+ ): Promise>;
+
+ ${method}(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("${method}", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined)
+ .then(async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data)
+ });
+ return typedResponse;
+ });
+ } else {
+ return this.fetcher("${method}", this.baseUrl + path, requestParams)
+ .then(response => this.parseResponse(response))${match(ctx.runtime)
+ .with("zod", "yup", () => `as Promise<${infer(`TEndpoint["response"]`)}>`)
+ .with(
+ "arktype",
+ "io-ts",
+ "typebox",
+ "valibot",
+ () => `as Promise<${infer(`TEndpoint`) + `["response"]`}>`,
+ )
+ .otherwise(() => `as Promise`)};
+ }
}
//
`
@@ -393,10 +556,25 @@ export function createApiClient(fetcher: Fetcher, baseUrl?: string) {
api.get("/users").then((users) => console.log(users));
api.post("/users", { body: { name: "John" } }).then((user) => console.log(user));
api.put("/users/:id", { path: { id: 1 }, body: { name: "John" } }).then((user) => console.log(user));
+
+ // With error handling
+ const result = await api.get("/users/{id}", { path: { id: "123" }, withResponse: true });
+ if (result.ok) {
+ // Access data directly
+ const user = result.data;
+ console.log(user);
+
+ // Or use the json() method for compatibility
+ const userFromJson = await result.json();
+ console.log(userFromJson);
+ } else {
+ const error = result.data;
+ console.error(\`Error \${result.status}:\`, error);
+ }
*/
// {
// Match the first 2xx-3xx response found, or fallback to default one otherwise
let responseObject: ResponseObject | undefined;
+ const allResponses: Record = {};
+
Object.entries(operation.responses ?? {}).map(([status, responseOrRef]) => {
const statusCode = Number(status);
- if (statusCode >= 200 && statusCode < 300) {
- responseObject = refs.unwrap(responseOrRef);
+ const responseObj = refs.unwrap(responseOrRef);
+
+ // Collect all responses for error handling
+ const content = responseObj?.content;
+ if (content) {
+ const matchingMediaType = Object.keys(content).find(isResponseMediaType);
+ if (matchingMediaType && content[matchingMediaType]) {
+ allResponses[status] = openApiSchemaToTs({
+ schema: content[matchingMediaType]?.schema ?? {},
+ ctx,
+ });
+ } else {
+ // If no JSON content, use unknown type
+ allResponses[status] = openApiSchemaToTs({ schema: {}, ctx });
+ }
+ } else {
+ // If no content defined, use unknown type
+ allResponses[status] = openApiSchemaToTs({ schema: {}, ctx });
+ }
+
+ // Keep the current logic for the main response (first 2xx-3xx)
+ if (statusCode >= 200 && statusCode < 300 && !responseObject) {
+ responseObject = responseObj;
}
});
+
if (!responseObject && operation.responses?.default) {
responseObject = refs.unwrap(operation.responses.default);
+ // Also add default to all responses if not already covered
+ if (!allResponses["default"]) {
+ const content = responseObject?.content;
+ if (content) {
+ const matchingMediaType = Object.keys(content).find(isResponseMediaType);
+ if (matchingMediaType && content[matchingMediaType]) {
+ allResponses["default"] = openApiSchemaToTs({
+ schema: content[matchingMediaType]?.schema ?? {},
+ ctx,
+ });
+ }
+ }
+ }
+ }
+
+ // Set the responses collection
+ if (Object.keys(allResponses).length > 0) {
+ endpoint.responses = allResponses;
}
const content = responseObject?.content;
@@ -197,6 +239,7 @@ type RequestFormat = "json" | "form-data" | "form-url" | "binary" | "text";
type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: AnyBox;
+ responses?: Record;
responseHeaders?: Record;
};
@@ -212,5 +255,6 @@ export type Endpoint = {
areParametersRequired: boolean;
};
response: TConfig["response"];
+ responses?: TConfig["responses"];
responseHeaders?: TConfig["responseHeaders"];
};
diff --git a/packages/typed-openapi/src/tanstack-query.generator.ts b/packages/typed-openapi/src/tanstack-query.generator.ts
index 8c1436a..bdb930f 100644
--- a/packages/typed-openapi/src/tanstack-query.generator.ts
+++ b/packages/typed-openapi/src/tanstack-query.generator.ts
@@ -2,15 +2,28 @@ import { capitalize } from "pastable/server";
import { prettify } from "./format.ts";
import type { mapOpenApiEndpoints } from "./map-openapi-endpoints.ts";
+// Default error status codes (4xx and 5xx ranges)
+export const DEFAULT_ERROR_STATUS_CODES = [
+ 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 421, 422, 423, 424,
+ 425, 426, 428, 429, 431, 451, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511,
+] as const;
+
+export type ErrorStatusCode = (typeof DEFAULT_ERROR_STATUS_CODES)[number];
+
type GeneratorOptions = ReturnType;
-type GeneratorContext = Required;
+type GeneratorContext = Required & {
+ errorStatusCodes?: readonly number[];
+};
export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relativeApiClientPath: string }) => {
const endpointMethods = new Set(ctx.endpointList.map((endpoint) => endpoint.method.toLowerCase()));
+ // Use configured error status codes or default
+ const errorStatusCodes = ctx.errorStatusCodes ?? DEFAULT_ERROR_STATUS_CODES;
+
const file = `
import { queryOptions } from "@tanstack/react-query"
- import type { EndpointByMethod, ApiClient } from "${ctx.relativeApiClientPath}"
+ import type { EndpointByMethod, ApiClient, SafeApiResponse } from "${ctx.relativeApiClientPath}"
type EndpointQueryKey = [
TOptions & {
@@ -63,6 +76,8 @@ export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relati
type MaybeOptionalArg = RequiredKeys extends never ? [config?: T] : [config: T];
+ type ErrorStatusCode = ${errorStatusCodes.join(" | ")};
+
//
//
@@ -77,18 +92,20 @@ export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relati
path: Path,
...params: MaybeOptionalArg
) {
- const queryKey = createQueryKey(path, params[0]);
+ const queryKey = createQueryKey(path as string, params[0]);
const query = {
/** type-only property if you need easy access to the endpoint params */
"~endpoint": {} as TEndpoint,
queryKey,
queryOptions: queryOptions({
queryFn: async ({ queryKey, signal, }) => {
- const res = await this.client.${method}(path, {
- ...params,
- ...queryKey[0],
+ const requestParams = {
+ ...(params[0] || {}),
+ ...(queryKey[0] || {}),
signal,
- });
+ withResponse: false as const
+ };
+ const res = await this.client.${method}(path, requestParams);
return res as TEndpoint["response"];
},
queryKey: queryKey
@@ -96,11 +113,13 @@ export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relati
mutationOptions: {
mutationKey: queryKey,
mutationFn: async (localOptions: TEndpoint extends { parameters: infer Parameters} ? Parameters: never) => {
- const res = await this.client.${method}(path, {
- ...params,
- ...queryKey[0],
- ...localOptions,
- });
+ const requestParams = {
+ ...(params[0] || {}),
+ ...(queryKey[0] || {}),
+ ...(localOptions || {}),
+ withResponse: false as const
+ };
+ const res = await this.client.${method}(path, requestParams);
return res as TEndpoint["response"];
}
}
@@ -121,11 +140,34 @@ export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relati
TMethod extends keyof EndpointByMethod,
TPath extends keyof EndpointByMethod[TMethod],
TEndpoint extends EndpointByMethod[TMethod][TPath],
- TSelection,
- >(method: TMethod, path: TPath, selectFn?: (res: Omit & {
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/json) */
- json: () => Promise;
- }) => TSelection) {
+ TWithResponse extends boolean = false,
+ TSelection = TWithResponse extends true
+ ? SafeApiResponse
+ : TEndpoint extends { response: infer Res } ? Res : never,
+ TError = TEndpoint extends { responses: infer TResponses }
+ ? TResponses extends Record
+ ? {
+ [K in keyof TResponses]: K extends string
+ ? K extends \`\${infer TStatusCode extends number}\`
+ ? TStatusCode extends ErrorStatusCode
+ ? Omit & { status: TStatusCode; data: TResponses[K] }
+ : never
+ : never
+ : K extends number
+ ? K extends ErrorStatusCode
+ ? Omit & { status: K; data: TResponses[K] }
+ : never
+ : never;
+ }[keyof TResponses]
+ : Error
+ : Error
+ >(method: TMethod, path: TPath, options?: {
+ withResponse?: TWithResponse;
+ selectFn?: (res: TWithResponse extends true
+ ? SafeApiResponse
+ : TEndpoint extends { response: infer Res } ? Res : never
+ ) => TSelection;
+ }) {
const mutationKey = [{ method, path }] as const;
return {
/** type-only property if you need easy access to the endpoint params */
@@ -133,14 +175,45 @@ export const generateTanstackQueryFile = async (ctx: GeneratorContext & { relati
mutationKey: mutationKey,
mutationOptions: {
mutationKey: mutationKey,
- mutationFn: async (params: TEndpoint extends { parameters: infer Parameters } ? Parameters : never) => {
- const response = await this.client.request(method, path, params);
- const res = selectFn ? selectFn(response) : response
- return res as unknown extends TSelection ? typeof response : Awaited
- },
- },
- };
+ mutationFn: async (params: TEndpoint extends { parameters: infer Parameters } ? Parameters : never): Promise => {
+ const withResponse = options?.withResponse ?? false;
+ const selectFn = options?.selectFn;
+
+ if (withResponse) {
+ // Type assertion is safe because we're handling the method dynamically
+ const response = await (this.client as any)[method](path, { ...params as any, withResponse: true });
+ if (!response.ok) {
+ // Create a Response-like error object with additional data property
+ const error = Object.assign(Object.create(Response.prototype), {
+ ...response,
+ data: response.data
+ }) as TError;
+ throw error;
+ }
+ const res = selectFn ? selectFn(response as any) : response;
+ return res as TSelection;
+ }
+
+ // Type assertion is safe because we're handling the method dynamically
+ // Always get the full response for error handling, even when withResponse is false
+ const response = await (this.client as any)[method](path, { ...params as any, withResponse: true });
+ if (!response.ok) {
+ // Create a Response-like error object with additional data property
+ const error = Object.assign(Object.create(Response.prototype), {
+ ...response,
+ data: response.data
+ }) as TError;
+ throw error;
+ }
+
+ // Return just the data if withResponse is false, otherwise return the full response
+ const finalResponse = withResponse ? response : response.data;
+ const res = selectFn ? selectFn(finalResponse as any) : finalResponse;
+ return res as TSelection;
+ }
+ } as import("@tanstack/react-query").UseMutationOptions,
}
+ }
//
}
`;
diff --git a/packages/typed-openapi/tests/configurable-status-codes.test.ts b/packages/typed-openapi/tests/configurable-status-codes.test.ts
new file mode 100644
index 0000000..58200ae
--- /dev/null
+++ b/packages/typed-openapi/tests/configurable-status-codes.test.ts
@@ -0,0 +1,69 @@
+import { it, expect } from "vitest";
+import type { OpenAPIObject } from "openapi3-ts/oas31";
+
+import { generateFile } from "../src/generator.ts";
+import { mapOpenApiEndpoints } from "../src/map-openapi-endpoints.ts";
+import { prettify } from "../src/format.ts";
+
+it("should use custom success status codes", async () => {
+ const openApiDoc: OpenAPIObject = {
+ openapi: "3.0.0",
+ info: { title: "Test API", version: "1.0.0" },
+ paths: {
+ "/test": {
+ get: {
+ operationId: "getTest",
+ responses: {
+ 200: {
+ description: "Success",
+ content: {
+ "application/json": {
+ schema: { type: "object", properties: { message: { type: "string" } } },
+ },
+ },
+ },
+ 201: {
+ description: "Created",
+ content: {
+ "application/json": {
+ schema: { type: "object", properties: { id: { type: "string" } } },
+ },
+ },
+ },
+ 400: {
+ description: "Bad Request",
+ content: {
+ "application/json": {
+ schema: { type: "object", properties: { error: { type: "string" } } },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+
+ const endpoints = mapOpenApiEndpoints(openApiDoc);
+
+ // Test with default success status codes (should include 200 and 201)
+ const defaultGenerated = await prettify(generateFile(endpoints));
+ expect(defaultGenerated).toContain("export type SuccessStatusCode =");
+ expect(defaultGenerated).toContain("| 200");
+ expect(defaultGenerated).toContain("| 201");
+
+ // Test with custom success status codes (only 200)
+ const customGenerated = await prettify(
+ generateFile({
+ ...endpoints,
+ successStatusCodes: [200] as const,
+ }),
+ );
+
+ // Should only contain 200 in the StatusCode type
+ expect(customGenerated).toContain("export type SuccessStatusCode = 200;");
+ expect(customGenerated).not.toContain("| 201");
+
+ // The ApiResponse type should use the custom StatusCode
+ expect(customGenerated).toContain("TStatusCode extends SuccessStatusCode");
+});
diff --git a/packages/typed-openapi/tests/generator.test.ts b/packages/typed-openapi/tests/generator.test.ts
index b21f687..67b465f 100644
--- a/packages/typed-openapi/tests/generator.test.ts
+++ b/packages/typed-openapi/tests/generator.test.ts
@@ -57,6 +57,7 @@ describe("generator", () => {
body: Schemas.Pet;
};
response: Schemas.Pet;
+ responses: { 200: Schemas.Pet; 400: unknown; 404: unknown; 405: unknown };
};
export type post_AddPet = {
method: "POST";
@@ -66,6 +67,7 @@ describe("generator", () => {
body: Schemas.Pet;
};
response: Schemas.Pet;
+ responses: { 200: Schemas.Pet; 405: unknown };
};
export type get_FindPetsByStatus = {
method: "GET";
@@ -75,6 +77,7 @@ describe("generator", () => {
query: Partial<{ status: "available" | "pending" | "sold" }>;
};
response: Array;
+ responses: { 200: Array; 400: { code: number; message: string } };
};
export type get_FindPetsByTags = {
method: "GET";
@@ -84,6 +87,7 @@ describe("generator", () => {
query: Partial<{ tags: Array }>;
};
response: Array;
+ responses: { 200: Array; 400: unknown };
};
export type get_GetPetById = {
method: "GET";
@@ -93,6 +97,7 @@ describe("generator", () => {
path: { petId: number };
};
response: Schemas.Pet;
+ responses: { 200: Schemas.Pet; 400: { code: number; message: string }; 404: { code: number; message: string } };
};
export type post_UpdatePetWithForm = {
method: "POST";
@@ -103,6 +108,7 @@ describe("generator", () => {
path: { petId: number };
};
response: unknown;
+ responses: { 405: unknown };
};
export type delete_DeletePet = {
method: "DELETE";
@@ -113,6 +119,7 @@ describe("generator", () => {
header: Partial<{ api_key: string }>;
};
response: unknown;
+ responses: { 400: unknown };
};
export type post_UploadFile = {
method: "POST";
@@ -125,6 +132,7 @@ describe("generator", () => {
body: string;
};
response: Schemas.ApiResponse;
+ responses: { 200: Schemas.ApiResponse };
};
export type get_GetInventory = {
method: "GET";
@@ -132,6 +140,7 @@ describe("generator", () => {
requestFormat: "json";
parameters: never;
response: Record;
+ responses: { 200: Record };
};
export type post_PlaceOrder = {
method: "POST";
@@ -141,6 +150,7 @@ describe("generator", () => {
body: Schemas.Order;
};
response: Schemas.Order;
+ responses: { 200: Schemas.Order; 405: unknown };
};
export type get_GetOrderById = {
method: "GET";
@@ -150,6 +160,7 @@ describe("generator", () => {
path: { orderId: number };
};
response: Schemas.Order;
+ responses: { 200: Schemas.Order; 400: unknown; 404: unknown };
};
export type delete_DeleteOrder = {
method: "DELETE";
@@ -159,6 +170,7 @@ describe("generator", () => {
path: { orderId: number };
};
response: unknown;
+ responses: { 400: unknown; 404: unknown };
};
export type post_CreateUser = {
method: "POST";
@@ -168,6 +180,7 @@ describe("generator", () => {
body: Schemas.User;
};
response: Schemas.User;
+ responses: { default: Schemas.User };
};
export type post_CreateUsersWithListInput = {
method: "POST";
@@ -177,6 +190,7 @@ describe("generator", () => {
body: Array;
};
response: Schemas.User;
+ responses: { 200: Schemas.User; default: unknown };
};
export type get_LoginUser = {
method: "GET";
@@ -186,6 +200,7 @@ describe("generator", () => {
query: Partial<{ username: string; password: string }>;
};
response: string;
+ responses: { 200: string; 400: unknown };
responseHeaders: { "x-rate-limit": number; "x-expires-after": string };
};
export type get_LogoutUser = {
@@ -194,6 +209,7 @@ describe("generator", () => {
requestFormat: "json";
parameters: never;
response: unknown;
+ responses: { default: unknown };
};
export type get_GetUserByName = {
method: "GET";
@@ -203,6 +219,7 @@ describe("generator", () => {
path: { username: string };
};
response: Schemas.User;
+ responses: { 200: Schemas.User; 400: unknown; 404: unknown };
};
export type put_UpdateUser = {
method: "PUT";
@@ -214,6 +231,7 @@ describe("generator", () => {
body: Schemas.User;
};
response: unknown;
+ responses: { default: unknown };
};
export type delete_DeleteUser = {
method: "DELETE";
@@ -223,6 +241,7 @@ describe("generator", () => {
path: { username: string };
};
response: unknown;
+ responses: { 400: unknown; 404: unknown };
};
//
@@ -284,6 +303,7 @@ describe("generator", () => {
export type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: unknown;
+ responses?: Record;
responseHeaders?: Record;
};
@@ -299,11 +319,97 @@ describe("generator", () => {
areParametersRequired: boolean;
};
response: TConfig["response"];
+ responses?: TConfig["responses"];
responseHeaders?: TConfig["responseHeaders"];
};
export type Fetcher = (method: Method, url: string, parameters?: EndpointParameters | undefined) => Promise;
+ // Status code type for success responses
+ export type SuccessStatusCode =
+ | 200
+ | 201
+ | 202
+ | 203
+ | 204
+ | 205
+ | 206
+ | 207
+ | 208
+ | 226
+ | 300
+ | 301
+ | 302
+ | 303
+ | 304
+ | 305
+ | 306
+ | 307
+ | 308;
+
+ // Error handling types
+ export type TypedApiResponse<
+ TSuccess,
+ TAllResponses extends Record = {},
+ > = keyof TAllResponses extends never
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : {
+ [K in keyof TAllResponses]: K extends string
+ ? K extends \`\${infer TStatusCode extends number}\`
+ ? TStatusCode extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: TStatusCode;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: TStatusCode;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never
+ : K extends number
+ ? K extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: K;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: K;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never;
+ }[keyof TAllResponses];
+
+ export type SafeApiResponse = TEndpoint extends { response: infer TSuccess; responses: infer TResponses }
+ ? TResponses extends Record
+ ? TypedApiResponse
+ : Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : TEndpoint extends { response: infer TSuccess }
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : never;
+
type RequiredKeys = {
[P in keyof T]-?: undefined extends T[P] ? never : P;
}[keyof T];
@@ -334,44 +440,182 @@ describe("generator", () => {
//
put(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("put", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ put(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ put(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("put", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("put", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
//
post(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("post", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("post", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("post", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
//
get(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("get", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("get", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("get", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
//
delete(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("delete", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ delete(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ delete(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher(
+ "delete",
+ this.baseUrl + path,
+ Object.keys(fetchParams).length ? fetchParams : undefined,
+ ).then(async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ });
+ } else {
+ return this.fetcher("delete", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
@@ -410,6 +654,21 @@ describe("generator", () => {
api.get("/users").then((users) => console.log(users));
api.post("/users", { body: { name: "John" } }).then((user) => console.log(user));
api.put("/users/:id", { path: { id: 1 }, body: { name: "John" } }).then((user) => console.log(user));
+
+ // With error handling
+ const result = await api.get("/users/{id}", { path: { id: "123" }, withResponse: true });
+ if (result.ok) {
+ // Access data directly
+ const user = result.data;
+ console.log(user);
+
+ // Or use the json() method for compatibility
+ const userFromJson = await result.json();
+ console.log(userFromJson);
+ } else {
+ const error = result.data;
+ console.error(\`Error \${result.status}:\`, error);
+ }
*/
// {
profilePictureURL?: (string | null) | undefined;
}>;
};
+ responses: {
+ 200: {
+ members: Array<{
+ id: string;
+ firstName?: (string | null) | undefined;
+ lastName?: (string | null) | undefined;
+ email: string;
+ profilePictureURL?: (string | null) | undefined;
+ }>;
+ };
+ };
};
//
@@ -721,6 +991,7 @@ describe("generator", () => {
export type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: unknown;
+ responses?: Record;
responseHeaders?: Record;
};
@@ -736,11 +1007,97 @@ describe("generator", () => {
areParametersRequired: boolean;
};
response: TConfig["response"];
+ responses?: TConfig["responses"];
responseHeaders?: TConfig["responseHeaders"];
};
export type Fetcher = (method: Method, url: string, parameters?: EndpointParameters | undefined) => Promise;
+ // Status code type for success responses
+ export type SuccessStatusCode =
+ | 200
+ | 201
+ | 202
+ | 203
+ | 204
+ | 205
+ | 206
+ | 207
+ | 208
+ | 226
+ | 300
+ | 301
+ | 302
+ | 303
+ | 304
+ | 305
+ | 306
+ | 307
+ | 308;
+
+ // Error handling types
+ export type TypedApiResponse<
+ TSuccess,
+ TAllResponses extends Record = {},
+ > = keyof TAllResponses extends never
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : {
+ [K in keyof TAllResponses]: K extends string
+ ? K extends \`\${infer TStatusCode extends number}\`
+ ? TStatusCode extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: TStatusCode;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: TStatusCode;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never
+ : K extends number
+ ? K extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: K;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: K;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never;
+ }[keyof TAllResponses];
+
+ export type SafeApiResponse = TEndpoint extends { response: infer TSuccess; responses: infer TResponses }
+ ? TResponses extends Record
+ ? TypedApiResponse
+ : Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : TEndpoint extends { response: infer TSuccess }
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : never;
+
type RequiredKeys = {
[P in keyof T]-?: undefined extends T[P] ? never : P;
}[keyof T];
@@ -771,11 +1128,45 @@ describe("generator", () => {
//
get(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("get", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("get", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("get", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
@@ -814,6 +1205,21 @@ describe("generator", () => {
api.get("/users").then((users) => console.log(users));
api.post("/users", { body: { name: "John" } }).then((user) => console.log(user));
api.put("/users/:id", { path: { id: 1 }, body: { name: "John" } }).then((user) => console.log(user));
+
+ // With error handling
+ const result = await api.get("/users/{id}", { path: { id: "123" }, withResponse: true });
+ if (result.ok) {
+ // Access data directly
+ const user = result.data;
+ console.log(user);
+
+ // Or use the json() method for compatibility
+ const userFromJson = await result.json();
+ console.log(userFromJson);
+ } else {
+ const error = result.data;
+ console.error(\`Error \${result.status}:\`, error);
+ }
*/
// {
path: Partial<{ optionalInPath1: string; optionalInPath2: string }>;
};
response: string;
+ responses: { 200: string };
};
//
@@ -933,6 +1340,7 @@ describe("generator", () => {
export type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: unknown;
+ responses?: Record;
responseHeaders?: Record;
};
@@ -948,11 +1356,97 @@ describe("generator", () => {
areParametersRequired: boolean;
};
response: TConfig["response"];
+ responses?: TConfig["responses"];
responseHeaders?: TConfig["responseHeaders"];
};
export type Fetcher = (method: Method, url: string, parameters?: EndpointParameters | undefined) => Promise;
+ // Status code type for success responses
+ export type SuccessStatusCode =
+ | 200
+ | 201
+ | 202
+ | 203
+ | 204
+ | 205
+ | 206
+ | 207
+ | 208
+ | 226
+ | 300
+ | 301
+ | 302
+ | 303
+ | 304
+ | 305
+ | 306
+ | 307
+ | 308;
+
+ // Error handling types
+ export type TypedApiResponse<
+ TSuccess,
+ TAllResponses extends Record = {},
+ > = keyof TAllResponses extends never
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : {
+ [K in keyof TAllResponses]: K extends string
+ ? K extends \`\${infer TStatusCode extends number}\`
+ ? TStatusCode extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: TStatusCode;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: TStatusCode;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never
+ : K extends number
+ ? K extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: K;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: K;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never;
+ }[keyof TAllResponses];
+
+ export type SafeApiResponse = TEndpoint extends { response: infer TSuccess; responses: infer TResponses }
+ ? TResponses extends Record
+ ? TypedApiResponse
+ : Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : TEndpoint extends { response: infer TSuccess }
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : never;
+
type RequiredKeys = {
[P in keyof T]-?: undefined extends T[P] ? never : P;
}[keyof T];
@@ -983,11 +1477,45 @@ describe("generator", () => {
//
get(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("get", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("get", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("get", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
@@ -1026,10 +1554,48 @@ describe("generator", () => {
api.get("/users").then((users) => console.log(users));
api.post("/users", { body: { name: "John" } }).then((user) => console.log(user));
api.put("/users/:id", { path: { id: 1 }, body: { name: "John" } }).then((user) => console.log(user));
+
+ // With error handling
+ const result = await api.get("/users/{id}", { path: { id: "123" }, withResponse: true });
+ if (result.ok) {
+ // Access data directly
+ const user = result.data;
+ console.log(user);
+
+ // Or use the json() method for compatibility
+ const userFromJson = await result.json();
+ console.log(userFromJson);
+ } else {
+ const error = result.data;
+ console.error(\`Error \${result.status}:\`, error);
+ }
*/
// {
+ const openApiDoc = (await SwaggerParser.parse("./tests/samples/error-schemas.yaml")) as OpenAPIObject;
+ const generated = await prettify(generateFile(mapOpenApiEndpoints(openApiDoc)));
+
+ // Verify error schemas are generated
+ expect(generated).toContain("export type AuthError");
+ expect(generated).toContain("export type NotFoundError");
+ expect(generated).toContain("export type ValidationError");
+ expect(generated).toContain("export type ForbiddenError");
+ expect(generated).toContain("export type ServerError");
+
+ // Verify error responses are included in endpoint types
+ expect(generated).toContain('responses: { 200: Schemas.User; 401: Schemas.AuthError; 404: Schemas.NotFoundError; 500: Schemas.ServerError }');
+ expect(generated).toContain('responses: { 201: Schemas.Post; 400: Schemas.ValidationError; 403: Schemas.ForbiddenError }');
+
+ // Verify specific error schema structure
+ expect(generated).toContain("error: string");
+ expect(generated).toContain("code: number");
+ expect(generated).toContain("message: string");
+ expect(generated).toContain("field: string");
+ expect(generated).toContain("reason: string");
+ });
});
diff --git a/packages/typed-openapi/tests/include-client.test.ts b/packages/typed-openapi/tests/include-client.test.ts
new file mode 100644
index 0000000..f5ac1e7
--- /dev/null
+++ b/packages/typed-openapi/tests/include-client.test.ts
@@ -0,0 +1,69 @@
+import { it, expect } from "vitest";
+import type { OpenAPIObject } from "openapi3-ts/oas31";
+
+import { generateFile } from "../src/generator.ts";
+import { mapOpenApiEndpoints } from "../src/map-openapi-endpoints.ts";
+import { prettify } from "../src/format.ts";
+
+it("should exclude API client when includeClient is false", async () => {
+ const openApiDoc: OpenAPIObject = {
+ openapi: "3.0.0",
+ info: { title: "Test API", version: "1.0.0" },
+ paths: {
+ "/test": {
+ get: {
+ operationId: "getTest",
+ responses: {
+ 200: {
+ description: "Success",
+ content: {
+ "application/json": {
+ schema: { type: "object", properties: { message: { type: "string" } } },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+
+ const endpoints = mapOpenApiEndpoints(openApiDoc);
+
+ // Test with includeClient: false
+ const withoutClient = await prettify(
+ generateFile({
+ ...endpoints,
+ includeClient: false,
+ }),
+ );
+
+ // Should not contain ApiClientTypes or ApiClient sections
+ expect(withoutClient).not.toContain("// ");
+ expect(withoutClient).not.toContain("// ");
+ expect(withoutClient).not.toContain("export class ApiClient");
+ expect(withoutClient).not.toContain("export type EndpointParameters");
+ expect(withoutClient).not.toContain("export type SuccessStatusCode");
+ expect(withoutClient).not.toContain("export type TypedApiResponse");
+
+ // Should still contain schemas and endpoints
+ expect(withoutClient).toContain("export namespace Schemas");
+ expect(withoutClient).toContain("export namespace Endpoints");
+ expect(withoutClient).toContain("export type EndpointByMethod");
+
+ // Test with includeClient: true (default)
+ const withClient = await prettify(
+ generateFile({
+ ...endpoints,
+ includeClient: true,
+ }),
+ );
+
+ // Should contain ApiClientTypes and ApiClient sections
+ expect(withClient).toContain("// ");
+ expect(withClient).toContain("// ");
+ expect(withClient).toContain("export class ApiClient");
+ expect(withClient).toContain("export type EndpointParameters");
+ expect(withClient).toContain("export type SuccessStatusCode");
+ expect(withClient).toContain("export type TypedApiResponse");
+});
diff --git a/packages/typed-openapi/tests/map-openapi-endpoints.test.ts b/packages/typed-openapi/tests/map-openapi-endpoints.test.ts
index f3bf3b2..430cf38 100644
--- a/packages/typed-openapi/tests/map-openapi-endpoints.test.ts
+++ b/packages/typed-openapi/tests/map-openapi-endpoints.test.ts
@@ -495,6 +495,27 @@ describe("map-openapi-endpoints", () => {
"description": "successful operation",
},
"400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "code": {
+ "example": 400,
+ "type": "integer",
+ },
+ "message": {
+ "example": "Invalid status value",
+ "type": "string",
+ },
+ },
+ "required": [
+ "code",
+ "message",
+ ],
+ "type": "object",
+ },
+ },
+ },
"description": "Invalid status value",
},
},
@@ -646,9 +667,51 @@ describe("map-openapi-endpoints", () => {
"description": "successful operation",
},
"400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "code": {
+ "example": 400,
+ "type": "integer",
+ },
+ "message": {
+ "example": "Invalid pet ID",
+ "type": "string",
+ },
+ },
+ "required": [
+ "code",
+ "message",
+ ],
+ "type": "object",
+ },
+ },
+ },
"description": "Invalid ID supplied",
},
"404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "code": {
+ "example": 404,
+ "type": "integer",
+ },
+ "message": {
+ "example": "Pet not found",
+ "type": "string",
+ },
+ },
+ "required": [
+ "code",
+ "message",
+ ],
+ "type": "object",
+ },
+ },
+ },
"description": "Pet not found",
},
},
@@ -1325,6 +1388,24 @@ describe("map-openapi-endpoints", () => {
"type": "ref",
"value": "Pet",
},
+ "responses": {
+ "200": {
+ "type": "ref",
+ "value": "Pet",
+ },
+ "400": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ "404": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ "405": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -1402,6 +1483,16 @@ describe("map-openapi-endpoints", () => {
"type": "ref",
"value": "Pet",
},
+ "responses": {
+ "200": {
+ "type": "ref",
+ "value": "Pet",
+ },
+ "405": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -1454,6 +1545,27 @@ describe("map-openapi-endpoints", () => {
"description": "successful operation",
},
"400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "code": {
+ "example": 400,
+ "type": "integer",
+ },
+ "message": {
+ "example": "Invalid status value",
+ "type": "string",
+ },
+ },
+ "required": [
+ "code",
+ "message",
+ ],
+ "type": "object",
+ },
+ },
+ },
"description": "Invalid status value",
},
},
@@ -1482,6 +1594,16 @@ describe("map-openapi-endpoints", () => {
"type": "array",
"value": "Array",
},
+ "responses": {
+ "200": {
+ "type": "array",
+ "value": "Array",
+ },
+ "400": {
+ "type": "object",
+ "value": "{ code: number, message: string }",
+ },
+ },
},
{
"meta": {
@@ -1559,6 +1681,16 @@ describe("map-openapi-endpoints", () => {
"type": "array",
"value": "Array",
},
+ "responses": {
+ "200": {
+ "type": "array",
+ "value": "Array",
+ },
+ "400": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -1599,9 +1731,51 @@ describe("map-openapi-endpoints", () => {
"description": "successful operation",
},
"400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "code": {
+ "example": 400,
+ "type": "integer",
+ },
+ "message": {
+ "example": "Invalid pet ID",
+ "type": "string",
+ },
+ },
+ "required": [
+ "code",
+ "message",
+ ],
+ "type": "object",
+ },
+ },
+ },
"description": "Invalid ID supplied",
},
"404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "code": {
+ "example": 404,
+ "type": "integer",
+ },
+ "message": {
+ "example": "Pet not found",
+ "type": "string",
+ },
+ },
+ "required": [
+ "code",
+ "message",
+ ],
+ "type": "object",
+ },
+ },
+ },
"description": "Pet not found",
},
},
@@ -1635,6 +1809,20 @@ describe("map-openapi-endpoints", () => {
"type": "ref",
"value": "Pet",
},
+ "responses": {
+ "200": {
+ "type": "ref",
+ "value": "Pet",
+ },
+ "400": {
+ "type": "object",
+ "value": "{ code: number, message: string }",
+ },
+ "404": {
+ "type": "object",
+ "value": "{ code: number, message: string }",
+ },
+ },
},
{
"meta": {
@@ -1710,6 +1898,12 @@ describe("map-openapi-endpoints", () => {
"type": "keyword",
"value": "unknown",
},
+ "responses": {
+ "405": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -1778,6 +1972,12 @@ describe("map-openapi-endpoints", () => {
"type": "keyword",
"value": "unknown",
},
+ "responses": {
+ "400": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -1867,6 +2067,12 @@ describe("map-openapi-endpoints", () => {
"type": "ref",
"value": "ApiResponse",
},
+ "responses": {
+ "200": {
+ "type": "ref",
+ "value": "ApiResponse",
+ },
+ },
},
{
"meta": {
@@ -1911,6 +2117,12 @@ describe("map-openapi-endpoints", () => {
"type": "literal",
"value": "Record",
},
+ "responses": {
+ "200": {
+ "type": "literal",
+ "value": "Record",
+ },
+ },
},
{
"meta": {
@@ -1973,6 +2185,16 @@ describe("map-openapi-endpoints", () => {
"type": "ref",
"value": "Order",
},
+ "responses": {
+ "200": {
+ "type": "ref",
+ "value": "Order",
+ },
+ "405": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -2038,6 +2260,20 @@ describe("map-openapi-endpoints", () => {
"type": "ref",
"value": "Order",
},
+ "responses": {
+ "200": {
+ "type": "ref",
+ "value": "Order",
+ },
+ "400": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ "404": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -2088,6 +2324,16 @@ describe("map-openapi-endpoints", () => {
"type": "keyword",
"value": "unknown",
},
+ "responses": {
+ "400": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ "404": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -2153,6 +2399,12 @@ describe("map-openapi-endpoints", () => {
"type": "ref",
"value": "User",
},
+ "responses": {
+ "default": {
+ "type": "ref",
+ "value": "User",
+ },
+ },
},
{
"meta": {
@@ -2213,6 +2465,16 @@ describe("map-openapi-endpoints", () => {
"type": "ref",
"value": "User",
},
+ "responses": {
+ "200": {
+ "type": "ref",
+ "value": "User",
+ },
+ "default": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -2307,6 +2569,16 @@ describe("map-openapi-endpoints", () => {
"value": "number",
},
},
+ "responses": {
+ "200": {
+ "type": "keyword",
+ "value": "string",
+ },
+ "400": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -2336,6 +2608,12 @@ describe("map-openapi-endpoints", () => {
"type": "keyword",
"value": "unknown",
},
+ "responses": {
+ "default": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -2400,6 +2678,20 @@ describe("map-openapi-endpoints", () => {
"type": "ref",
"value": "User",
},
+ "responses": {
+ "200": {
+ "type": "ref",
+ "value": "User",
+ },
+ "400": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ "404": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -2470,6 +2762,12 @@ describe("map-openapi-endpoints", () => {
"type": "keyword",
"value": "unknown",
},
+ "responses": {
+ "default": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
{
"meta": {
@@ -2519,6 +2817,16 @@ describe("map-openapi-endpoints", () => {
"type": "keyword",
"value": "unknown",
},
+ "responses": {
+ "400": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ "404": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
],
"factory": {
@@ -2690,6 +2998,12 @@ describe("map-openapi-endpoints", () => {
"type": "keyword",
"value": "unknown",
},
+ "responses": {
+ "200": {
+ "type": "keyword",
+ "value": "unknown",
+ },
+ },
},
]
`);
@@ -2907,8 +3221,78 @@ describe("map-openapi-endpoints", () => {
"type": "ref",
"value": "SerializedUserSession",
},
+ "responses": {
+ "200": {
+ "type": "ref",
+ "value": "SerializedUserSession",
+ },
+ "401": {
+ "type": "keyword",
+ "value": "string",
+ },
+ "500": {
+ "type": "keyword",
+ "value": "string",
+ },
+ },
},
]
`);
});
+
+ test("error schemas", async ({ expect }) => {
+ const openApiDoc = (await SwaggerParser.parse("./tests/samples/error-schemas.yaml")) as OpenAPIObject;
+ const result = mapOpenApiEndpoints(openApiDoc);
+
+ // Find the getUserById endpoint
+ const getUserEndpoint = result.endpointList.find(e => e.meta.alias === "get_GetUserById");
+ expect(getUserEndpoint).toBeDefined();
+ expect(getUserEndpoint?.responses).toMatchInlineSnapshot(`
+ {
+ "200": {
+ "type": "ref",
+ "value": "User",
+ },
+ "401": {
+ "type": "ref",
+ "value": "AuthError",
+ },
+ "404": {
+ "type": "ref",
+ "value": "NotFoundError",
+ },
+ "500": {
+ "type": "ref",
+ "value": "ServerError",
+ },
+ }
+ `);
+
+ // Find the createPost endpoint
+ const createPostEndpoint = result.endpointList.find(e => e.meta.alias === "post_CreatePost");
+ expect(createPostEndpoint).toBeDefined();
+ expect(createPostEndpoint?.responses).toMatchInlineSnapshot(`
+ {
+ "201": {
+ "type": "ref",
+ "value": "Post",
+ },
+ "400": {
+ "type": "ref",
+ "value": "ValidationError",
+ },
+ "403": {
+ "type": "ref",
+ "value": "ForbiddenError",
+ },
+ }
+ `);
+
+ // Verify that error schemas are properly resolved
+ const authErrorBox = result.refs.getInfosByRef("#/components/schemas/AuthError");
+ expect(authErrorBox?.name).toBe("AuthError");
+
+ const validationErrorBox = result.refs.getInfosByRef("#/components/schemas/ValidationError");
+ expect(validationErrorBox?.name).toBe("ValidationError");
+ });
});
diff --git a/packages/typed-openapi/tests/multiple-success-responses.test.ts b/packages/typed-openapi/tests/multiple-success-responses.test.ts
new file mode 100644
index 0000000..5f088a2
--- /dev/null
+++ b/packages/typed-openapi/tests/multiple-success-responses.test.ts
@@ -0,0 +1,399 @@
+import { describe, test } from "vitest";
+import type { OpenAPIObject } from "openapi3-ts/oas31";
+import { mapOpenApiEndpoints } from "../src/map-openapi-endpoints.js";
+import { generateFile } from "../src/generator.js";
+import { prettify } from "../src/format.js";
+
+describe("multiple success responses", () => {
+ test("should handle 200 vs 201 responses with different schemas", async ({ expect }) => {
+ const openApiDoc: OpenAPIObject = {
+ openapi: "3.0.3",
+ info: {
+ title: "Multi Success API",
+ version: "1.0.0"
+ },
+ paths: {
+ "/users": {
+ post: {
+ operationId: "createOrUpdateUser",
+ requestBody: {
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ name: { type: "string" },
+ email: { type: "string" }
+ },
+ required: ["name", "email"]
+ }
+ }
+ }
+ },
+ responses: {
+ "200": {
+ description: "User updated",
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ id: { type: "string" },
+ name: { type: "string" },
+ email: { type: "string" },
+ updated: { type: "boolean", const: true },
+ updatedAt: { type: "string", format: "date-time" }
+ },
+ required: ["id", "name", "email", "updated", "updatedAt"]
+ }
+ }
+ }
+ },
+ "201": {
+ description: "User created",
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ id: { type: "string" },
+ name: { type: "string" },
+ email: { type: "string" },
+ created: { type: "boolean", const: true },
+ createdAt: { type: "string", format: "date-time" }
+ },
+ required: ["id", "name", "email", "created", "createdAt"]
+ }
+ }
+ }
+ },
+ "400": {
+ description: "Validation error",
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ message: { type: "string" },
+ errors: {
+ type: "array",
+ items: { type: "string" }
+ }
+ },
+ required: ["message", "errors"]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ const mapped = mapOpenApiEndpoints(openApiDoc);
+ const generated = await prettify(generateFile(mapped));
+
+ // Check that the endpoint has proper response types
+ expect(generated).toContain("post_CreateOrUpdateUser");
+
+ // Check that different success responses have different schemas
+ expect(generated).toContain("updated: boolean");
+ expect(generated).toContain("created: boolean");
+ expect(generated).toContain("Array");
+
+ // Verify the SafeApiResponse type is present for error handling
+ expect(generated).toContain("SafeApiResponse");
+
+ expect(generated).toMatchInlineSnapshot(`
+ "export namespace Schemas {
+ //
+ //
+ }
+
+ export namespace Endpoints {
+ //
+
+ export type post_CreateOrUpdateUser = {
+ method: "POST";
+ path: "/users";
+ requestFormat: "json";
+ parameters: {
+ body: { name: string; email: string };
+ };
+ response: { id: string; name: string; email: string; updated: boolean; updatedAt: string };
+ responses: {
+ 200: { id: string; name: string; email: string; updated: boolean; updatedAt: string };
+ 201: { id: string; name: string; email: string; created: boolean; createdAt: string };
+ 400: { message: string; errors: Array };
+ };
+ };
+
+ //
+ }
+
+ //
+ export type EndpointByMethod = {
+ post: {
+ "/users": Endpoints.post_CreateOrUpdateUser;
+ };
+ };
+
+ //
+
+ //
+ export type PostEndpoints = EndpointByMethod["post"];
+ //
+
+ //
+ export type EndpointParameters = {
+ body?: unknown;
+ query?: Record;
+ header?: Record;
+ path?: Record;
+ };
+
+ export type MutationMethod = "post" | "put" | "patch" | "delete";
+ export type Method = "get" | "head" | "options" | MutationMethod;
+
+ type RequestFormat = "json" | "form-data" | "form-url" | "binary" | "text";
+
+ export type DefaultEndpoint = {
+ parameters?: EndpointParameters | undefined;
+ response: unknown;
+ responses?: Record;
+ responseHeaders?: Record;
+ };
+
+ export type Endpoint = {
+ operationId: string;
+ method: Method;
+ path: string;
+ requestFormat: RequestFormat;
+ parameters?: TConfig["parameters"];
+ meta: {
+ alias: string;
+ hasParameters: boolean;
+ areParametersRequired: boolean;
+ };
+ response: TConfig["response"];
+ responses?: TConfig["responses"];
+ responseHeaders?: TConfig["responseHeaders"];
+ };
+
+ export type Fetcher = (method: Method, url: string, parameters?: EndpointParameters | undefined) => Promise;
+
+ // Status code type for success responses
+ export type SuccessStatusCode =
+ | 200
+ | 201
+ | 202
+ | 203
+ | 204
+ | 205
+ | 206
+ | 207
+ | 208
+ | 226
+ | 300
+ | 301
+ | 302
+ | 303
+ | 304
+ | 305
+ | 306
+ | 307
+ | 308;
+
+ // Error handling types
+ export type TypedApiResponse<
+ TSuccess,
+ TAllResponses extends Record = {},
+ > = keyof TAllResponses extends never
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : {
+ [K in keyof TAllResponses]: K extends string
+ ? K extends \`\${infer TStatusCode extends number}\`
+ ? TStatusCode extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: TStatusCode;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: TStatusCode;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never
+ : K extends number
+ ? K extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: K;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: K;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never;
+ }[keyof TAllResponses];
+
+ export type SafeApiResponse = TEndpoint extends { response: infer TSuccess; responses: infer TResponses }
+ ? TResponses extends Record
+ ? TypedApiResponse
+ : Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : TEndpoint extends { response: infer TSuccess }
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : never;
+
+ type RequiredKeys = {
+ [P in keyof T]-?: undefined extends T[P] ? never : P;
+ }[keyof T];
+
+ type MaybeOptionalArg = RequiredKeys extends never ? [config?: T] : [config: T];
+
+ //
+
+ //
+ export class ApiClient {
+ baseUrl: string = "";
+
+ constructor(public fetcher: Fetcher) {}
+
+ setBaseUrl(baseUrl: string) {
+ this.baseUrl = baseUrl;
+ return this;
+ }
+
+ parseResponse = async (response: Response): Promise => {
+ const contentType = response.headers.get("content-type");
+ if (contentType?.includes("application/json")) {
+ return response.json();
+ }
+ return response.text() as unknown as T;
+ };
+
+ //
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("post", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("post", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
+ }
+ //
+
+ //
+ /**
+ * Generic request method with full type-safety for any endpoint
+ */
+ request<
+ TMethod extends keyof EndpointByMethod,
+ TPath extends keyof EndpointByMethod[TMethod],
+ TEndpoint extends EndpointByMethod[TMethod][TPath],
+ >(
+ method: TMethod,
+ path: TPath,
+ ...params: MaybeOptionalArg
+ ): Promise<
+ Omit & {
+ /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/json) */
+ json: () => Promise;
+ }
+ > {
+ return this.fetcher(method, this.baseUrl + (path as string), params[0] as EndpointParameters);
+ }
+ //
+ }
+
+ export function createApiClient(fetcher: Fetcher, baseUrl?: string) {
+ return new ApiClient(fetcher).setBaseUrl(baseUrl ?? "");
+ }
+
+ /**
+ Example usage:
+ const api = createApiClient((method, url, params) =>
+ fetch(url, { method, body: JSON.stringify(params) }).then((res) => res.json()),
+ );
+ api.get("/users").then((users) => console.log(users));
+ api.post("/users", { body: { name: "John" } }).then((user) => console.log(user));
+ api.put("/users/:id", { path: { id: 1 }, body: { name: "John" } }).then((user) => console.log(user));
+
+ // With error handling
+ const result = await api.get("/users/{id}", { path: { id: "123" }, withResponse: true });
+ if (result.ok) {
+ // Access data directly
+ const user = result.data;
+ console.log(user);
+
+ // Or use the json() method for compatibility
+ const userFromJson = await result.json();
+ console.log(userFromJson);
+ } else {
+ const error = result.data;
+ console.error(\`Error \${result.status}:\`, error);
+ }
+ */
+
+ // ;
};
response: Array;
+ responses: { 200: Array; 400: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ContainerCreate = {
method: "POST";
@@ -885,6 +886,13 @@ export namespace Endpoints {
Partial<{ HostConfig: Schemas.HostConfig; NetworkingConfig: Schemas.NetworkingConfig }>;
};
response: Schemas.ContainerCreateResponse;
+ responses: {
+ 201: Schemas.ContainerCreateResponse;
+ 400: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 409: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type get_ContainerInspect = {
method: "GET";
@@ -921,6 +929,37 @@ export namespace Endpoints {
Config: Schemas.ContainerConfig;
NetworkSettings: Schemas.NetworkSettings;
}>;
+ responses: {
+ 200: Partial<{
+ Id: string;
+ Created: string;
+ Path: string;
+ Args: Array;
+ State: Schemas.ContainerState;
+ Image: string;
+ ResolvConfPath: string;
+ HostnamePath: string;
+ HostsPath: string;
+ LogPath: string;
+ Name: string;
+ RestartCount: number;
+ Driver: string;
+ Platform: string;
+ MountLabel: string;
+ ProcessLabel: string;
+ AppArmorProfile: string;
+ ExecIDs: Array | null;
+ HostConfig: Schemas.HostConfig;
+ GraphDriver: Schemas.GraphDriverData;
+ SizeRw: number;
+ SizeRootFs: number;
+ Mounts: Array;
+ Config: Schemas.ContainerConfig;
+ NetworkSettings: Schemas.NetworkSettings;
+ }>;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type get_ContainerTop = {
method: "GET";
@@ -931,6 +970,11 @@ export namespace Endpoints {
path: { id: string };
};
response: Partial<{ Titles: Array; Processes: Array> }>;
+ responses: {
+ 200: Partial<{ Titles: Array; Processes: Array> }>;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type get_ContainerLogs = {
method: "GET";
@@ -949,6 +993,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 200: unknown; 404: unknown; 500: unknown };
};
export type get_ContainerChanges = {
method: "GET";
@@ -958,6 +1003,7 @@ export namespace Endpoints {
path: { id: string };
};
response: Array;
+ responses: { 200: Array; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type get_ContainerExport = {
method: "GET";
@@ -967,6 +1013,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 200: unknown; 404: unknown; 500: unknown };
};
export type get_ContainerStats = {
method: "GET";
@@ -977,6 +1024,7 @@ export namespace Endpoints {
path: { id: string };
};
response: Record;
+ responses: { 200: Record; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ContainerResize = {
method: "POST";
@@ -987,6 +1035,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 200: unknown; 404: unknown; 500: unknown };
};
export type post_ContainerStart = {
method: "POST";
@@ -997,6 +1046,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 204: unknown; 304: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ContainerStop = {
method: "POST";
@@ -1007,6 +1057,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 204: unknown; 304: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ContainerRestart = {
method: "POST";
@@ -1017,6 +1068,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 204: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ContainerKill = {
method: "POST";
@@ -1027,6 +1079,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 204: unknown; 404: Schemas.ErrorResponse; 409: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ContainerUpdate = {
method: "POST";
@@ -1038,6 +1091,7 @@ export namespace Endpoints {
body: Schemas.Resources & Partial<{ RestartPolicy: Schemas.RestartPolicy }>;
};
response: Partial<{ Warnings: Array }>;
+ responses: { 200: Partial<{ Warnings: Array }>; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ContainerRename = {
method: "POST";
@@ -1048,6 +1102,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 204: unknown; 404: Schemas.ErrorResponse; 409: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ContainerPause = {
method: "POST";
@@ -1057,6 +1112,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 204: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ContainerUnpause = {
method: "POST";
@@ -1066,6 +1122,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 204: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ContainerAttach = {
method: "POST";
@@ -1083,6 +1140,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 101: unknown; 200: unknown; 400: unknown; 404: unknown; 500: unknown };
};
export type get_ContainerAttachWebsocket = {
method: "GET";
@@ -1100,6 +1158,13 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: {
+ 101: unknown;
+ 200: unknown;
+ 400: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type post_ContainerWait = {
method: "POST";
@@ -1110,6 +1175,12 @@ export namespace Endpoints {
path: { id: string };
};
response: Schemas.ContainerWaitResponse;
+ responses: {
+ 200: Schemas.ContainerWaitResponse;
+ 400: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type delete_ContainerDelete = {
method: "DELETE";
@@ -1120,6 +1191,13 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: {
+ 204: unknown;
+ 400: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 409: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type get_ContainerArchive = {
method: "GET";
@@ -1130,6 +1208,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 200: unknown; 400: unknown; 404: unknown; 500: unknown };
};
export type put_PutContainerArchive = {
method: "PUT";
@@ -1142,6 +1221,13 @@ export namespace Endpoints {
body: string;
};
response: unknown;
+ responses: {
+ 200: unknown;
+ 400: Schemas.ErrorResponse;
+ 403: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type head_ContainerArchiveInfo = {
method: "HEAD";
@@ -1152,6 +1238,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 200: unknown; 400: Schemas.ErrorResponse; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
responseHeaders: { "x-docker-container-path-stat": string };
};
export type post_ContainerPrune = {
@@ -1162,6 +1249,10 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Partial<{ ContainersDeleted: Array; SpaceReclaimed: number }>;
+ responses: {
+ 200: Partial<{ ContainersDeleted: Array; SpaceReclaimed: number }>;
+ 500: Schemas.ErrorResponse;
+ };
};
export type get_ImageList = {
method: "GET";
@@ -1171,6 +1262,7 @@ export namespace Endpoints {
query: Partial<{ all: boolean; filters: string; "shared-size": boolean; digests: boolean }>;
};
response: Array;
+ responses: { 200: Array; 500: Schemas.ErrorResponse };
};
export type post_ImageBuild = {
method: "POST";
@@ -1208,6 +1300,7 @@ export namespace Endpoints {
body: string;
};
response: unknown;
+ responses: { 200: unknown; 400: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_BuildPrune = {
method: "POST";
@@ -1217,6 +1310,7 @@ export namespace Endpoints {
query: Partial<{ "keep-storage": number; all: boolean; filters: string }>;
};
response: Partial<{ CachesDeleted: Array; SpaceReclaimed: number }>;
+ responses: { 200: Partial<{ CachesDeleted: Array; SpaceReclaimed: number }>; 500: Schemas.ErrorResponse };
};
export type post_ImageCreate = {
method: "POST";
@@ -1237,6 +1331,7 @@ export namespace Endpoints {
body: string;
};
response: unknown;
+ responses: { 200: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type get_ImageInspect = {
method: "GET";
@@ -1246,6 +1341,7 @@ export namespace Endpoints {
path: { name: string };
};
response: Schemas.ImageInspect;
+ responses: { 200: Schemas.ImageInspect; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type get_ImageHistory = {
method: "GET";
@@ -1262,6 +1358,18 @@ export namespace Endpoints {
Size: number;
Comment: string;
}>;
+ responses: {
+ 200: Array<{
+ Id: string;
+ Created: number;
+ CreatedBy: string;
+ Tags: Array;
+ Size: number;
+ Comment: string;
+ }>;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type post_ImagePush = {
method: "POST";
@@ -1273,6 +1381,7 @@ export namespace Endpoints {
header: { "X-Registry-Auth": string };
};
response: unknown;
+ responses: { 200: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_ImageTag = {
method: "POST";
@@ -1283,6 +1392,13 @@ export namespace Endpoints {
path: { name: string };
};
response: unknown;
+ responses: {
+ 201: unknown;
+ 400: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 409: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type delete_ImageDelete = {
method: "DELETE";
@@ -1293,6 +1409,12 @@ export namespace Endpoints {
path: { name: string };
};
response: Array;
+ responses: {
+ 200: Array;
+ 404: Schemas.ErrorResponse;
+ 409: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type get_ImageSearch = {
method: "GET";
@@ -1304,6 +1426,12 @@ export namespace Endpoints {
response: Array<
Partial<{ description: string; is_official: boolean; is_automated: boolean; name: string; star_count: number }>
>;
+ responses: {
+ 200: Array<
+ Partial<{ description: string; is_official: boolean; is_automated: boolean; name: string; star_count: number }>
+ >;
+ 500: Schemas.ErrorResponse;
+ };
};
export type post_ImagePrune = {
method: "POST";
@@ -1313,6 +1441,10 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Partial<{ ImagesDeleted: Array; SpaceReclaimed: number }>;
+ responses: {
+ 200: Partial<{ ImagesDeleted: Array; SpaceReclaimed: number }>;
+ 500: Schemas.ErrorResponse;
+ };
};
export type post_SystemAuth = {
method: "POST";
@@ -1321,7 +1453,13 @@ export namespace Endpoints {
parameters: {
body: Schemas.AuthConfig;
};
- response: unknown;
+ response: { Status: string; IdentityToken?: string | undefined };
+ responses: {
+ 200: { Status: string; IdentityToken?: string | undefined };
+ 204: unknown;
+ 401: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type get_SystemInfo = {
method: "GET";
@@ -1329,6 +1467,7 @@ export namespace Endpoints {
requestFormat: "json";
parameters: never;
response: Schemas.SystemInfo;
+ responses: { 200: Schemas.SystemInfo; 500: Schemas.ErrorResponse };
};
export type get_SystemVersion = {
method: "GET";
@@ -1336,6 +1475,7 @@ export namespace Endpoints {
requestFormat: "json";
parameters: never;
response: Schemas.SystemVersion;
+ responses: { 200: Schemas.SystemVersion; 500: Schemas.ErrorResponse };
};
export type get_SystemPing = {
method: "GET";
@@ -1343,6 +1483,7 @@ export namespace Endpoints {
requestFormat: "json";
parameters: never;
response: unknown;
+ responses: { 200: unknown; 500: unknown };
responseHeaders: {
swarm: "inactive" | "pending" | "error" | "locked" | "active/worker" | "active/manager";
"docker-experimental": boolean;
@@ -1358,6 +1499,7 @@ export namespace Endpoints {
requestFormat: "json";
parameters: never;
response: unknown;
+ responses: { 200: unknown; 500: unknown };
responseHeaders: {
swarm: "inactive" | "pending" | "error" | "locked" | "active/worker" | "active/manager";
"docker-experimental": boolean;
@@ -1385,6 +1527,7 @@ export namespace Endpoints {
body: Schemas.ContainerConfig;
};
response: Schemas.IdResponse;
+ responses: { 201: Schemas.IdResponse; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type get_SystemEvents = {
method: "GET";
@@ -1394,6 +1537,7 @@ export namespace Endpoints {
query: Partial<{ since: string; until: string; filters: string }>;
};
response: Schemas.EventMessage;
+ responses: { 200: Schemas.EventMessage; 400: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type get_SystemDataUsage = {
method: "GET";
@@ -1409,6 +1553,16 @@ export namespace Endpoints {
Volumes: Array;
BuildCache: Array;
}>;
+ responses: {
+ 200: Partial<{
+ LayersSize: number;
+ Images: Array;
+ Containers: Array;
+ Volumes: Array;
+ BuildCache: Array;
+ }>;
+ 500: Schemas.ErrorResponse;
+ };
};
export type get_ImageGet = {
method: "GET";
@@ -1418,6 +1572,7 @@ export namespace Endpoints {
path: { name: string };
};
response: unknown;
+ responses: { 200: unknown; 500: unknown };
};
export type get_ImageGetAll = {
method: "GET";
@@ -1427,6 +1582,7 @@ export namespace Endpoints {
query: Partial<{ names: Array }>;
};
response: unknown;
+ responses: { 200: unknown; 500: unknown };
};
export type post_ImageLoad = {
method: "POST";
@@ -1436,6 +1592,7 @@ export namespace Endpoints {
query: Partial<{ quiet: boolean }>;
};
response: unknown;
+ responses: { 200: unknown; 500: Schemas.ErrorResponse };
};
export type post_ContainerExec = {
method: "POST";
@@ -1459,6 +1616,12 @@ export namespace Endpoints {
}>;
};
response: Schemas.IdResponse;
+ responses: {
+ 201: Schemas.IdResponse;
+ 404: Schemas.ErrorResponse;
+ 409: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type post_ExecStart = {
method: "POST";
@@ -1470,6 +1633,7 @@ export namespace Endpoints {
body: Partial<{ Detach: boolean; Tty: boolean; ConsoleSize: Array | null }>;
};
response: unknown;
+ responses: { 200: unknown; 404: unknown; 409: unknown };
};
export type post_ExecResize = {
method: "POST";
@@ -1480,6 +1644,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 200: unknown; 400: Schemas.ErrorResponse; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type get_ExecInspect = {
method: "GET";
@@ -1501,6 +1666,23 @@ export namespace Endpoints {
ContainerID: string;
Pid: number;
}>;
+ responses: {
+ 200: Partial<{
+ CanRemove: boolean;
+ DetachKeys: string;
+ ID: string;
+ Running: boolean;
+ ExitCode: number;
+ ProcessConfig: Schemas.ProcessConfig;
+ OpenStdin: boolean;
+ OpenStderr: boolean;
+ OpenStdout: boolean;
+ ContainerID: string;
+ Pid: number;
+ }>;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type get_VolumeList = {
method: "GET";
@@ -1510,6 +1692,7 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Schemas.VolumeListResponse;
+ responses: { 200: Schemas.VolumeListResponse; 500: Schemas.ErrorResponse };
};
export type post_VolumeCreate = {
method: "POST";
@@ -1519,6 +1702,7 @@ export namespace Endpoints {
body: Schemas.VolumeCreateOptions;
};
response: Schemas.Volume;
+ responses: { 201: Schemas.Volume; 500: Schemas.ErrorResponse };
};
export type get_VolumeInspect = {
method: "GET";
@@ -1528,6 +1712,7 @@ export namespace Endpoints {
path: { name: string };
};
response: Schemas.Volume;
+ responses: { 200: Schemas.Volume; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type put_VolumeUpdate = {
method: "PUT";
@@ -1540,6 +1725,13 @@ export namespace Endpoints {
body: Partial<{ Spec: Schemas.ClusterVolumeSpec }>;
};
response: unknown;
+ responses: {
+ 200: unknown;
+ 400: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type delete_VolumeDelete = {
method: "DELETE";
@@ -1550,6 +1742,7 @@ export namespace Endpoints {
path: { name: string };
};
response: unknown;
+ responses: { 204: unknown; 404: Schemas.ErrorResponse; 409: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_VolumePrune = {
method: "POST";
@@ -1559,6 +1752,7 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Partial<{ VolumesDeleted: Array; SpaceReclaimed: number }>;
+ responses: { 200: Partial<{ VolumesDeleted: Array; SpaceReclaimed: number }>; 500: Schemas.ErrorResponse };
};
export type get_NetworkList = {
method: "GET";
@@ -1568,6 +1762,7 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Array;
+ responses: { 200: Array; 500: Schemas.ErrorResponse };
};
export type get_NetworkInspect = {
method: "GET";
@@ -1578,6 +1773,7 @@ export namespace Endpoints {
path: { id: string };
};
response: Schemas.Network;
+ responses: { 200: Schemas.Network; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type delete_NetworkDelete = {
method: "DELETE";
@@ -1587,6 +1783,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 204: unknown; 403: Schemas.ErrorResponse; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_NetworkCreate = {
method: "POST";
@@ -1607,6 +1804,12 @@ export namespace Endpoints {
};
};
response: Partial<{ Id: string; Warning: string }>;
+ responses: {
+ 201: Partial<{ Id: string; Warning: string }>;
+ 403: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ };
};
export type post_NetworkConnect = {
method: "POST";
@@ -1618,6 +1821,7 @@ export namespace Endpoints {
body: Partial<{ Container: string; EndpointConfig: Schemas.EndpointSettings }>;
};
response: unknown;
+ responses: { 200: unknown; 403: Schemas.ErrorResponse; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_NetworkDisconnect = {
method: "POST";
@@ -1629,6 +1833,7 @@ export namespace Endpoints {
body: Partial<{ Container: string; Force: boolean }>;
};
response: unknown;
+ responses: { 200: unknown; 403: Schemas.ErrorResponse; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_NetworkPrune = {
method: "POST";
@@ -1638,6 +1843,7 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Partial<{ NetworksDeleted: Array }>;
+ responses: { 200: Partial<{ NetworksDeleted: Array }>; 500: Schemas.ErrorResponse };
};
export type get_PluginList = {
method: "GET";
@@ -1647,6 +1853,7 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Array;
+ responses: { 200: Array; 500: Schemas.ErrorResponse };
};
export type get_GetPluginPrivileges = {
method: "GET";
@@ -1656,6 +1863,7 @@ export namespace Endpoints {
query: { remote: string };
};
response: Array;
+ responses: { 200: Array; 500: Schemas.ErrorResponse };
};
export type post_PluginPull = {
method: "POST";
@@ -1668,6 +1876,7 @@ export namespace Endpoints {
body: Array;
};
response: unknown;
+ responses: { 204: unknown; 500: Schemas.ErrorResponse };
};
export type get_PluginInspect = {
method: "GET";
@@ -1677,6 +1886,7 @@ export namespace Endpoints {
path: { name: string };
};
response: Schemas.Plugin;
+ responses: { 200: Schemas.Plugin; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type delete_PluginDelete = {
method: "DELETE";
@@ -1687,6 +1897,7 @@ export namespace Endpoints {
path: { name: string };
};
response: Schemas.Plugin;
+ responses: { 200: Schemas.Plugin; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_PluginEnable = {
method: "POST";
@@ -1697,6 +1908,7 @@ export namespace Endpoints {
path: { name: string };
};
response: unknown;
+ responses: { 200: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_PluginDisable = {
method: "POST";
@@ -1707,6 +1919,7 @@ export namespace Endpoints {
path: { name: string };
};
response: unknown;
+ responses: { 200: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_PluginUpgrade = {
method: "POST";
@@ -1719,6 +1932,7 @@ export namespace Endpoints {
body: Array;
};
response: unknown;
+ responses: { 204: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_PluginCreate = {
method: "POST";
@@ -1728,6 +1942,7 @@ export namespace Endpoints {
query: { name: string };
};
response: unknown;
+ responses: { 204: unknown; 500: Schemas.ErrorResponse };
};
export type post_PluginPush = {
method: "POST";
@@ -1737,6 +1952,7 @@ export namespace Endpoints {
path: { name: string };
};
response: unknown;
+ responses: { 200: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_PluginSet = {
method: "POST";
@@ -1748,6 +1964,7 @@ export namespace Endpoints {
body: Array;
};
response: unknown;
+ responses: { 204: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type get_NodeList = {
method: "GET";
@@ -1757,6 +1974,7 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Array;
+ responses: { 200: Array; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type get_NodeInspect = {
method: "GET";
@@ -1766,6 +1984,12 @@ export namespace Endpoints {
path: { id: string };
};
response: Schemas.Node;
+ responses: {
+ 200: Schemas.Node;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type delete_NodeDelete = {
method: "DELETE";
@@ -1776,6 +2000,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 200: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_NodeUpdate = {
method: "POST";
@@ -1788,6 +2013,13 @@ export namespace Endpoints {
body: Schemas.NodeSpec;
};
response: unknown;
+ responses: {
+ 200: unknown;
+ 400: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type get_SwarmInspect = {
method: "GET";
@@ -1795,6 +2027,12 @@ export namespace Endpoints {
requestFormat: "json";
parameters: never;
response: Schemas.Swarm;
+ responses: {
+ 200: Schemas.Swarm;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type post_SwarmInit = {
method: "POST";
@@ -1813,6 +2051,7 @@ export namespace Endpoints {
}>;
};
response: string;
+ responses: { 200: string; 400: Schemas.ErrorResponse; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_SwarmJoin = {
method: "POST";
@@ -1828,6 +2067,7 @@ export namespace Endpoints {
}>;
};
response: unknown;
+ responses: { 200: unknown; 400: Schemas.ErrorResponse; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_SwarmLeave = {
method: "POST";
@@ -1837,6 +2077,7 @@ export namespace Endpoints {
query: Partial<{ force: boolean }>;
};
response: unknown;
+ responses: { 200: unknown; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_SwarmUpdate = {
method: "POST";
@@ -1853,6 +2094,7 @@ export namespace Endpoints {
body: Schemas.SwarmSpec;
};
response: unknown;
+ responses: { 200: unknown; 400: Schemas.ErrorResponse; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type get_SwarmUnlockkey = {
method: "GET";
@@ -1860,6 +2102,7 @@ export namespace Endpoints {
requestFormat: "json";
parameters: never;
response: Partial<{ UnlockKey: string }>;
+ responses: { 200: Partial<{ UnlockKey: string }>; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_SwarmUnlock = {
method: "POST";
@@ -1869,6 +2112,7 @@ export namespace Endpoints {
body: Partial<{ UnlockKey: string }>;
};
response: unknown;
+ responses: { 200: unknown; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type get_ServiceList = {
method: "GET";
@@ -1878,6 +2122,7 @@ export namespace Endpoints {
query: Partial<{ filters: string; status: boolean }>;
};
response: Array;
+ responses: { 200: Array; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_ServiceCreate = {
method: "POST";
@@ -1888,6 +2133,14 @@ export namespace Endpoints {
body: Schemas.ServiceSpec & Record;
};
response: Partial<{ ID: string; Warning: string }>;
+ responses: {
+ 201: Partial<{ ID: string; Warning: string }>;
+ 400: Schemas.ErrorResponse;
+ 403: Schemas.ErrorResponse;
+ 409: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type get_ServiceInspect = {
method: "GET";
@@ -1898,6 +2151,12 @@ export namespace Endpoints {
path: { id: string };
};
response: Schemas.Service;
+ responses: {
+ 200: Schemas.Service;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type delete_ServiceDelete = {
method: "DELETE";
@@ -1907,6 +2166,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 200: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_ServiceUpdate = {
method: "POST";
@@ -1923,6 +2183,13 @@ export namespace Endpoints {
body: Schemas.ServiceSpec & Record;
};
response: Schemas.ServiceUpdateResponse;
+ responses: {
+ 200: Schemas.ServiceUpdateResponse;
+ 400: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type get_ServiceLogs = {
method: "GET";
@@ -1941,6 +2208,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 200: unknown; 404: unknown; 500: unknown; 503: unknown };
};
export type get_TaskList = {
method: "GET";
@@ -1950,6 +2218,7 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Array;
+ responses: { 200: Array; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type get_TaskInspect = {
method: "GET";
@@ -1959,6 +2228,12 @@ export namespace Endpoints {
path: { id: string };
};
response: Schemas.Task;
+ responses: {
+ 200: Schemas.Task;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type get_TaskLogs = {
method: "GET";
@@ -1977,6 +2252,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 200: unknown; 404: unknown; 500: unknown; 503: unknown };
};
export type get_SecretList = {
method: "GET";
@@ -1986,6 +2262,7 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Array;
+ responses: { 200: Array; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_SecretCreate = {
method: "POST";
@@ -1995,6 +2272,12 @@ export namespace Endpoints {
body: Schemas.SecretSpec & Record;
};
response: Schemas.IdResponse;
+ responses: {
+ 201: Schemas.IdResponse;
+ 409: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type get_SecretInspect = {
method: "GET";
@@ -2004,6 +2287,12 @@ export namespace Endpoints {
path: { id: string };
};
response: Schemas.Secret;
+ responses: {
+ 200: Schemas.Secret;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type delete_SecretDelete = {
method: "DELETE";
@@ -2013,6 +2302,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 204: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_SecretUpdate = {
method: "POST";
@@ -2025,6 +2315,13 @@ export namespace Endpoints {
body: Schemas.SecretSpec;
};
response: unknown;
+ responses: {
+ 200: unknown;
+ 400: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type get_ConfigList = {
method: "GET";
@@ -2034,6 +2331,7 @@ export namespace Endpoints {
query: Partial<{ filters: string }>;
};
response: Array;
+ responses: { 200: Array; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_ConfigCreate = {
method: "POST";
@@ -2043,6 +2341,12 @@ export namespace Endpoints {
body: Schemas.ConfigSpec & Record;
};
response: Schemas.IdResponse;
+ responses: {
+ 201: Schemas.IdResponse;
+ 409: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type get_ConfigInspect = {
method: "GET";
@@ -2052,6 +2356,12 @@ export namespace Endpoints {
path: { id: string };
};
response: Schemas.Config;
+ responses: {
+ 200: Schemas.Config;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type delete_ConfigDelete = {
method: "DELETE";
@@ -2061,6 +2371,7 @@ export namespace Endpoints {
path: { id: string };
};
response: unknown;
+ responses: { 204: unknown; 404: Schemas.ErrorResponse; 500: Schemas.ErrorResponse; 503: Schemas.ErrorResponse };
};
export type post_ConfigUpdate = {
method: "POST";
@@ -2073,6 +2384,13 @@ export namespace Endpoints {
body: Schemas.ConfigSpec;
};
response: unknown;
+ responses: {
+ 200: unknown;
+ 400: Schemas.ErrorResponse;
+ 404: Schemas.ErrorResponse;
+ 500: Schemas.ErrorResponse;
+ 503: Schemas.ErrorResponse;
+ };
};
export type get_DistributionInspect = {
method: "GET";
@@ -2082,6 +2400,7 @@ export namespace Endpoints {
path: { name: string };
};
response: Schemas.DistributionInspect;
+ responses: { 200: Schemas.DistributionInspect; 401: Schemas.ErrorResponse; 500: Schemas.ErrorResponse };
};
export type post_Session = {
method: "POST";
@@ -2089,6 +2408,7 @@ export namespace Endpoints {
requestFormat: "json";
parameters: never;
response: unknown;
+ responses: { 101: unknown; 400: unknown; 500: unknown };
};
//
@@ -2241,6 +2561,7 @@ type RequestFormat = "json" | "form-data" | "form-url" | "binary" | "text";
export type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: unknown;
+ responses?: Record;
responseHeaders?: Record;
};
@@ -2256,11 +2577,97 @@ export type Endpoint = {
areParametersRequired: boolean;
};
response: TConfig["response"];
+ responses?: TConfig["responses"];
responseHeaders?: TConfig["responseHeaders"];
};
export type Fetcher = (method: Method, url: string, parameters?: EndpointParameters | undefined) => Promise;
+// Status code type for success responses
+export type SuccessStatusCode =
+ | 200
+ | 201
+ | 202
+ | 203
+ | 204
+ | 205
+ | 206
+ | 207
+ | 208
+ | 226
+ | 300
+ | 301
+ | 302
+ | 303
+ | 304
+ | 305
+ | 306
+ | 307
+ | 308;
+
+// Error handling types
+export type TypedApiResponse<
+ TSuccess,
+ TAllResponses extends Record = {},
+> = keyof TAllResponses extends never
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : {
+ [K in keyof TAllResponses]: K extends string
+ ? K extends `${infer TStatusCode extends number}`
+ ? TStatusCode extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: TStatusCode;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: TStatusCode;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never
+ : K extends number
+ ? K extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: K;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: K;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never;
+ }[keyof TAllResponses];
+
+export type SafeApiResponse = TEndpoint extends { response: infer TSuccess; responses: infer TResponses }
+ ? TResponses extends Record
+ ? TypedApiResponse
+ : Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : TEndpoint extends { response: infer TSuccess }
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : never;
+
type RequiredKeys = {
[P in keyof T]-?: undefined extends T[P] ? never : P;
}[keyof T];
@@ -2291,55 +2698,227 @@ export class ApiClient {
//
get(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("get", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("get", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("get", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
//
post(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("post", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("post", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("post", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
//
delete(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("delete", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ delete(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ delete(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher(
+ "delete",
+ this.baseUrl + path,
+ Object.keys(fetchParams).length ? fetchParams : undefined,
+ ).then(async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ });
+ } else {
+ return this.fetcher("delete", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
//
put(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("put", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ put(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ put(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("put", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("put", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
//
head(
path: Path,
- ...params: MaybeOptionalArg
- ): Promise {
- return this.fetcher("head", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise;
+ ...params: MaybeOptionalArg
+ ): Promise;
+
+ head(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise>;
+
+ head(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("head", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("head", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise;
+ }
}
//
@@ -2378,6 +2957,21 @@ export function createApiClient(fetcher: Fetcher, baseUrl?: string) {
api.get("/users").then((users) => console.log(users));
api.post("/users", { body: { name: "John" } }).then((user) => console.log(user));
api.put("/users/:id", { path: { id: 1 }, body: { name: "John" } }).then((user) => console.log(user));
+
+ // With error handling
+ const result = await api.get("/users/{id}", { path: { id: "123" }, withResponse: true });
+ if (result.ok) {
+ // Access data directly
+ const user = result.data;
+ console.log(user);
+
+ // Or use the json() method for compatibility
+ const userFromJson = await result.json();
+ console.log(userFromJson);
+ } else {
+ const error = result.data;
+ console.error(`Error ${result.status}:`, error);
+ }
*/
// ;
@@ -1764,6 +1769,13 @@ export const post_ContainerCreate = t.type({
]),
}),
response: ContainerCreateResponse,
+ responses: t.type({
+ "201": ContainerCreateResponse,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ContainerInspect = t.TypeOf;
@@ -1806,6 +1818,37 @@ export const get_ContainerInspect = t.type({
Config: t.union([t.undefined, ContainerConfig]),
NetworkSettings: t.union([t.undefined, NetworkSettings]),
}),
+ responses: t.type({
+ "200": t.type({
+ Id: t.union([t.undefined, t.string]),
+ Created: t.union([t.undefined, t.string]),
+ Path: t.union([t.undefined, t.string]),
+ Args: t.union([t.undefined, t.array(t.string)]),
+ State: t.union([t.undefined, ContainerState]),
+ Image: t.union([t.undefined, t.string]),
+ ResolvConfPath: t.union([t.undefined, t.string]),
+ HostnamePath: t.union([t.undefined, t.string]),
+ HostsPath: t.union([t.undefined, t.string]),
+ LogPath: t.union([t.undefined, t.string]),
+ Name: t.union([t.undefined, t.string]),
+ RestartCount: t.union([t.undefined, t.number]),
+ Driver: t.union([t.undefined, t.string]),
+ Platform: t.union([t.undefined, t.string]),
+ MountLabel: t.union([t.undefined, t.string]),
+ ProcessLabel: t.union([t.undefined, t.string]),
+ AppArmorProfile: t.union([t.undefined, t.string]),
+ ExecIDs: t.union([t.undefined, t.union([t.array(t.string), t.null])]),
+ HostConfig: t.union([t.undefined, HostConfig]),
+ GraphDriver: t.union([t.undefined, GraphDriverData]),
+ SizeRw: t.union([t.undefined, t.number]),
+ SizeRootFs: t.union([t.undefined, t.number]),
+ Mounts: t.union([t.undefined, t.array(MountPoint)]),
+ Config: t.union([t.undefined, ContainerConfig]),
+ NetworkSettings: t.union([t.undefined, NetworkSettings]),
+ }),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ContainerTop = t.TypeOf;
@@ -1825,6 +1868,14 @@ export const get_ContainerTop = t.type({
Titles: t.union([t.undefined, t.array(t.string)]),
Processes: t.union([t.undefined, t.array(t.array(t.string))]),
}),
+ responses: t.type({
+ "200": t.type({
+ Titles: t.union([t.undefined, t.array(t.string)]),
+ Processes: t.union([t.undefined, t.array(t.array(t.string))]),
+ }),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ContainerLogs = t.TypeOf;
@@ -1847,6 +1898,11 @@ export const get_ContainerLogs = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": t.unknown,
+ "500": t.unknown,
+ }),
});
export type get_ContainerChanges = t.TypeOf;
@@ -1860,6 +1916,11 @@ export const get_ContainerChanges = t.type({
}),
}),
response: t.array(FilesystemChange),
+ responses: t.type({
+ "200": t.array(FilesystemChange),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ContainerExport = t.TypeOf;
@@ -1873,6 +1934,11 @@ export const get_ContainerExport = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": t.unknown,
+ "500": t.unknown,
+ }),
});
export type get_ContainerStats = t.TypeOf;
@@ -1890,6 +1956,11 @@ export const get_ContainerStats = t.type({
}),
}),
response: t.record(t.string, t.unknown),
+ responses: t.type({
+ "200": t.record(t.string, t.unknown),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerResize = t.TypeOf;
@@ -1907,6 +1978,11 @@ export const post_ContainerResize = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": t.unknown,
+ "500": t.unknown,
+ }),
});
export type post_ContainerStart = t.TypeOf;
@@ -1923,6 +1999,12 @@ export const post_ContainerStart = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "304": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerStop = t.TypeOf;
@@ -1940,6 +2022,12 @@ export const post_ContainerStop = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "304": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerRestart = t.TypeOf;
@@ -1957,6 +2045,11 @@ export const post_ContainerRestart = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerKill = t.TypeOf;
@@ -1973,6 +2066,12 @@ export const post_ContainerKill = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerUpdate = t.TypeOf;
@@ -1994,6 +2093,13 @@ export const post_ContainerUpdate = t.type({
response: t.type({
Warnings: t.union([t.undefined, t.array(t.string)]),
}),
+ responses: t.type({
+ "200": t.type({
+ Warnings: t.union([t.undefined, t.array(t.string)]),
+ }),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerRename = t.TypeOf;
@@ -2010,6 +2116,12 @@ export const post_ContainerRename = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerPause = t.TypeOf;
@@ -2023,6 +2135,11 @@ export const post_ContainerPause = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerUnpause = t.TypeOf;
@@ -2036,6 +2153,11 @@ export const post_ContainerUnpause = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerAttach = t.TypeOf;
@@ -2057,6 +2179,13 @@ export const post_ContainerAttach = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "101": t.unknown,
+ "200": t.unknown,
+ "400": t.unknown,
+ "404": t.unknown,
+ "500": t.unknown,
+ }),
});
export type get_ContainerAttachWebsocket = t.TypeOf;
@@ -2078,6 +2207,13 @@ export const get_ContainerAttachWebsocket = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "101": t.unknown,
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerWait = t.TypeOf;
@@ -2097,6 +2233,12 @@ export const post_ContainerWait = t.type({
}),
}),
response: ContainerWaitResponse,
+ responses: t.type({
+ "200": ContainerWaitResponse,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type delete_ContainerDelete = t.TypeOf;
@@ -2115,6 +2257,13 @@ export const delete_ContainerDelete = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ContainerArchive = t.TypeOf;
@@ -2131,6 +2280,12 @@ export const get_ContainerArchive = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": t.unknown,
+ "404": t.unknown,
+ "500": t.unknown,
+ }),
});
export type put_PutContainerArchive = t.TypeOf;
@@ -2150,6 +2305,13 @@ export const put_PutContainerArchive = t.type({
body: t.string,
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "403": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type head_ContainerArchiveInfo = t.TypeOf;
@@ -2166,6 +2328,12 @@ export const head_ContainerArchiveInfo = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
responseHeaders: t.type({
"x-docker-container-path-stat": t.string,
}),
@@ -2185,6 +2353,13 @@ export const post_ContainerPrune = t.type({
ContainersDeleted: t.union([t.undefined, t.array(t.string)]),
SpaceReclaimed: t.union([t.undefined, t.number]),
}),
+ responses: t.type({
+ "200": t.type({
+ ContainersDeleted: t.union([t.undefined, t.array(t.string)]),
+ SpaceReclaimed: t.union([t.undefined, t.number]),
+ }),
+ "500": ErrorResponse,
+ }),
});
export type get_ImageList = t.TypeOf;
@@ -2201,6 +2376,10 @@ export const get_ImageList = t.type({
}),
}),
response: t.array(ImageSummary),
+ responses: t.type({
+ "200": t.array(ImageSummary),
+ "500": ErrorResponse,
+ }),
});
export type post_ImageBuild = t.TypeOf;
@@ -2242,6 +2421,11 @@ export const post_ImageBuild = t.type({
body: t.string,
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_BuildPrune = t.TypeOf;
@@ -2260,6 +2444,13 @@ export const post_BuildPrune = t.type({
CachesDeleted: t.union([t.undefined, t.array(t.string)]),
SpaceReclaimed: t.union([t.undefined, t.number]),
}),
+ responses: t.type({
+ "200": t.type({
+ CachesDeleted: t.union([t.undefined, t.array(t.string)]),
+ SpaceReclaimed: t.union([t.undefined, t.number]),
+ }),
+ "500": ErrorResponse,
+ }),
});
export type post_ImageCreate = t.TypeOf;
@@ -2283,6 +2474,11 @@ export const post_ImageCreate = t.type({
body: t.string,
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ImageInspect = t.TypeOf;
@@ -2296,6 +2492,11 @@ export const get_ImageInspect = t.type({
}),
}),
response: ImageInspect,
+ responses: t.type({
+ "200": ImageInspect,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ImageHistory = t.TypeOf;
@@ -2318,6 +2519,20 @@ export const get_ImageHistory = t.type({
Comment: t.string,
}),
),
+ responses: t.type({
+ "200": t.array(
+ t.type({
+ Id: t.string,
+ Created: t.number,
+ CreatedBy: t.string,
+ Tags: t.array(t.string),
+ Size: t.number,
+ Comment: t.string,
+ }),
+ ),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ImagePush = t.TypeOf;
@@ -2337,6 +2552,11 @@ export const post_ImagePush = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ImageTag = t.TypeOf;
@@ -2354,6 +2574,13 @@ export const post_ImageTag = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "201": t.unknown,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type delete_ImageDelete = t.TypeOf;
@@ -2371,6 +2598,12 @@ export const delete_ImageDelete = t.type({
}),
}),
response: t.array(ImageDeleteResponseItem),
+ responses: t.type({
+ "200": t.array(ImageDeleteResponseItem),
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ImageSearch = t.TypeOf;
@@ -2394,6 +2627,18 @@ export const get_ImageSearch = t.type({
star_count: t.union([t.undefined, t.number]),
}),
),
+ responses: t.type({
+ "200": t.array(
+ t.type({
+ description: t.union([t.undefined, t.string]),
+ is_official: t.union([t.undefined, t.boolean]),
+ is_automated: t.union([t.undefined, t.boolean]),
+ name: t.union([t.undefined, t.string]),
+ star_count: t.union([t.undefined, t.number]),
+ }),
+ ),
+ "500": ErrorResponse,
+ }),
});
export type post_ImagePrune = t.TypeOf;
@@ -2410,6 +2655,13 @@ export const post_ImagePrune = t.type({
ImagesDeleted: t.union([t.undefined, t.array(ImageDeleteResponseItem)]),
SpaceReclaimed: t.union([t.undefined, t.number]),
}),
+ responses: t.type({
+ "200": t.type({
+ ImagesDeleted: t.union([t.undefined, t.array(ImageDeleteResponseItem)]),
+ SpaceReclaimed: t.union([t.undefined, t.number]),
+ }),
+ "500": ErrorResponse,
+ }),
});
export type post_SystemAuth = t.TypeOf;
@@ -2420,7 +2672,19 @@ export const post_SystemAuth = t.type({
parameters: t.type({
body: AuthConfig,
}),
- response: t.unknown,
+ response: t.type({
+ Status: t.string,
+ IdentityToken: t.union([t.undefined, t.union([t.string, t.undefined])]),
+ }),
+ responses: t.type({
+ "200": t.type({
+ Status: t.string,
+ IdentityToken: t.union([t.undefined, t.union([t.string, t.undefined])]),
+ }),
+ "204": t.unknown,
+ "401": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_SystemInfo = t.TypeOf;
@@ -2430,6 +2694,10 @@ export const get_SystemInfo = t.type({
requestFormat: t.literal("json"),
parameters: t.never,
response: SystemInfo,
+ responses: t.type({
+ "200": SystemInfo,
+ "500": ErrorResponse,
+ }),
});
export type get_SystemVersion = t.TypeOf;
@@ -2439,6 +2707,10 @@ export const get_SystemVersion = t.type({
requestFormat: t.literal("json"),
parameters: t.never,
response: SystemVersion,
+ responses: t.type({
+ "200": SystemVersion,
+ "500": ErrorResponse,
+ }),
});
export type get_SystemPing = t.TypeOf;
@@ -2448,6 +2720,10 @@ export const get_SystemPing = t.type({
requestFormat: t.literal("json"),
parameters: t.never,
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "500": t.unknown,
+ }),
responseHeaders: t.type({
swarm: t.union([
t.literal("inactive"),
@@ -2472,6 +2748,10 @@ export const head_SystemPingHead = t.type({
requestFormat: t.literal("json"),
parameters: t.never,
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "500": t.unknown,
+ }),
responseHeaders: t.type({
swarm: t.union([
t.literal("inactive"),
@@ -2507,6 +2787,11 @@ export const post_ImageCommit = t.type({
body: ContainerConfig,
}),
response: IdResponse,
+ responses: t.type({
+ "201": IdResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_SystemEvents = t.TypeOf;
@@ -2522,6 +2807,11 @@ export const get_SystemEvents = t.type({
}),
}),
response: EventMessage,
+ responses: t.type({
+ "200": EventMessage,
+ "400": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_SystemDataUsage = t.TypeOf;
@@ -2544,6 +2834,16 @@ export const get_SystemDataUsage = t.type({
Volumes: t.union([t.undefined, t.array(Volume)]),
BuildCache: t.union([t.undefined, t.array(BuildCache)]),
}),
+ responses: t.type({
+ "200": t.type({
+ LayersSize: t.union([t.undefined, t.number]),
+ Images: t.union([t.undefined, t.array(ImageSummary)]),
+ Containers: t.union([t.undefined, t.array(ContainerSummary)]),
+ Volumes: t.union([t.undefined, t.array(Volume)]),
+ BuildCache: t.union([t.undefined, t.array(BuildCache)]),
+ }),
+ "500": ErrorResponse,
+ }),
});
export type get_ImageGet = t.TypeOf;
@@ -2557,6 +2857,10 @@ export const get_ImageGet = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "500": t.unknown,
+ }),
});
export type get_ImageGetAll = t.TypeOf;
@@ -2570,6 +2874,10 @@ export const get_ImageGetAll = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "500": t.unknown,
+ }),
});
export type post_ImageLoad = t.TypeOf;
@@ -2583,6 +2891,10 @@ export const post_ImageLoad = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerExec = t.TypeOf;
@@ -2609,6 +2921,12 @@ export const post_ContainerExec = t.type({
}),
}),
response: IdResponse,
+ responses: t.type({
+ "201": IdResponse,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ExecStart = t.TypeOf;
@@ -2627,6 +2945,11 @@ export const post_ExecStart = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": t.unknown,
+ "409": t.unknown,
+ }),
});
export type post_ExecResize = t.TypeOf;
@@ -2644,6 +2967,12 @@ export const post_ExecResize = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ExecInspect = t.TypeOf;
@@ -2669,6 +2998,23 @@ export const get_ExecInspect = t.type({
ContainerID: t.union([t.undefined, t.string]),
Pid: t.union([t.undefined, t.number]),
}),
+ responses: t.type({
+ "200": t.type({
+ CanRemove: t.union([t.undefined, t.boolean]),
+ DetachKeys: t.union([t.undefined, t.string]),
+ ID: t.union([t.undefined, t.string]),
+ Running: t.union([t.undefined, t.boolean]),
+ ExitCode: t.union([t.undefined, t.number]),
+ ProcessConfig: t.union([t.undefined, ProcessConfig]),
+ OpenStdin: t.union([t.undefined, t.boolean]),
+ OpenStderr: t.union([t.undefined, t.boolean]),
+ OpenStdout: t.union([t.undefined, t.boolean]),
+ ContainerID: t.union([t.undefined, t.string]),
+ Pid: t.union([t.undefined, t.number]),
+ }),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_VolumeList = t.TypeOf;
@@ -2682,6 +3028,10 @@ export const get_VolumeList = t.type({
}),
}),
response: VolumeListResponse,
+ responses: t.type({
+ "200": VolumeListResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_VolumeCreate = t.TypeOf;
@@ -2693,6 +3043,10 @@ export const post_VolumeCreate = t.type({
body: VolumeCreateOptions,
}),
response: Volume,
+ responses: t.type({
+ "201": Volume,
+ "500": ErrorResponse,
+ }),
});
export type get_VolumeInspect = t.TypeOf;
@@ -2706,6 +3060,11 @@ export const get_VolumeInspect = t.type({
}),
}),
response: Volume,
+ responses: t.type({
+ "200": Volume,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type put_VolumeUpdate = t.TypeOf;
@@ -2725,6 +3084,13 @@ export const put_VolumeUpdate = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type delete_VolumeDelete = t.TypeOf;
@@ -2741,6 +3107,12 @@ export const delete_VolumeDelete = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_VolumePrune = t.TypeOf;
@@ -2757,6 +3129,13 @@ export const post_VolumePrune = t.type({
VolumesDeleted: t.union([t.undefined, t.array(t.string)]),
SpaceReclaimed: t.union([t.undefined, t.number]),
}),
+ responses: t.type({
+ "200": t.type({
+ VolumesDeleted: t.union([t.undefined, t.array(t.string)]),
+ SpaceReclaimed: t.union([t.undefined, t.number]),
+ }),
+ "500": ErrorResponse,
+ }),
});
export type get_NetworkList = t.TypeOf;
@@ -2770,6 +3149,10 @@ export const get_NetworkList = t.type({
}),
}),
response: t.array(Network),
+ responses: t.type({
+ "200": t.array(Network),
+ "500": ErrorResponse,
+ }),
});
export type get_NetworkInspect = t.TypeOf;
@@ -2787,6 +3170,11 @@ export const get_NetworkInspect = t.type({
}),
}),
response: Network,
+ responses: t.type({
+ "200": Network,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type delete_NetworkDelete = t.TypeOf;
@@ -2800,6 +3188,12 @@ export const delete_NetworkDelete = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "403": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_NetworkCreate = t.TypeOf;
@@ -2825,6 +3219,15 @@ export const post_NetworkCreate = t.type({
Id: t.union([t.undefined, t.string]),
Warning: t.union([t.undefined, t.string]),
}),
+ responses: t.type({
+ "201": t.type({
+ Id: t.union([t.undefined, t.string]),
+ Warning: t.union([t.undefined, t.string]),
+ }),
+ "403": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_NetworkConnect = t.TypeOf;
@@ -2842,6 +3245,12 @@ export const post_NetworkConnect = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "403": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_NetworkDisconnect = t.TypeOf;
@@ -2859,6 +3268,12 @@ export const post_NetworkDisconnect = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "403": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_NetworkPrune = t.TypeOf;
@@ -2874,6 +3289,12 @@ export const post_NetworkPrune = t.type({
response: t.type({
NetworksDeleted: t.union([t.undefined, t.array(t.string)]),
}),
+ responses: t.type({
+ "200": t.type({
+ NetworksDeleted: t.union([t.undefined, t.array(t.string)]),
+ }),
+ "500": ErrorResponse,
+ }),
});
export type get_PluginList = t.TypeOf;
@@ -2887,6 +3308,10 @@ export const get_PluginList = t.type({
}),
}),
response: t.array(Plugin),
+ responses: t.type({
+ "200": t.array(Plugin),
+ "500": ErrorResponse,
+ }),
});
export type get_GetPluginPrivileges = t.TypeOf;
@@ -2900,6 +3325,10 @@ export const get_GetPluginPrivileges = t.type({
}),
}),
response: t.array(PluginPrivilege),
+ responses: t.type({
+ "200": t.array(PluginPrivilege),
+ "500": ErrorResponse,
+ }),
});
export type post_PluginPull = t.TypeOf;
@@ -2918,6 +3347,10 @@ export const post_PluginPull = t.type({
body: t.array(PluginPrivilege),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "500": ErrorResponse,
+ }),
});
export type get_PluginInspect = t.TypeOf;
@@ -2931,6 +3364,11 @@ export const get_PluginInspect = t.type({
}),
}),
response: Plugin,
+ responses: t.type({
+ "200": Plugin,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type delete_PluginDelete = t.TypeOf;
@@ -2947,6 +3385,11 @@ export const delete_PluginDelete = t.type({
}),
}),
response: Plugin,
+ responses: t.type({
+ "200": Plugin,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_PluginEnable = t.TypeOf;
@@ -2963,6 +3406,11 @@ export const post_PluginEnable = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_PluginDisable = t.TypeOf;
@@ -2979,6 +3427,11 @@ export const post_PluginDisable = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_PluginUpgrade = t.TypeOf;
@@ -2999,6 +3452,11 @@ export const post_PluginUpgrade = t.type({
body: t.array(PluginPrivilege),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_PluginCreate = t.TypeOf;
@@ -3012,6 +3470,10 @@ export const post_PluginCreate = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "500": ErrorResponse,
+ }),
});
export type post_PluginPush = t.TypeOf;
@@ -3025,6 +3487,11 @@ export const post_PluginPush = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_PluginSet = t.TypeOf;
@@ -3039,6 +3506,11 @@ export const post_PluginSet = t.type({
body: t.array(t.string),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_NodeList = t.TypeOf;
@@ -3052,6 +3524,11 @@ export const get_NodeList = t.type({
}),
}),
response: t.array(Node),
+ responses: t.type({
+ "200": t.array(Node),
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_NodeInspect = t.TypeOf;
@@ -3065,6 +3542,12 @@ export const get_NodeInspect = t.type({
}),
}),
response: Node,
+ responses: t.type({
+ "200": Node,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type delete_NodeDelete = t.TypeOf;
@@ -3081,6 +3564,12 @@ export const delete_NodeDelete = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_NodeUpdate = t.TypeOf;
@@ -3098,6 +3587,13 @@ export const post_NodeUpdate = t.type({
body: NodeSpec,
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_SwarmInspect = t.TypeOf;
@@ -3107,6 +3603,12 @@ export const get_SwarmInspect = t.type({
requestFormat: t.literal("json"),
parameters: t.never,
response: Swarm,
+ responses: t.type({
+ "200": Swarm,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_SwarmInit = t.TypeOf;
@@ -3127,6 +3629,12 @@ export const post_SwarmInit = t.type({
}),
}),
response: t.string,
+ responses: t.type({
+ "200": t.string,
+ "400": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_SwarmJoin = t.TypeOf;
@@ -3144,6 +3652,12 @@ export const post_SwarmJoin = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_SwarmLeave = t.TypeOf;
@@ -3157,6 +3671,11 @@ export const post_SwarmLeave = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_SwarmUpdate = t.TypeOf;
@@ -3174,6 +3693,12 @@ export const post_SwarmUpdate = t.type({
body: SwarmSpec,
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_SwarmUnlockkey = t.TypeOf;
@@ -3185,6 +3710,13 @@ export const get_SwarmUnlockkey = t.type({
response: t.type({
UnlockKey: t.union([t.undefined, t.string]),
}),
+ responses: t.type({
+ "200": t.type({
+ UnlockKey: t.union([t.undefined, t.string]),
+ }),
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_SwarmUnlock = t.TypeOf;
@@ -3198,6 +3730,11 @@ export const post_SwarmUnlock = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_ServiceList = t.TypeOf;
@@ -3212,6 +3749,11 @@ export const get_ServiceList = t.type({
}),
}),
response: t.array(Service),
+ responses: t.type({
+ "200": t.array(Service),
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_ServiceCreate = t.TypeOf;
@@ -3229,6 +3771,17 @@ export const post_ServiceCreate = t.type({
ID: t.union([t.undefined, t.string]),
Warning: t.union([t.undefined, t.string]),
}),
+ responses: t.type({
+ "201": t.type({
+ ID: t.union([t.undefined, t.string]),
+ Warning: t.union([t.undefined, t.string]),
+ }),
+ "400": ErrorResponse,
+ "403": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_ServiceInspect = t.TypeOf;
@@ -3245,6 +3798,12 @@ export const get_ServiceInspect = t.type({
}),
}),
response: Service,
+ responses: t.type({
+ "200": Service,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type delete_ServiceDelete = t.TypeOf;
@@ -3258,6 +3817,12 @@ export const delete_ServiceDelete = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_ServiceUpdate = t.TypeOf;
@@ -3283,6 +3848,13 @@ export const post_ServiceUpdate = t.type({
body: t.intersection([ServiceSpec, t.record(t.string, t.unknown)]),
}),
response: ServiceUpdateResponse,
+ responses: t.type({
+ "200": ServiceUpdateResponse,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_ServiceLogs = t.TypeOf;
@@ -3305,6 +3877,12 @@ export const get_ServiceLogs = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": t.unknown,
+ "500": t.unknown,
+ "503": t.unknown,
+ }),
});
export type get_TaskList = t.TypeOf;
@@ -3318,6 +3896,11 @@ export const get_TaskList = t.type({
}),
}),
response: t.array(Task),
+ responses: t.type({
+ "200": t.array(Task),
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_TaskInspect = t.TypeOf;
@@ -3331,6 +3914,12 @@ export const get_TaskInspect = t.type({
}),
}),
response: Task,
+ responses: t.type({
+ "200": Task,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_TaskLogs = t.TypeOf;
@@ -3353,6 +3942,12 @@ export const get_TaskLogs = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "404": t.unknown,
+ "500": t.unknown,
+ "503": t.unknown,
+ }),
});
export type get_SecretList = t.TypeOf;
@@ -3366,6 +3961,11 @@ export const get_SecretList = t.type({
}),
}),
response: t.array(Secret),
+ responses: t.type({
+ "200": t.array(Secret),
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_SecretCreate = t.TypeOf;
@@ -3377,6 +3977,12 @@ export const post_SecretCreate = t.type({
body: t.intersection([SecretSpec, t.record(t.string, t.unknown)]),
}),
response: IdResponse,
+ responses: t.type({
+ "201": IdResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_SecretInspect = t.TypeOf;
@@ -3390,6 +3996,12 @@ export const get_SecretInspect = t.type({
}),
}),
response: Secret,
+ responses: t.type({
+ "200": Secret,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type delete_SecretDelete = t.TypeOf;
@@ -3403,6 +4015,12 @@ export const delete_SecretDelete = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_SecretUpdate = t.TypeOf;
@@ -3420,6 +4038,13 @@ export const post_SecretUpdate = t.type({
body: SecretSpec,
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_ConfigList = t.TypeOf;
@@ -3433,6 +4058,11 @@ export const get_ConfigList = t.type({
}),
}),
response: t.array(Config),
+ responses: t.type({
+ "200": t.array(Config),
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_ConfigCreate = t.TypeOf;
@@ -3444,6 +4074,12 @@ export const post_ConfigCreate = t.type({
body: t.intersection([ConfigSpec, t.record(t.string, t.unknown)]),
}),
response: IdResponse,
+ responses: t.type({
+ "201": IdResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_ConfigInspect = t.TypeOf;
@@ -3457,6 +4093,12 @@ export const get_ConfigInspect = t.type({
}),
}),
response: Config,
+ responses: t.type({
+ "200": Config,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type delete_ConfigDelete = t.TypeOf;
@@ -3470,6 +4112,12 @@ export const delete_ConfigDelete = t.type({
}),
}),
response: t.unknown,
+ responses: t.type({
+ "204": t.unknown,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type post_ConfigUpdate = t.TypeOf;
@@ -3487,6 +4135,13 @@ export const post_ConfigUpdate = t.type({
body: ConfigSpec,
}),
response: t.unknown,
+ responses: t.type({
+ "200": t.unknown,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ "503": ErrorResponse,
+ }),
});
export type get_DistributionInspect = t.TypeOf;
@@ -3500,6 +4155,11 @@ export const get_DistributionInspect = t.type({
}),
}),
response: DistributionInspect,
+ responses: t.type({
+ "200": DistributionInspect,
+ "401": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_Session = t.TypeOf;
@@ -3509,6 +4169,11 @@ export const post_Session = t.type({
requestFormat: t.literal("json"),
parameters: t.never,
response: t.unknown,
+ responses: t.type({
+ "101": t.unknown,
+ "400": t.unknown,
+ "500": t.unknown,
+ }),
});
export type __ENDPOINTS_END__ = t.TypeOf;
@@ -3661,6 +4326,7 @@ type RequestFormat = "json" | "form-data" | "form-url" | "binary" | "text";
export type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: unknown;
+ responses?: Record;
responseHeaders?: Record;
};
@@ -3676,11 +4342,97 @@ export type Endpoint = {
areParametersRequired: boolean;
};
response: TConfig["response"];
+ responses?: TConfig["responses"];
responseHeaders?: TConfig["responseHeaders"];
};
export type Fetcher = (method: Method, url: string, parameters?: EndpointParameters | undefined) => Promise;
+// Status code type for success responses
+export type SuccessStatusCode =
+ | 200
+ | 201
+ | 202
+ | 203
+ | 204
+ | 205
+ | 206
+ | 207
+ | 208
+ | 226
+ | 300
+ | 301
+ | 302
+ | 303
+ | 304
+ | 305
+ | 306
+ | 307
+ | 308;
+
+// Error handling types
+export type TypedApiResponse<
+ TSuccess,
+ TAllResponses extends Record = {},
+> = keyof TAllResponses extends never
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : {
+ [K in keyof TAllResponses]: K extends string
+ ? K extends `${infer TStatusCode extends number}`
+ ? TStatusCode extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: TStatusCode;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: TStatusCode;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never
+ : K extends number
+ ? K extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: K;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: K;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never;
+ }[keyof TAllResponses];
+
+export type SafeApiResponse = TEndpoint extends { response: infer TSuccess; responses: infer TResponses }
+ ? TResponses extends Record
+ ? TypedApiResponse
+ : Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : TEndpoint extends { response: infer TSuccess }
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : never;
+
type RequiredKeys = {
[P in keyof T]-?: undefined extends T[P] ? never : P;
}[keyof T];
@@ -3711,55 +4463,227 @@ export class ApiClient {
//
get(
path: Path,
- ...params: MaybeOptionalArg["parameters"]>
- ): Promise["response"]> {
- return this.fetcher("get", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise["response"]>;
+ ...params: MaybeOptionalArg["parameters"] & { withResponse?: false }>
+ ): Promise["response"]>;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg["parameters"] & { withResponse: true }>
+ ): Promise>;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("get", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("get", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise["response"]>;
+ }
}
//
//
post(
path: Path,
- ...params: MaybeOptionalArg["parameters"]>
- ): Promise["response"]> {
- return this.fetcher("post", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise["response"]>;
+ ...params: MaybeOptionalArg["parameters"] & { withResponse?: false }>
+ ): Promise["response"]>;
+
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg["parameters"] & { withResponse: true }>
+ ): Promise>;
+
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("post", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("post", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise["response"]>;
+ }
}
//
//
delete(
path: Path,
- ...params: MaybeOptionalArg["parameters"]>
- ): Promise["response"]> {
- return this.fetcher("delete", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise["response"]>;
+ ...params: MaybeOptionalArg["parameters"] & { withResponse?: false }>
+ ): Promise["response"]>;
+
+ delete(
+ path: Path,
+ ...params: MaybeOptionalArg["parameters"] & { withResponse: true }>
+ ): Promise>;
+
+ delete(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher(
+ "delete",
+ this.baseUrl + path,
+ Object.keys(fetchParams).length ? fetchParams : undefined,
+ ).then(async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ });
+ } else {
+ return this.fetcher("delete", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise["response"]>;
+ }
}
//
//
put(
path: Path,
- ...params: MaybeOptionalArg["parameters"]>
- ): Promise["response"]> {
- return this.fetcher("put", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise["response"]>;
+ ...params: MaybeOptionalArg["parameters"] & { withResponse?: false }>
+ ): Promise["response"]>;
+
+ put(
+ path: Path,
+ ...params: MaybeOptionalArg["parameters"] & { withResponse: true }>
+ ): Promise>;
+
+ put(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("put", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("put", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise["response"]>;
+ }
}
//
//
head(
path: Path,
- ...params: MaybeOptionalArg["parameters"]>
- ): Promise["response"]> {
- return this.fetcher("head", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise["response"]>;
+ ...params: MaybeOptionalArg["parameters"] & { withResponse?: false }>
+ ): Promise["response"]>;
+
+ head(
+ path: Path,
+ ...params: MaybeOptionalArg["parameters"] & { withResponse: true }>
+ ): Promise>;
+
+ head(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("head", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("head", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise["response"]>;
+ }
}
//
@@ -3798,6 +4722,21 @@ export function createApiClient(fetcher: Fetcher, baseUrl?: string) {
api.get("/users").then((users) => console.log(users));
api.post("/users", { body: { name: "John" } }).then((user) => console.log(user));
api.put("/users/:id", { path: { id: 1 }, body: { name: "John" } }).then((user) => console.log(user));
+
+ // With error handling
+ const result = await api.get("/users/{id}", { path: { id: "123" }, withResponse: true });
+ if (result.ok) {
+ // Access data directly
+ const user = result.data;
+ console.log(user);
+
+ // Or use the json() method for compatibility
+ const userFromJson = await result.json();
+ console.log(userFromJson);
+ } else {
+ const error = result.data;
+ console.error(`Error ${result.status}:`, error);
+ }
*/
// ;
@@ -1859,6 +1864,13 @@ export const post_ContainerCreate = Type.Object({
]),
}),
response: ContainerCreateResponse,
+ responses: Type.Object({
+ 201: ContainerCreateResponse,
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_ContainerInspect = Static;
@@ -1905,6 +1917,39 @@ export const get_ContainerInspect = Type.Object({
NetworkSettings: NetworkSettings,
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ Id: Type.String(),
+ Created: Type.String(),
+ Path: Type.String(),
+ Args: Type.Array(Type.String()),
+ State: ContainerState,
+ Image: Type.String(),
+ ResolvConfPath: Type.String(),
+ HostnamePath: Type.String(),
+ HostsPath: Type.String(),
+ LogPath: Type.String(),
+ Name: Type.String(),
+ RestartCount: Type.Number(),
+ Driver: Type.String(),
+ Platform: Type.String(),
+ MountLabel: Type.String(),
+ ProcessLabel: Type.String(),
+ AppArmorProfile: Type.String(),
+ ExecIDs: Type.Union([Type.Array(Type.String()), Type.Null()]),
+ HostConfig: HostConfig,
+ GraphDriver: GraphDriverData,
+ SizeRw: Type.Number(),
+ SizeRootFs: Type.Number(),
+ Mounts: Type.Array(MountPoint),
+ Config: ContainerConfig,
+ NetworkSettings: NetworkSettings,
+ }),
+ ),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_ContainerTop = Static;
@@ -1928,6 +1973,16 @@ export const get_ContainerTop = Type.Object({
Processes: Type.Array(Type.Array(Type.String())),
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ Titles: Type.Array(Type.String()),
+ Processes: Type.Array(Type.Array(Type.String())),
+ }),
+ ),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_ContainerLogs = Static;
@@ -1952,6 +2007,11 @@ export const get_ContainerLogs = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: Type.Unknown(),
+ 500: Type.Unknown(),
+ }),
});
export type get_ContainerChanges = Static;
@@ -1965,6 +2025,11 @@ export const get_ContainerChanges = Type.Object({
}),
}),
response: Type.Array(FilesystemChange),
+ responses: Type.Object({
+ 200: Type.Array(FilesystemChange),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_ContainerExport = Static;
@@ -1978,6 +2043,11 @@ export const get_ContainerExport = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: Type.Unknown(),
+ 500: Type.Unknown(),
+ }),
});
export type get_ContainerStats = Static;
@@ -1997,6 +2067,11 @@ export const get_ContainerStats = Type.Object({
}),
}),
response: Type.Record(Type.String(), Type.Unknown()),
+ responses: Type.Object({
+ 200: Type.Record(Type.String(), Type.Unknown()),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerResize = Static;
@@ -2016,6 +2091,11 @@ export const post_ContainerResize = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: Type.Unknown(),
+ 500: Type.Unknown(),
+ }),
});
export type post_ContainerStart = Static;
@@ -2034,6 +2114,12 @@ export const post_ContainerStart = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 304: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerStop = Static;
@@ -2053,6 +2139,12 @@ export const post_ContainerStop = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 304: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerRestart = Static;
@@ -2072,6 +2164,11 @@ export const post_ContainerRestart = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerKill = Static;
@@ -2090,6 +2187,12 @@ export const post_ContainerKill = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 404: ErrorResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerUpdate = Static;
@@ -2115,6 +2218,15 @@ export const post_ContainerUpdate = Type.Object({
Warnings: Type.Array(Type.String()),
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ Warnings: Type.Array(Type.String()),
+ }),
+ ),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerRename = Static;
@@ -2131,6 +2243,12 @@ export const post_ContainerRename = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 404: ErrorResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerPause = Static;
@@ -2144,6 +2262,11 @@ export const post_ContainerPause = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerUnpause = Static;
@@ -2157,6 +2280,11 @@ export const post_ContainerUnpause = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerAttach = Static;
@@ -2180,6 +2308,13 @@ export const post_ContainerAttach = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 101: Type.Unknown(),
+ 200: Type.Unknown(),
+ 400: Type.Unknown(),
+ 404: Type.Unknown(),
+ 500: Type.Unknown(),
+ }),
});
export type get_ContainerAttachWebsocket = Static;
@@ -2203,6 +2338,13 @@ export const get_ContainerAttachWebsocket = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 101: Type.Unknown(),
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerWait = Static;
@@ -2221,6 +2363,12 @@ export const post_ContainerWait = Type.Object({
}),
}),
response: ContainerWaitResponse,
+ responses: Type.Object({
+ 200: ContainerWaitResponse,
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type delete_ContainerDelete = Static;
@@ -2241,6 +2389,13 @@ export const delete_ContainerDelete = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_ContainerArchive = Static;
@@ -2257,6 +2412,12 @@ export const get_ContainerArchive = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: Type.Unknown(),
+ 404: Type.Unknown(),
+ 500: Type.Unknown(),
+ }),
});
export type put_PutContainerArchive = Static;
@@ -2276,6 +2437,13 @@ export const put_PutContainerArchive = Type.Object({
body: Type.String(),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 403: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type head_ContainerArchiveInfo = Static;
@@ -2292,6 +2460,12 @@ export const head_ContainerArchiveInfo = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
responseHeaders: Type.Object({
"x-docker-container-path-stat": Type.String(),
}),
@@ -2315,6 +2489,15 @@ export const post_ContainerPrune = Type.Object({
SpaceReclaimed: Type.Number(),
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ ContainersDeleted: Type.Array(Type.String()),
+ SpaceReclaimed: Type.Number(),
+ }),
+ ),
+ 500: ErrorResponse,
+ }),
});
export type get_ImageList = Static;
@@ -2333,6 +2516,10 @@ export const get_ImageList = Type.Object({
),
}),
response: Type.Array(ImageSummary),
+ responses: Type.Object({
+ 200: Type.Array(ImageSummary),
+ 500: ErrorResponse,
+ }),
});
export type post_ImageBuild = Static;
@@ -2378,6 +2565,11 @@ export const post_ImageBuild = Type.Object({
body: Type.String(),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_BuildPrune = Static;
@@ -2400,6 +2592,15 @@ export const post_BuildPrune = Type.Object({
SpaceReclaimed: Type.Number(),
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ CachesDeleted: Type.Array(Type.String()),
+ SpaceReclaimed: Type.Number(),
+ }),
+ ),
+ 500: ErrorResponse,
+ }),
});
export type post_ImageCreate = Static;
@@ -2427,6 +2628,11 @@ export const post_ImageCreate = Type.Object({
body: Type.String(),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_ImageInspect = Static;
@@ -2440,6 +2646,11 @@ export const get_ImageInspect = Type.Object({
}),
}),
response: ImageInspect,
+ responses: Type.Object({
+ 200: ImageInspect,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_ImageHistory = Static;
@@ -2462,6 +2673,20 @@ export const get_ImageHistory = Type.Object({
Comment: Type.String(),
}),
),
+ responses: Type.Object({
+ 200: Type.Array(
+ Type.Object({
+ Id: Type.String(),
+ Created: Type.Number(),
+ CreatedBy: Type.String(),
+ Tags: Type.Array(Type.String()),
+ Size: Type.Number(),
+ Comment: Type.String(),
+ }),
+ ),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ImagePush = Static;
@@ -2483,6 +2708,11 @@ export const post_ImagePush = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ImageTag = Static;
@@ -2502,6 +2732,13 @@ export const post_ImageTag = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 201: Type.Unknown(),
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type delete_ImageDelete = Static;
@@ -2521,6 +2758,12 @@ export const delete_ImageDelete = Type.Object({
}),
}),
response: Type.Array(ImageDeleteResponseItem),
+ responses: Type.Object({
+ 200: Type.Array(ImageDeleteResponseItem),
+ 404: ErrorResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_ImageSearch = Static;
@@ -2546,6 +2789,20 @@ export const get_ImageSearch = Type.Object({
}),
),
),
+ responses: Type.Object({
+ 200: Type.Array(
+ Type.Partial(
+ Type.Object({
+ description: Type.String(),
+ is_official: Type.Boolean(),
+ is_automated: Type.Boolean(),
+ name: Type.String(),
+ star_count: Type.Number(),
+ }),
+ ),
+ ),
+ 500: ErrorResponse,
+ }),
});
export type post_ImagePrune = Static;
@@ -2566,6 +2823,15 @@ export const post_ImagePrune = Type.Object({
SpaceReclaimed: Type.Number(),
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ ImagesDeleted: Type.Array(ImageDeleteResponseItem),
+ SpaceReclaimed: Type.Number(),
+ }),
+ ),
+ 500: ErrorResponse,
+ }),
});
export type post_SystemAuth = Static;
@@ -2576,7 +2842,19 @@ export const post_SystemAuth = Type.Object({
parameters: Type.Object({
body: AuthConfig,
}),
- response: Type.Unknown(),
+ response: Type.Object({
+ Status: Type.String(),
+ IdentityToken: Type.Optional(Type.Union([Type.String(), Type.Undefined()])),
+ }),
+ responses: Type.Object({
+ 200: Type.Object({
+ Status: Type.String(),
+ IdentityToken: Type.Optional(Type.Union([Type.String(), Type.Undefined()])),
+ }),
+ 204: Type.Unknown(),
+ 401: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_SystemInfo = Static;
@@ -2586,6 +2864,10 @@ export const get_SystemInfo = Type.Object({
requestFormat: Type.Literal("json"),
parameters: Type.Never(),
response: SystemInfo,
+ responses: Type.Object({
+ 200: SystemInfo,
+ 500: ErrorResponse,
+ }),
});
export type get_SystemVersion = Static;
@@ -2595,6 +2877,10 @@ export const get_SystemVersion = Type.Object({
requestFormat: Type.Literal("json"),
parameters: Type.Never(),
response: SystemVersion,
+ responses: Type.Object({
+ 200: SystemVersion,
+ 500: ErrorResponse,
+ }),
});
export type get_SystemPing = Static;
@@ -2604,6 +2890,10 @@ export const get_SystemPing = Type.Object({
requestFormat: Type.Literal("json"),
parameters: Type.Never(),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 500: Type.Unknown(),
+ }),
responseHeaders: Type.Object({
swarm: Type.Union([
Type.Literal("inactive"),
@@ -2628,6 +2918,10 @@ export const head_SystemPingHead = Type.Object({
requestFormat: Type.Literal("json"),
parameters: Type.Never(),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 500: Type.Unknown(),
+ }),
responseHeaders: Type.Object({
swarm: Type.Union([
Type.Literal("inactive"),
@@ -2665,6 +2959,11 @@ export const post_ImageCommit = Type.Object({
body: ContainerConfig,
}),
response: IdResponse,
+ responses: Type.Object({
+ 201: IdResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_SystemEvents = Static;
@@ -2682,6 +2981,11 @@ export const get_SystemEvents = Type.Object({
),
}),
response: EventMessage,
+ responses: Type.Object({
+ 200: EventMessage,
+ 400: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_SystemDataUsage = Static;
@@ -2712,6 +3016,18 @@ export const get_SystemDataUsage = Type.Object({
BuildCache: Type.Array(BuildCache),
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ LayersSize: Type.Number(),
+ Images: Type.Array(ImageSummary),
+ Containers: Type.Array(ContainerSummary),
+ Volumes: Type.Array(Volume),
+ BuildCache: Type.Array(BuildCache),
+ }),
+ ),
+ 500: ErrorResponse,
+ }),
});
export type get_ImageGet = Static;
@@ -2725,6 +3041,10 @@ export const get_ImageGet = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 500: Type.Unknown(),
+ }),
});
export type get_ImageGetAll = Static;
@@ -2740,6 +3060,10 @@ export const get_ImageGetAll = Type.Object({
),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 500: Type.Unknown(),
+ }),
});
export type post_ImageLoad = Static;
@@ -2755,6 +3079,10 @@ export const post_ImageLoad = Type.Object({
),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 500: ErrorResponse,
+ }),
});
export type post_ContainerExec = Static;
@@ -2783,6 +3111,12 @@ export const post_ContainerExec = Type.Object({
),
}),
response: IdResponse,
+ responses: Type.Object({
+ 201: IdResponse,
+ 404: ErrorResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_ExecStart = Static;
@@ -2803,6 +3137,11 @@ export const post_ExecStart = Type.Object({
),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: Type.Unknown(),
+ 409: Type.Unknown(),
+ }),
});
export type post_ExecResize = Static;
@@ -2822,6 +3161,12 @@ export const post_ExecResize = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_ExecInspect = Static;
@@ -2849,6 +3194,25 @@ export const get_ExecInspect = Type.Object({
Pid: Type.Number(),
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ CanRemove: Type.Boolean(),
+ DetachKeys: Type.String(),
+ ID: Type.String(),
+ Running: Type.Boolean(),
+ ExitCode: Type.Number(),
+ ProcessConfig: ProcessConfig,
+ OpenStdin: Type.Boolean(),
+ OpenStderr: Type.Boolean(),
+ OpenStdout: Type.Boolean(),
+ ContainerID: Type.String(),
+ Pid: Type.Number(),
+ }),
+ ),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_VolumeList = Static;
@@ -2864,6 +3228,10 @@ export const get_VolumeList = Type.Object({
),
}),
response: VolumeListResponse,
+ responses: Type.Object({
+ 200: VolumeListResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_VolumeCreate = Static;
@@ -2875,6 +3243,10 @@ export const post_VolumeCreate = Type.Object({
body: VolumeCreateOptions,
}),
response: Volume,
+ responses: Type.Object({
+ 201: Volume,
+ 500: ErrorResponse,
+ }),
});
export type get_VolumeInspect = Static;
@@ -2888,6 +3260,11 @@ export const get_VolumeInspect = Type.Object({
}),
}),
response: Volume,
+ responses: Type.Object({
+ 200: Volume,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type put_VolumeUpdate = Static;
@@ -2909,6 +3286,13 @@ export const put_VolumeUpdate = Type.Object({
),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type delete_VolumeDelete = Static;
@@ -2927,6 +3311,12 @@ export const delete_VolumeDelete = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 404: ErrorResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_VolumePrune = Static;
@@ -2947,6 +3337,15 @@ export const post_VolumePrune = Type.Object({
SpaceReclaimed: Type.Number(),
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ VolumesDeleted: Type.Array(Type.String()),
+ SpaceReclaimed: Type.Number(),
+ }),
+ ),
+ 500: ErrorResponse,
+ }),
});
export type get_NetworkList = Static;
@@ -2962,6 +3361,10 @@ export const get_NetworkList = Type.Object({
),
}),
response: Type.Array(Network),
+ responses: Type.Object({
+ 200: Type.Array(Network),
+ 500: ErrorResponse,
+ }),
});
export type get_NetworkInspect = Static;
@@ -2981,6 +3384,11 @@ export const get_NetworkInspect = Type.Object({
}),
}),
response: Network,
+ responses: Type.Object({
+ 200: Network,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type delete_NetworkDelete = Static;
@@ -2994,6 +3402,12 @@ export const delete_NetworkDelete = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 403: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_NetworkCreate = Static;
@@ -3021,6 +3435,17 @@ export const post_NetworkCreate = Type.Object({
Warning: Type.String(),
}),
),
+ responses: Type.Object({
+ 201: Type.Partial(
+ Type.Object({
+ Id: Type.String(),
+ Warning: Type.String(),
+ }),
+ ),
+ 403: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_NetworkConnect = Static;
@@ -3040,6 +3465,12 @@ export const post_NetworkConnect = Type.Object({
),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 403: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_NetworkDisconnect = Static;
@@ -3059,6 +3490,12 @@ export const post_NetworkDisconnect = Type.Object({
),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 403: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_NetworkPrune = Static;
@@ -3078,6 +3515,14 @@ export const post_NetworkPrune = Type.Object({
NetworksDeleted: Type.Array(Type.String()),
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ NetworksDeleted: Type.Array(Type.String()),
+ }),
+ ),
+ 500: ErrorResponse,
+ }),
});
export type get_PluginList = Static;
@@ -3093,6 +3538,10 @@ export const get_PluginList = Type.Object({
),
}),
response: Type.Array(Plugin),
+ responses: Type.Object({
+ 200: Type.Array(Plugin),
+ 500: ErrorResponse,
+ }),
});
export type get_GetPluginPrivileges = Static;
@@ -3106,6 +3555,10 @@ export const get_GetPluginPrivileges = Type.Object({
}),
}),
response: Type.Array(PluginPrivilege),
+ responses: Type.Object({
+ 200: Type.Array(PluginPrivilege),
+ 500: ErrorResponse,
+ }),
});
export type post_PluginPull = Static;
@@ -3126,6 +3579,10 @@ export const post_PluginPull = Type.Object({
body: Type.Array(PluginPrivilege),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 500: ErrorResponse,
+ }),
});
export type get_PluginInspect = Static;
@@ -3139,6 +3596,11 @@ export const get_PluginInspect = Type.Object({
}),
}),
response: Plugin,
+ responses: Type.Object({
+ 200: Plugin,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type delete_PluginDelete = Static;
@@ -3157,6 +3619,11 @@ export const delete_PluginDelete = Type.Object({
}),
}),
response: Plugin,
+ responses: Type.Object({
+ 200: Plugin,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_PluginEnable = Static;
@@ -3175,6 +3642,11 @@ export const post_PluginEnable = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_PluginDisable = Static;
@@ -3193,6 +3665,11 @@ export const post_PluginDisable = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_PluginUpgrade = Static;
@@ -3215,6 +3692,11 @@ export const post_PluginUpgrade = Type.Object({
body: Type.Array(PluginPrivilege),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_PluginCreate = Static;
@@ -3228,6 +3710,10 @@ export const post_PluginCreate = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 500: ErrorResponse,
+ }),
});
export type post_PluginPush = Static;
@@ -3241,6 +3727,11 @@ export const post_PluginPush = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_PluginSet = Static;
@@ -3255,6 +3746,11 @@ export const post_PluginSet = Type.Object({
body: Type.Array(Type.String()),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type get_NodeList = Static;
@@ -3270,6 +3766,11 @@ export const get_NodeList = Type.Object({
),
}),
response: Type.Array(Node),
+ responses: Type.Object({
+ 200: Type.Array(Node),
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_NodeInspect = Static;
@@ -3283,6 +3784,12 @@ export const get_NodeInspect = Type.Object({
}),
}),
response: Node,
+ responses: Type.Object({
+ 200: Node,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type delete_NodeDelete = Static;
@@ -3301,6 +3808,12 @@ export const delete_NodeDelete = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_NodeUpdate = Static;
@@ -3318,6 +3831,13 @@ export const post_NodeUpdate = Type.Object({
body: NodeSpec,
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_SwarmInspect = Static;
@@ -3327,6 +3847,12 @@ export const get_SwarmInspect = Type.Object({
requestFormat: Type.Literal("json"),
parameters: Type.Never(),
response: Swarm,
+ responses: Type.Object({
+ 200: Swarm,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_SwarmInit = Static;
@@ -3349,6 +3875,12 @@ export const post_SwarmInit = Type.Object({
),
}),
response: Type.String(),
+ responses: Type.Object({
+ 200: Type.String(),
+ 400: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_SwarmJoin = Static;
@@ -3368,6 +3900,12 @@ export const post_SwarmJoin = Type.Object({
),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_SwarmLeave = Static;
@@ -3383,6 +3921,11 @@ export const post_SwarmLeave = Type.Object({
),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_SwarmUpdate = Static;
@@ -3400,6 +3943,12 @@ export const post_SwarmUpdate = Type.Object({
body: SwarmSpec,
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_SwarmUnlockkey = Static;
@@ -3413,6 +3962,15 @@ export const get_SwarmUnlockkey = Type.Object({
UnlockKey: Type.String(),
}),
),
+ responses: Type.Object({
+ 200: Type.Partial(
+ Type.Object({
+ UnlockKey: Type.String(),
+ }),
+ ),
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_SwarmUnlock = Static;
@@ -3428,6 +3986,11 @@ export const post_SwarmUnlock = Type.Object({
),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_ServiceList = Static;
@@ -3444,6 +4007,11 @@ export const get_ServiceList = Type.Object({
),
}),
response: Type.Array(Service),
+ responses: Type.Object({
+ 200: Type.Array(Service),
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_ServiceCreate = Static;
@@ -3465,6 +4033,19 @@ export const post_ServiceCreate = Type.Object({
Warning: Type.String(),
}),
),
+ responses: Type.Object({
+ 201: Type.Partial(
+ Type.Object({
+ ID: Type.String(),
+ Warning: Type.String(),
+ }),
+ ),
+ 400: ErrorResponse,
+ 403: ErrorResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_ServiceInspect = Static;
@@ -3483,6 +4064,12 @@ export const get_ServiceInspect = Type.Object({
}),
}),
response: Service,
+ responses: Type.Object({
+ 200: Service,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type delete_ServiceDelete = Static;
@@ -3496,6 +4083,12 @@ export const delete_ServiceDelete = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_ServiceUpdate = Static;
@@ -3522,6 +4115,13 @@ export const post_ServiceUpdate = Type.Object({
body: Type.Intersect([ServiceSpec, Type.Record(Type.String(), Type.Unknown())]),
}),
response: ServiceUpdateResponse,
+ responses: Type.Object({
+ 200: ServiceUpdateResponse,
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_ServiceLogs = Static;
@@ -3546,6 +4146,12 @@ export const get_ServiceLogs = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: Type.Unknown(),
+ 500: Type.Unknown(),
+ 503: Type.Unknown(),
+ }),
});
export type get_TaskList = Static;
@@ -3561,6 +4167,11 @@ export const get_TaskList = Type.Object({
),
}),
response: Type.Array(Task),
+ responses: Type.Object({
+ 200: Type.Array(Task),
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_TaskInspect = Static;
@@ -3574,6 +4185,12 @@ export const get_TaskInspect = Type.Object({
}),
}),
response: Task,
+ responses: Type.Object({
+ 200: Task,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_TaskLogs = Static;
@@ -3598,6 +4215,12 @@ export const get_TaskLogs = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 404: Type.Unknown(),
+ 500: Type.Unknown(),
+ 503: Type.Unknown(),
+ }),
});
export type get_SecretList = Static;
@@ -3613,6 +4236,11 @@ export const get_SecretList = Type.Object({
),
}),
response: Type.Array(Secret),
+ responses: Type.Object({
+ 200: Type.Array(Secret),
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_SecretCreate = Static;
@@ -3624,6 +4252,12 @@ export const post_SecretCreate = Type.Object({
body: Type.Intersect([SecretSpec, Type.Record(Type.String(), Type.Unknown())]),
}),
response: IdResponse,
+ responses: Type.Object({
+ 201: IdResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_SecretInspect = Static;
@@ -3637,6 +4271,12 @@ export const get_SecretInspect = Type.Object({
}),
}),
response: Secret,
+ responses: Type.Object({
+ 200: Secret,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type delete_SecretDelete = Static;
@@ -3650,6 +4290,12 @@ export const delete_SecretDelete = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_SecretUpdate = Static;
@@ -3667,6 +4313,13 @@ export const post_SecretUpdate = Type.Object({
body: SecretSpec,
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_ConfigList = Static;
@@ -3682,6 +4335,11 @@ export const get_ConfigList = Type.Object({
),
}),
response: Type.Array(Config),
+ responses: Type.Object({
+ 200: Type.Array(Config),
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_ConfigCreate = Static;
@@ -3693,6 +4351,12 @@ export const post_ConfigCreate = Type.Object({
body: Type.Intersect([ConfigSpec, Type.Record(Type.String(), Type.Unknown())]),
}),
response: IdResponse,
+ responses: Type.Object({
+ 201: IdResponse,
+ 409: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_ConfigInspect = Static;
@@ -3706,6 +4370,12 @@ export const get_ConfigInspect = Type.Object({
}),
}),
response: Config,
+ responses: Type.Object({
+ 200: Config,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type delete_ConfigDelete = Static;
@@ -3719,6 +4389,12 @@ export const delete_ConfigDelete = Type.Object({
}),
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 204: Type.Unknown(),
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type post_ConfigUpdate = Static;
@@ -3736,6 +4412,13 @@ export const post_ConfigUpdate = Type.Object({
body: ConfigSpec,
}),
response: Type.Unknown(),
+ responses: Type.Object({
+ 200: Type.Unknown(),
+ 400: ErrorResponse,
+ 404: ErrorResponse,
+ 500: ErrorResponse,
+ 503: ErrorResponse,
+ }),
});
export type get_DistributionInspect = Static;
@@ -3749,6 +4432,11 @@ export const get_DistributionInspect = Type.Object({
}),
}),
response: DistributionInspect,
+ responses: Type.Object({
+ 200: DistributionInspect,
+ 401: ErrorResponse,
+ 500: ErrorResponse,
+ }),
});
export type post_Session = Static;
@@ -3758,6 +4446,11 @@ export const post_Session = Type.Object({
requestFormat: Type.Literal("json"),
parameters: Type.Never(),
response: Type.Unknown(),
+ responses: Type.Object({
+ 101: Type.Unknown(),
+ 400: Type.Unknown(),
+ 500: Type.Unknown(),
+ }),
});
type __ENDPOINTS_END__ = Static;
@@ -3910,6 +4603,7 @@ type RequestFormat = "json" | "form-data" | "form-url" | "binary" | "text";
export type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: unknown;
+ responses?: Record;
responseHeaders?: Record;
};
@@ -3925,11 +4619,97 @@ export type Endpoint = {
areParametersRequired: boolean;
};
response: TConfig["response"];
+ responses?: TConfig["responses"];
responseHeaders?: TConfig["responseHeaders"];
};
export type Fetcher = (method: Method, url: string, parameters?: EndpointParameters | undefined) => Promise;
+// Status code type for success responses
+export type SuccessStatusCode =
+ | 200
+ | 201
+ | 202
+ | 203
+ | 204
+ | 205
+ | 206
+ | 207
+ | 208
+ | 226
+ | 300
+ | 301
+ | 302
+ | 303
+ | 304
+ | 305
+ | 306
+ | 307
+ | 308;
+
+// Error handling types
+export type TypedApiResponse<
+ TSuccess,
+ TAllResponses extends Record = {},
+> = keyof TAllResponses extends never
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : {
+ [K in keyof TAllResponses]: K extends string
+ ? K extends `${infer TStatusCode extends number}`
+ ? TStatusCode extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: TStatusCode;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: TStatusCode;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never
+ : K extends number
+ ? K extends SuccessStatusCode
+ ? Omit & {
+ ok: true;
+ status: K;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : Omit & {
+ ok: false;
+ status: K;
+ data: TAllResponses[K];
+ json: () => Promise;
+ }
+ : never;
+ }[keyof TAllResponses];
+
+export type SafeApiResponse = TEndpoint extends { response: infer TSuccess; responses: infer TResponses }
+ ? TResponses extends Record
+ ? TypedApiResponse
+ : Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : TEndpoint extends { response: infer TSuccess }
+ ? Omit & {
+ ok: true;
+ status: number;
+ data: TSuccess;
+ json: () => Promise;
+ }
+ : never;
+
type RequiredKeys = {
[P in keyof T]-?: undefined extends T[P] ? never : P;
}[keyof T];
@@ -3960,55 +4740,227 @@ export class ApiClient {
//
get(
path: Path,
- ...params: MaybeOptionalArg["parameters"]>
- ): Promise["response"]> {
- return this.fetcher("get", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise["response"]>;
+ ...params: MaybeOptionalArg["parameters"] & { withResponse?: false }>
+ ): Promise["response"]>;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg["parameters"] & { withResponse: true }>
+ ): Promise>;
+
+ get(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("get", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("get", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise["response"]>;
+ }
}
//
//
post(
path: Path,
- ...params: MaybeOptionalArg["parameters"]>
- ): Promise["response"]> {
- return this.fetcher("post", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise["response"]>;
+ ...params: MaybeOptionalArg["parameters"] & { withResponse?: false }>
+ ): Promise["response"]>;
+
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg["parameters"] & { withResponse: true }>
+ ): Promise>;
+
+ post(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("post", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("post", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise["response"]>;
+ }
}
//
//
delete(
path: Path,
- ...params: MaybeOptionalArg["parameters"]>
- ): Promise["response"]> {
- return this.fetcher("delete", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise["response"]>;
+ ...params: MaybeOptionalArg["parameters"] & { withResponse?: false }>
+ ): Promise["response"]>;
+
+ delete(
+ path: Path,
+ ...params: MaybeOptionalArg["parameters"] & { withResponse: true }>
+ ): Promise>;
+
+ delete(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher(
+ "delete",
+ this.baseUrl + path,
+ Object.keys(fetchParams).length ? fetchParams : undefined,
+ ).then(async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ });
+ } else {
+ return this.fetcher("delete", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise["response"]>;
+ }
}
//
//
put(
path: Path,
- ...params: MaybeOptionalArg["parameters"]>
- ): Promise["response"]> {
- return this.fetcher("put", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise["response"]>;
+ ...params: MaybeOptionalArg["parameters"] & { withResponse?: false }>
+ ): Promise["response"]>;
+
+ put(
+ path: Path,
+ ...params: MaybeOptionalArg["parameters"] & { withResponse: true }>
+ ): Promise>;
+
+ put(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("put", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("put", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise["response"]>;
+ }
}
//
//
head(
path: Path,
- ...params: MaybeOptionalArg["parameters"]>
- ): Promise["response"]> {
- return this.fetcher("head", this.baseUrl + path, params[0]).then((response) =>
- this.parseResponse(response),
- ) as Promise["response"]>;
+ ...params: MaybeOptionalArg["parameters"] & { withResponse?: false }>
+ ): Promise["response"]>;
+
+ head(
+ path: Path,
+ ...params: MaybeOptionalArg["parameters"] & { withResponse: true }>
+ ): Promise>;
+
+ head(
+ path: Path,
+ ...params: MaybeOptionalArg
+ ): Promise {
+ const requestParams = params[0];
+ const withResponse = requestParams?.withResponse;
+
+ // Remove withResponse from params before passing to fetcher
+ const { withResponse: _, ...fetchParams } = requestParams || {};
+
+ if (withResponse) {
+ return this.fetcher("head", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
+ async (response) => {
+ // Parse the response data
+ const data = await this.parseResponse(response);
+
+ // Override properties while keeping the original Response object
+ const typedResponse = Object.assign(response, {
+ ok: response.ok,
+ status: response.status,
+ data: data,
+ json: () => Promise.resolve(data),
+ });
+ return typedResponse;
+ },
+ );
+ } else {
+ return this.fetcher("head", this.baseUrl + path, requestParams).then((response) =>
+ this.parseResponse(response),
+ ) as Promise["response"]>;
+ }
}
//
@@ -4047,6 +4999,21 @@ export function createApiClient(fetcher: Fetcher, baseUrl?: string) {
api.get("/users").then((users) => console.log(users));
api.post("/users", { body: { name: "John" } }).then((user) => console.log(user));
api.put("/users/:id", { path: { id: 1 }, body: { name: "John" } }).then((user) => console.log(user));
+
+ // With error handling
+ const result = await api.get("/users/{id}", { path: { id: "123" }, withResponse: true });
+ if (result.ok) {
+ // Access data directly
+ const user = result.data;
+ console.log(user);
+
+ // Or use the json() method for compatibility
+ const userFromJson = await result.json();
+ console.log(userFromJson);
+ } else {
+ const error = result.data;
+ console.error(`Error ${result.status}:`, error);
+ }
*/
// ;
@@ -1683,6 +1688,13 @@ export const post_ContainerCreate = v.object({
]),
}),
response: ContainerCreateResponse,
+ responses: v.object({
+ "201": ContainerCreateResponse,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ContainerInspect = v.InferOutput;
@@ -1725,6 +1737,37 @@ export const get_ContainerInspect = v.object({
Config: v.optional(ContainerConfig),
NetworkSettings: v.optional(NetworkSettings),
}),
+ responses: v.object({
+ "200": v.object({
+ Id: v.optional(v.string()),
+ Created: v.optional(v.string()),
+ Path: v.optional(v.string()),
+ Args: v.optional(v.array(v.string())),
+ State: v.optional(ContainerState),
+ Image: v.optional(v.string()),
+ ResolvConfPath: v.optional(v.string()),
+ HostnamePath: v.optional(v.string()),
+ HostsPath: v.optional(v.string()),
+ LogPath: v.optional(v.string()),
+ Name: v.optional(v.string()),
+ RestartCount: v.optional(v.number()),
+ Driver: v.optional(v.string()),
+ Platform: v.optional(v.string()),
+ MountLabel: v.optional(v.string()),
+ ProcessLabel: v.optional(v.string()),
+ AppArmorProfile: v.optional(v.string()),
+ ExecIDs: v.optional(v.union([v.array(v.string()), v.null()])),
+ HostConfig: v.optional(HostConfig),
+ GraphDriver: v.optional(GraphDriverData),
+ SizeRw: v.optional(v.number()),
+ SizeRootFs: v.optional(v.number()),
+ Mounts: v.optional(v.array(MountPoint)),
+ Config: v.optional(ContainerConfig),
+ NetworkSettings: v.optional(NetworkSettings),
+ }),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ContainerTop = v.InferOutput;
@@ -1744,6 +1787,14 @@ export const get_ContainerTop = v.object({
Titles: v.optional(v.array(v.string())),
Processes: v.optional(v.array(v.array(v.string()))),
}),
+ responses: v.object({
+ "200": v.object({
+ Titles: v.optional(v.array(v.string())),
+ Processes: v.optional(v.array(v.array(v.string()))),
+ }),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ContainerLogs = v.InferOutput;
@@ -1766,6 +1817,11 @@ export const get_ContainerLogs = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "404": v.unknown(),
+ "500": v.unknown(),
+ }),
});
export type get_ContainerChanges = v.InferOutput;
@@ -1779,6 +1835,11 @@ export const get_ContainerChanges = v.object({
}),
}),
response: v.array(FilesystemChange),
+ responses: v.object({
+ "200": v.array(FilesystemChange),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ContainerExport = v.InferOutput;
@@ -1792,6 +1853,11 @@ export const get_ContainerExport = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "404": v.unknown(),
+ "500": v.unknown(),
+ }),
});
export type get_ContainerStats = v.InferOutput;
@@ -1809,6 +1875,11 @@ export const get_ContainerStats = v.object({
}),
}),
response: v.record(v.string(), v.unknown()),
+ responses: v.object({
+ "200": v.record(v.string(), v.unknown()),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerResize = v.InferOutput;
@@ -1826,6 +1897,11 @@ export const post_ContainerResize = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "404": v.unknown(),
+ "500": v.unknown(),
+ }),
});
export type post_ContainerStart = v.InferOutput;
@@ -1842,6 +1918,12 @@ export const post_ContainerStart = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "204": v.unknown(),
+ "304": v.unknown(),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerStop = v.InferOutput;
@@ -1859,6 +1941,12 @@ export const post_ContainerStop = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "204": v.unknown(),
+ "304": v.unknown(),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerRestart = v.InferOutput;
@@ -1876,6 +1964,11 @@ export const post_ContainerRestart = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "204": v.unknown(),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerKill = v.InferOutput;
@@ -1892,6 +1985,12 @@ export const post_ContainerKill = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "204": v.unknown(),
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerUpdate = v.InferOutput;
@@ -1913,6 +2012,13 @@ export const post_ContainerUpdate = v.object({
response: v.object({
Warnings: v.optional(v.array(v.string())),
}),
+ responses: v.object({
+ "200": v.object({
+ Warnings: v.optional(v.array(v.string())),
+ }),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerRename = v.InferOutput;
@@ -1929,6 +2035,12 @@ export const post_ContainerRename = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "204": v.unknown(),
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerPause = v.InferOutput;
@@ -1942,6 +2054,11 @@ export const post_ContainerPause = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "204": v.unknown(),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerUnpause = v.InferOutput;
@@ -1955,6 +2072,11 @@ export const post_ContainerUnpause = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "204": v.unknown(),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerAttach = v.InferOutput;
@@ -1976,6 +2098,13 @@ export const post_ContainerAttach = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "101": v.unknown(),
+ "200": v.unknown(),
+ "400": v.unknown(),
+ "404": v.unknown(),
+ "500": v.unknown(),
+ }),
});
export type get_ContainerAttachWebsocket = v.InferOutput;
@@ -1997,6 +2126,13 @@ export const get_ContainerAttachWebsocket = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "101": v.unknown(),
+ "200": v.unknown(),
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerWait = v.InferOutput;
@@ -2013,6 +2149,12 @@ export const post_ContainerWait = v.object({
}),
}),
response: ContainerWaitResponse,
+ responses: v.object({
+ "200": ContainerWaitResponse,
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type delete_ContainerDelete = v.InferOutput;
@@ -2031,6 +2173,13 @@ export const delete_ContainerDelete = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "204": v.unknown(),
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ContainerArchive = v.InferOutput;
@@ -2047,6 +2196,12 @@ export const get_ContainerArchive = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "400": v.unknown(),
+ "404": v.unknown(),
+ "500": v.unknown(),
+ }),
});
export type put_PutContainerArchive = v.InferOutput;
@@ -2066,6 +2221,13 @@ export const put_PutContainerArchive = v.object({
body: v.string(),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "400": ErrorResponse,
+ "403": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type head_ContainerArchiveInfo = v.InferOutput;
@@ -2082,6 +2244,12 @@ export const head_ContainerArchiveInfo = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
responseHeaders: v.object({
"x-docker-container-path-stat": v.string(),
}),
@@ -2101,6 +2269,13 @@ export const post_ContainerPrune = v.object({
ContainersDeleted: v.optional(v.array(v.string())),
SpaceReclaimed: v.optional(v.number()),
}),
+ responses: v.object({
+ "200": v.object({
+ ContainersDeleted: v.optional(v.array(v.string())),
+ SpaceReclaimed: v.optional(v.number()),
+ }),
+ "500": ErrorResponse,
+ }),
});
export type get_ImageList = v.InferOutput;
@@ -2117,6 +2292,10 @@ export const get_ImageList = v.object({
}),
}),
response: v.array(ImageSummary),
+ responses: v.object({
+ "200": v.array(ImageSummary),
+ "500": ErrorResponse,
+ }),
});
export type post_ImageBuild = v.InferOutput;
@@ -2158,6 +2337,11 @@ export const post_ImageBuild = v.object({
body: v.string(),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "400": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_BuildPrune = v.InferOutput;
@@ -2176,6 +2360,13 @@ export const post_BuildPrune = v.object({
CachesDeleted: v.optional(v.array(v.string())),
SpaceReclaimed: v.optional(v.number()),
}),
+ responses: v.object({
+ "200": v.object({
+ CachesDeleted: v.optional(v.array(v.string())),
+ SpaceReclaimed: v.optional(v.number()),
+ }),
+ "500": ErrorResponse,
+ }),
});
export type post_ImageCreate = v.InferOutput;
@@ -2199,6 +2390,11 @@ export const post_ImageCreate = v.object({
body: v.string(),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ImageInspect = v.InferOutput;
@@ -2212,6 +2408,11 @@ export const get_ImageInspect = v.object({
}),
}),
response: ImageInspect,
+ responses: v.object({
+ "200": ImageInspect,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ImageHistory = v.InferOutput;
@@ -2234,6 +2435,20 @@ export const get_ImageHistory = v.object({
Comment: v.string(),
}),
),
+ responses: v.object({
+ "200": v.array(
+ v.object({
+ Id: v.string(),
+ Created: v.number(),
+ CreatedBy: v.string(),
+ Tags: v.array(v.string()),
+ Size: v.number(),
+ Comment: v.string(),
+ }),
+ ),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ImagePush = v.InferOutput;
@@ -2253,6 +2468,11 @@ export const post_ImagePush = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ImageTag = v.InferOutput;
@@ -2270,6 +2490,13 @@ export const post_ImageTag = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "201": v.unknown(),
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type delete_ImageDelete = v.InferOutput;
@@ -2287,6 +2514,12 @@ export const delete_ImageDelete = v.object({
}),
}),
response: v.array(ImageDeleteResponseItem),
+ responses: v.object({
+ "200": v.array(ImageDeleteResponseItem),
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ImageSearch = v.InferOutput;
@@ -2310,6 +2543,18 @@ export const get_ImageSearch = v.object({
star_count: v.optional(v.number()),
}),
),
+ responses: v.object({
+ "200": v.array(
+ v.object({
+ description: v.optional(v.string()),
+ is_official: v.optional(v.boolean()),
+ is_automated: v.optional(v.boolean()),
+ name: v.optional(v.string()),
+ star_count: v.optional(v.number()),
+ }),
+ ),
+ "500": ErrorResponse,
+ }),
});
export type post_ImagePrune = v.InferOutput;
@@ -2326,6 +2571,13 @@ export const post_ImagePrune = v.object({
ImagesDeleted: v.optional(v.array(ImageDeleteResponseItem)),
SpaceReclaimed: v.optional(v.number()),
}),
+ responses: v.object({
+ "200": v.object({
+ ImagesDeleted: v.optional(v.array(ImageDeleteResponseItem)),
+ SpaceReclaimed: v.optional(v.number()),
+ }),
+ "500": ErrorResponse,
+ }),
});
export type post_SystemAuth = v.InferOutput;
@@ -2336,7 +2588,19 @@ export const post_SystemAuth = v.object({
parameters: v.object({
body: AuthConfig,
}),
- response: v.unknown(),
+ response: v.object({
+ Status: v.string(),
+ IdentityToken: v.optional(v.union([v.string(), v.undefined()])),
+ }),
+ responses: v.object({
+ "200": v.object({
+ Status: v.string(),
+ IdentityToken: v.optional(v.union([v.string(), v.undefined()])),
+ }),
+ "204": v.unknown(),
+ "401": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_SystemInfo = v.InferOutput;
@@ -2346,6 +2610,10 @@ export const get_SystemInfo = v.object({
requestFormat: v.literal("json"),
parameters: v.never(),
response: SystemInfo,
+ responses: v.object({
+ "200": SystemInfo,
+ "500": ErrorResponse,
+ }),
});
export type get_SystemVersion = v.InferOutput;
@@ -2355,6 +2623,10 @@ export const get_SystemVersion = v.object({
requestFormat: v.literal("json"),
parameters: v.never(),
response: SystemVersion,
+ responses: v.object({
+ "200": SystemVersion,
+ "500": ErrorResponse,
+ }),
});
export type get_SystemPing = v.InferOutput;
@@ -2364,6 +2636,10 @@ export const get_SystemPing = v.object({
requestFormat: v.literal("json"),
parameters: v.never(),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "500": v.unknown(),
+ }),
responseHeaders: v.object({
swarm: v.union([
v.literal("inactive"),
@@ -2388,6 +2664,10 @@ export const head_SystemPingHead = v.object({
requestFormat: v.literal("json"),
parameters: v.never(),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "500": v.unknown(),
+ }),
responseHeaders: v.object({
swarm: v.union([
v.literal("inactive"),
@@ -2423,6 +2703,11 @@ export const post_ImageCommit = v.object({
body: ContainerConfig,
}),
response: IdResponse,
+ responses: v.object({
+ "201": IdResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_SystemEvents = v.InferOutput;
@@ -2438,6 +2723,11 @@ export const get_SystemEvents = v.object({
}),
}),
response: EventMessage,
+ responses: v.object({
+ "200": EventMessage,
+ "400": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_SystemDataUsage = v.InferOutput;
@@ -2459,6 +2749,16 @@ export const get_SystemDataUsage = v.object({
Volumes: v.optional(v.array(Volume)),
BuildCache: v.optional(v.array(BuildCache)),
}),
+ responses: v.object({
+ "200": v.object({
+ LayersSize: v.optional(v.number()),
+ Images: v.optional(v.array(ImageSummary)),
+ Containers: v.optional(v.array(ContainerSummary)),
+ Volumes: v.optional(v.array(Volume)),
+ BuildCache: v.optional(v.array(BuildCache)),
+ }),
+ "500": ErrorResponse,
+ }),
});
export type get_ImageGet = v.InferOutput;
@@ -2472,6 +2772,10 @@ export const get_ImageGet = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "500": v.unknown(),
+ }),
});
export type get_ImageGetAll = v.InferOutput;
@@ -2485,6 +2789,10 @@ export const get_ImageGetAll = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "500": v.unknown(),
+ }),
});
export type post_ImageLoad = v.InferOutput;
@@ -2498,6 +2806,10 @@ export const post_ImageLoad = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "500": ErrorResponse,
+ }),
});
export type post_ContainerExec = v.InferOutput;
@@ -2524,6 +2836,12 @@ export const post_ContainerExec = v.object({
}),
}),
response: IdResponse,
+ responses: v.object({
+ "201": IdResponse,
+ "404": ErrorResponse,
+ "409": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type post_ExecStart = v.InferOutput;
@@ -2542,6 +2860,11 @@ export const post_ExecStart = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "404": v.unknown(),
+ "409": v.unknown(),
+ }),
});
export type post_ExecResize = v.InferOutput;
@@ -2559,6 +2882,12 @@ export const post_ExecResize = v.object({
}),
}),
response: v.unknown(),
+ responses: v.object({
+ "200": v.unknown(),
+ "400": ErrorResponse,
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_ExecInspect = v.InferOutput;
@@ -2584,6 +2913,23 @@ export const get_ExecInspect = v.object({
ContainerID: v.optional(v.string()),
Pid: v.optional(v.number()),
}),
+ responses: v.object({
+ "200": v.object({
+ CanRemove: v.optional(v.boolean()),
+ DetachKeys: v.optional(v.string()),
+ ID: v.optional(v.string()),
+ Running: v.optional(v.boolean()),
+ ExitCode: v.optional(v.number()),
+ ProcessConfig: v.optional(ProcessConfig),
+ OpenStdin: v.optional(v.boolean()),
+ OpenStderr: v.optional(v.boolean()),
+ OpenStdout: v.optional(v.boolean()),
+ ContainerID: v.optional(v.string()),
+ Pid: v.optional(v.number()),
+ }),
+ "404": ErrorResponse,
+ "500": ErrorResponse,
+ }),
});
export type get_VolumeList = v.InferOutput