OpenAPI zu Fetch

OpenAPI & Swagger zu nativem Fetch TypeScript Client Generator

Erstellen Sie abhängigkeitsfreie native Fetch TypeScript API-Clients mit Abfrageparameter-Serialisierung, Headern und Antworttypen.

6 Operationen • 4 Modelle
Voreinstellungen:
Architektur:
Antwortformat:
YAMLBase: https://petstore3.swagger.io/api/v3
OpenAPI / Swagger Spezifikation (YAML oder JSON)YAML
/**
 * Zero-Dependency Native Fetch TypeScript Client
 * API: Swagger Petstore (v1.0.0)
 * Base URL: https://petstore3.swagger.io/api/v3
 * Standard Web Fetch API compatible with Browsers, Node.js 18+, Bun, Deno, and Next.js
 */

/**
 * Generated TypeScript Interfaces & Models
 * API: Swagger Petstore (v1.0.0)
 * Spec: OpenAPI 3.0.3
 * Generated automatically by ToolsAA Native Fetch Generator
 */

Category {
  id?: number | undefined;
  name?: string | undefined;
}

Tag {
  id?: number | undefined;
  name?: string | undefined;
}

Pet {
  id: number;
  name: string;
  category?: Category | undefined;
  photoUrls?: string[] | undefined;
  tags?: Tag[] | undefined;
  status?: 'available' | 'pending' | 'sold' | undefined;
}

ApiResponse {
  code?: number | undefined;
  type?: string | undefined;
  message?: string | undefined;
}

// ============================================================================
// Operation Parameter Interfaces
// ============================================================================

ListPetsQueryParams {
  /** Status values that need to be considered for filter */
  status?: 'available' | 'pending' | 'sold' | undefined;
  /** How many items to return at one time (max 100) */
  limit?: number | undefined;
}

GetPetByIdPathParams {
  /** The id of the pet to retrieve */
  petId: number;
}

DeletePetPathParams {
  /** Pet id to delete */
  petId: number;
}

DeletePetHeaders {
  api_key?: string | undefined;
}

UploadFilePathParams {
  /** ID of pet to update */
  petId: number;
}

UploadFileQueryParams {
  additionalMetadata?: string | undefined;
}


// ============================================================================
// Runtime ApiError & Client Infrastructure
// ============================================================================

export class ApiError extends Error {
  readonly status: number;
  readonly statusText: string;
  readonly data: unknown;
  readonly headers: Headers;

  constructor(status: number, statusText: string, data: unknown, headers: Headers) {
    super(`HTTP ${status} ${statusText}`);
    this.name = 'ApiError';
    this.status = status;
    this.statusText = statusText;
    this.data = data;
    this.headers = headers;
  }
}

FetchClientConfig {
  baseUrl?: string;
  headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
  customFetch?: typeof fetch;
  timeoutMs?: number;
  onRequest?: (url: string, init: RequestInit) => void | Promise<void>;
  onResponse?: (response: Response) => void | Promise<void>;
}

RequestOptions extends Omit<RequestInit, 'body' | 'headers'> {
  headers?: Record<string, string>;
  query?: Record<string, any>;
  timeoutMs?: number;
}

ApiResponseEnvelope<T> {
  data: T;
  status: number;
  headers: Headers;
}

function serializeQuery(query?: Record<string, any>): string {
  if (!query) return '';
  const params = new URLSearchParams();
  for (const [key, value] of Object.entries(query)) {
    if (value === undefined || value === null) continue;
    if (Array.isArray(value)) {
      value.forEach((v) => params.append(key, String(v)));
    } else {
      params.append(key, String(value));
    }
  }
  const str = params.toString();
  return str ? `?${str}` : '';
}

async function executeFetch<T>(
  config: FetchClientConfig,
  method: string,
  path: string,
  options?: RequestOptions & { body?: any }
): Promise<T> {
  const baseUrl = (config.baseUrl || 'https://petstore3.swagger.io/api/v3').replace(/\/+$/, '');
  const queryString = serializeQuery(options?.query);
  const fullUrl = `${baseUrl}${path.startsWith('/') ? path : '/' + path}${queryString}`;

  let dynamicHeaders: Record<string, string> = {};
  if (typeof config.headers === 'function') {
    dynamicHeaders = await config.headers();
  } else if (config.headers) {
    dynamicHeaders = config.headers;
  }

  const headers = new Headers({
    ...dynamicHeaders,
    ...options?.headers,
  });

  let requestBody: any = undefined;
  if (options?.body !== undefined) {
    if (typeof FormData !== 'undefined' && options.body instanceof FormData) {
      requestBody = options.body;
      // Browser sets multipart boundary automatically, remove conflicting content-type
      headers.delete('Content-Type');
    } else if (typeof Blob !== 'undefined' && options.body instanceof Blob) {
      requestBody = options.body;
    } else if (typeof options.body === 'object') {
      if (!headers.has('Content-Type')) {
        headers.set('Content-Type', 'application/json');
      }
      requestBody = JSON.stringify(options.body);
    } else {
      requestBody = String(options.body);
    }
  }

  const timeoutMs = options?.timeoutMs ?? config.timeoutMs ?? 15000;
  let signal = options?.signal;
  let timeoutId: any = null;

  if (!signal && typeof AbortController !== 'undefined') {
    const controller = new AbortController();
    timeoutId = setTimeout(() => controller.abort(new Error('Request Timeout')), timeoutMs);
    signal = controller.signal;
  }

  const requestInit: RequestInit = {
    method,
    headers,
    body: requestBody,
    signal,
    ...options,
  };

  if (config.onRequest) {
    await config.onRequest(fullUrl, requestInit);
  }

  const fetchFn = config.customFetch || fetch;

  try {
    const response = await fetchFn(fullUrl, requestInit);
    if (config.onResponse) {
      await config.onResponse(response);
    }

    let responseData: any = null;
    if (response.status !== 204) {
      const contentType = response.headers.get('content-type') || '';
      if (contentType.includes('application/json')) {
        responseData = await response.json();
      } else {
        responseData = await response.text();
      }
    }

    if (!response.ok) {
      throw new ApiError(response.status, response.statusText, responseData, response.headers);
    }

    return responseData as T;
  } finally {
    if (timeoutId) clearTimeout(timeoutId);
  }
}

