OpenAPI vers Fetch

Générateur de Client TypeScript Fetch Natif depuis OpenAPI & Swagger

Générez des clients d'API TypeScript en fetch natif sans dépendance externe, avec sérialisation des requêtes, en-têtes et typage complet.

6 opérations • 4 modèles
Préréglages :
Architecture:
Format de Réponse:
YAMLBase: https://petstore3.swagger.io/api/v3
Spécification OpenAPI / Swagger (YAML ou 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
Opérations d'API
4
Modèles TypeScript
9.5 KB
Taille du Fichier Généré

Confidentialité 100% Côté Client

Aucun envoi vers un serveur ni télémétrie. Vos contrats d'API confidentiels sont analysés exclusivement dans la mémoire locale de votre navigateur.

Fetch Natif Zéro Dépendance

Génère du code exploitant l'API Web Fetch standard, parfaitement compatible avec les navigateurs, Node.js 18+, Bun, Deno et Next.js sans dépendances externes.

Sérialisation et Typage Strict

Remplacement automatique des paramètres d'URL, sérialisation URLSearchParams, support multipart/form-data et gestion typée des erreurs ApiError.

Référence technique et guide d'architecture

Guide Développeur du Générateur de Client TypeScript Fetch Natif depuis OpenAPI & Swagger — Guide de référence

Générez des clients d'API TypeScript en fetch natif sans dépendance externe, avec sérialisation des requêtes, en-têtes et typage complet.

Paramètres clés et contrôles

architecture'class' | 'functional'

Définit l'architecture du client : classe orientée objet avec configuration partagée ou fonctions autonomes compatibles avec le tree-shaking.

Par défaut : 'class'
unwrapResponse'direct' | 'envelope'

Définit la structure de retour : corps de réponse directement extrait (Promise<T>) ou enveloppe HTTP complète ({ data, status, headers }).

Par défaut : 'direct'
includeJsdocboolean

Injecte les résumés, descriptions et annotations de paramètres OpenAPI sous forme de commentaires JSDoc dans les méthodes TypeScript.

Par défaut : true
strictNullChecksboolean

Applique des propriétés optionnelles strictes et des types nuls explicites (T | null) conformes au mode strict de TypeScript.

Par défaut : true
includeTimeoutboolean

Intègre la gestion native des délais d'expiration configurables en millisecondes via AbortController pour fiabiliser les requêtes.

Par défaut : true
includeMockStubsboolean

Génère des jeux de données simulées et des implémentations de test pour les tests unitaires hors ligne et le prototypage d'interface.

Par défaut : false

Conseils de pro et bonnes practices

Pour les architectures micro-frontends

Pour les architectures micro-frontends ou les fonctions serverless edge, sélectionnez le 'SDK Fonctionnel'. Les bundlers modernes (Vite, Rollup, Webpack) élimineront les routes inutilisées grâce au tree-shaking.

Transmettez les options RequestInit

Transmettez les options RequestInit telles que next: { revalidate: 60, tags: ['articles'] } ou cache: 'no-store' directement aux méthodes générées afin d'exploiter le cache natif et l'ISR de Next.js.

Gestion Typée des Erreurs sans Axios

Interceptez la classe d'exception typée ApiError générée dans des blocs try/catch classiques pour inspecter les statuts HTTP et les charges utiles d'erreur sans recourir à des intercepteurs tiers.

Pièges courants et dépannage

Les références de schéma ($ref) dans les definitions de Swagger 2.0 ne sont pas reconnues

L'analyseur convertit automatiquement les anciens pointeurs Swagger 2.0 #/definitions/ et les schémas OpenAPI 3.x #/components/schemas/ en interfaces TypeScript au format PascalCase.

Les paramètres de requête de type tableau sont mal interprétés par le serveur

Ajustez le format de sérialisation d'URLSearchParams selon les exigences de votre backend (format explosé à clés répétées ou délimité par des virgules pour FastAPI, Express ou Spring).

Erreurs CORS ou cookies de session non transmis dans le navigateur

Spécifiez { credentials: 'include' } dans la configuration du client ou au niveau des options par requête pour autoriser l'envoi sécurisé des cookies d'authentification entre domaines.

Foire aux questions (FAQ)

Pourquoi privilégier le Fetch natif plutôt qu'Axios ou des générateurs lourds ?▼

Le Fetch natif est un standard du Web pris en charge par tous les navigateurs modernes, Node.js 18+, Bun, Deno et les environnements Edge. Supprimer Axios permet d'économiser 15 à 40 Ko sur le bundle et prévient les failles de sécurité tierces.

Comment sont gérées l'interpolation des routes et la sérialisation des requêtes ?▼

Les paramètres de chemin d'accès (ex. : /users/{id}) sont interpolés de manière sécurisée avec encodeURIComponent, tandis que les paramètres de requête sont sérialisés via URLSearchParams en ignorant automatiquement les valeurs null ou undefined.

Mes spécifications d'API confidentielles sont-elles transmises à un serveur ?▼

Non. L'analyse syntaxique OpenAPI, la génération d'arbre syntaxique (AST) et l'émission du code TypeScript s'exécutent intégralement en mémoire dans votre navigateur web local. Aucune donnée ne quitte votre machine.

Est-il possible de générer des React Hooks pour TanStack Query ou SWR ?▼

Oui. Rendez-vous dans l'onglet 'React Hooks' pour exporter des hooks personnalisés et des fonctions fetcher directement exploitables avec TanStack Query (React Query) et SWR.

Comment le client généré traite-t-il les statuts d'erreur HTTP (4xx et 5xx) ?▼

L'API fetch ne rejetant pas la promesse sur un code d'erreur HTTP, le client généré vérifie response.ok, extrait le contenu d'erreur JSON et lève une exception typée ApiError contenant le statut et les en-têtes.

Outils et utilitaires connexes

Tous les outils →
Guide Développeur : Générateur de DDL SQL CREATE TABLE depuis Schéma Drizzle ORMDéveloppement

Traduisez fidèlement les définitions pgTable, mysqlTable et sqliteTable de Drizzle ORM en scripts de migration SQL CREATE TABLE exécutables.

Ouvrir l'outil→
Guide de développement pour le générateur de workflows YAML GitHub Actions CI/CDDéveloppement

Créez des pipelines YAML GitHub Actions prêts pour la production pour Node.js, Go, Python, conteneurs Docker, tests unitaires et déploiements automatisés.

Ouvrir l'outil→
Générateur de Configuration Linux Logrotate (Rétention & Compression)Développement

Générez des fichiers de configuration /etc/logrotate.d/ prêts pour la production avec rotation quotidienne/hebdomadaire, compression gzip, dateext, limites de taille et scripts postrotate.

Ouvrir l'outil→
Guide Développeur du Générateur de Configuration YAML Ubuntu NetplanDéveloppement

Générez des configurations YAML Netplan pour Ubuntu 20.04/22.04/24.04 : adresses IP statiques, DHCP, résolveurs DNS, passerelles, ponts et agrégations de liens.

Ouvrir l'outil→
Guide Développeur : Générateur de Modèles Python SQLAlchemy 2.0 depuis SQL DDLDéveloppement

Convertissez vos instructions SQL CREATE TABLE en modèles Python SQLAlchemy 2.0 DeclarativeBase fortement typés avec les annotations Mapped et mapped_column.

Ouvrir l'outil→
Guide Développeur : Générateur de Modèles Struct Golang GORM depuis SQL DDLDéveloppement

Convertissez vos schémas SQL CREATE TABLE en définitions de structures (struct) Golang avec balises GORM, balises JSON et typage Go précis.

Ouvrir l'outil→