// ============================================================================
// Flagship ApiClient Class
// ============================================================================

export class ApiClient {
  private config: FetchClientConfig;

  constructor(config: FetchClientConfig = {}) {
    this.config = config;
  }

  public setBaseUrl(url: string): void {
    this.config.baseUrl = url;
  }

  public setHeaders(headers: Record<string, string>): void {
    this.config.headers = headers;
  }

  public setBearerToken(token: string): void {
    this.config.headers = { ...((typeof this.config.headers === 'object' ? this.config.headers : {})), Authorization: `Bearer ${token}` };
  }

  public setApiKey(key: string, headerName: string = 'X-API-Key'): void {
    this.config.headers = { ...((typeof this.config.headers === 'object' ? this.config.headers : {})), [headerName]: key };
  }

  /**
   * List all pets
   * @description Returns all pets from the store with optional status and tag filtering.
   * @route GET /pets
   * @param query URL search query parameters
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async listPets(query?: ListPetsQueryParams, options?: RequestOptions): Promise<Pet[]> {
    const path = '/pets';
    return executeFetch<Pet[]>(this.config, 'GET', path, { ...options, query });
  }

  /**
   * Create a pet
   * @description Adds a new pet to the catalog.
   * @route POST /pets
   * @param body Request payload (application/json)
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async createPet(body: Pet, options?: RequestOptions): Promise<Pet> {
    const path = '/pets';
    return executeFetch<Pet>(this.config, 'POST', path, { ...options, body });
  }

  /**
   * Info for a specific pet
   * @route GET /pets/{petId}
   * @param pathParams URL path interpolation parameters
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async getPetById(pathParams: GetPetByIdPathParams, options?: RequestOptions): Promise<Pet> {
    const path = `/pets/${encodeURIComponent(String(pathParams['petId']))}`;
    return executeFetch<Pet>(this.config, 'GET', path, { ...options });
  }

  /**
   * Deletes a pet
   * @route DELETE /pets/{petId}
   * @param pathParams URL path interpolation parameters
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async deletePet(pathParams: DeletePetPathParams, options?: RequestOptions): Promise<void> {
    const path = `/pets/${encodeURIComponent(String(pathParams['petId']))}`;
    return executeFetch<void>(this.config, 'DELETE', path, { ...options });
  }

  /**
   * Uploads an image
   * @route POST /pets/{petId}/uploadImage
   * @param pathParams URL path interpolation parameters
   * @param body Request payload (multipart/form-data)
   * @param query URL search query parameters
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async uploadFile(pathParams: UploadFilePathParams, body?: {
   /** File to upload @format binary */
  file?: Blob | File | undefined;
}, query?: UploadFileQueryParams, options?: RequestOptions): Promise<ApiResponse> {
    const path = `/pets/${encodeURIComponent(String(pathParams['petId']))}/uploadImage`;
    return executeFetch<ApiResponse>(this.config, 'POST', path, { ...options, query, body });
  }

  /**
   * Returns pet inventories by status
   * @route GET /store/inventory
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async getInventory(options?: RequestOptions): Promise<Record<string, number>> {
    const path = '/store/inventory';
    return executeFetch<Record<string, number>>(this.config, 'GET', path, { ...options });
  }

}

api = new ApiClient();
export default ApiClient;
6
API-Operationen
4
TypeScript-Modelle
9.5 KB
Generierte Dateigröße

100% Client-seitige Privatsphäre

Keine Server-Uploads oder Telemetrie. Ihre vertraulichen API-Spezifikationen werden ausschließlich im lokalen Browserspeicher verarbeitet.

Abhängigkeitsfreier nativer Fetch

Generiert reinen Web-Fetch-API-Code ohne externe Bibliotheken, sofort kompatibel mit Browsern, Node.js 18+, Bun, Deno und Next.js.

Vollständige typsichere Serialisierung

Automatische Pfadparameter-Interpolation, URLSearchParams, multipart/form-data und typisiertes ApiError-Handling.

Technische Referenz & Architektur-Leitfaden

OpenAPI & Swagger zu Native Fetch TypeScript Client Generator Entwickler-Handbuch — Referenz-Leitfaden

Erstellen Sie abhängigkeitsfreie native Fetch TypeScript API-Clients mit Abfrageparameter-Serialisierung, Headern und Antworttypen.

Wichtige Parameter & Steuerelemente

architecture'class' | 'functional'

Definiert die Client-Architektur: Objektorientierte Client-Klasse mit gemeinsamen Konfigurationen oder Tree-Shake-bare funktionale Einzelfunktionen.

Standard: 'class'
unwrapResponse'direct' | 'envelope'

Legt die Rückgabestruktur fest: Direkt entpackter Nutzdaten-Body (Promise<T>) oder vollständiges HTTP-Envelope ({ data, status, headers }).

Standard: 'direct'
includeJsdocboolean

Bettet OpenAPI-Zusammenfassungen, Beschreibungen und Parameter-Annotationen als JSDoc-Kommentare in TypeScript-Methoden ein.

Standard: true
strictNullChecksboolean

Erzwingt strikte optionale Eigenschaften und explizite Null-Unions (T | null) konform zum TypeScript-Strict-Mode.

Standard: true
includeTimeoutboolean

Integriert eine konfigurierbare Timeout-Unterstützung in Millisekunden über AbortController-Signale für Netzwerk-Resilienz.

Standard: true
includeMockStubsboolean

Generiert realistische Mock-Daten und Test-Client-Implementierungen für Offline-Unit-Tests und UI-Prototypen.

Standard: false

Profi-Tipps & Best Practices

Wählen Sie in Micro-Frontends oder

Wählen Sie in Micro-Frontends oder Serverless Edge Handlern den 'Funktionalen SDK'-Modus. Moderne Bundler wie Vite, Rollup und Webpack entfernen ungenutzte API-Routen automatisch via Tree-Shaking.

Nahtlose Next.js App Router Integration

Übergeben Sie erweiterte RequestInit-Optionen wie next: { revalidate: 60, tags: ['posts'] } oder cache: 'no-store' direkt an die generierten Methoden, um das Caching von Next.js optimal zu nutzen.

Typsichere Fehlerbehandlung ohne Axios

Nutzen Sie den Envelope-Modus oder fangen Sie die generierte typisierte ApiError-Klasse in try/catch-Blöcken ab, um Statuscodes präzise und ohne schwere externe Bibliotheken zu prüfen.

Häufige Fallstricke & Fehlerbehebung

Swagger 2.0 Schemareferenzen ($ref) werden in definitions nicht aufgelöst

Der Parser normalisiert ältere Swagger 2.0 #/definitions/-Pfade und OpenAPI 3.x #/components/schemas/-Ziele automatisch in saubere PascalCase-TypeScript-Schnittstellen.

Array-Abfrageparameter werden vom Backend falsch interpretiert

Passen Sie die URLSearchParams-Serialisierung an die Anforderungen Ihres Backends (z.B. Spring Boot, FastAPI oder Express) bezüglich Explode- oder Komma-Formatierung an.

CORS-Fehler oder fehlende Cookies im Browser-Umfeld

Konfigurieren Sie { credentials: 'include' } in der globalen Client-Initialisierung oder in den Request-Optionen, um HTTP-Cookies und Autorisierungs-Header zu übertragen.

Häufig gestellte Fragen (FAQ)

Warum sollte man nativen Fetch anstelle von Axios verwenden?▼

Die native Fetch-API ist ein offizieller Webstandard in allen modernen Browsern, Node.js 18+, Bun, Deno und Edge-Laufzeitumgebungen. Der Verzicht auf Axios spart 15–40 KB Bundle-Größe und verhindert Abhängigkeitskonflikte.

Wie werden Pfadparameter und Query-Strings serialisiert?▼

Pfadparameter wie /users/{id} werden sicher mit encodeURIComponent interpoliert. Abfrageparameter werden über URLSearchParams serialisiert, wobei nicht definierte oder null-Werte automatisch ignoriert werden.

Werden vertrauliche API-Spezifikationen an externe Server übertragen?▼

Nein. Die gesamte Analyse, AST-Generierung und TypeScript-Ausgabe erfolgt zu 100% clientseitig im lokalen Arbeitsspeicher Ihres Browsers. Es findet keinerlei Serverübertragung statt.

Können React Hooks oder TanStack Query Client-Funktionen generiert werden?▼

Ja. Im Tab 'React Hooks' erhalten Sie sofort einsatzbereite benutzerdefinierte Hooks und Abfragefunktionen für TanStack Query (React Query) und SWR.

Wie behandelt der generierte Client HTTP-Fehlercodes (4xx/5xx)?▼

Da fetch bei HTTP-Fehlercodes nicht standardmäßig abbricht, prüft der generierte Client response.ok, liest JSON-Fehlerdetails aus und wirft eine typisierte ApiError-Instanz mit Statuscode und Headern.

Verwandte Werkzeuge & Dienstprogramme

Alle Werkzeuge →