OpenAPIからFetch変換

OpenAPI・Swagger ネイティブFetchクライアント自動生成ツール

依存関係ゼロの標準Fetch APIを活用したTypeScriptクライアントコードを生成。クエリ文字列のシリアライズ、ヘッダー設定、型定義を自動完結。

6 個のエンドポイント • 4 個のモデル
プリセット:
クライアント形式:
レスポンス形式:
YAMLBase: https://petstore3.swagger.io/api/v3
OpenAPI / Swagger 仕様書 (YAMLまたは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操作数
4
型定義モデル数
9.5 KB
クライアント生成サイズ

100% クライアント内完結の安全性

機密性の高いAPI仕様書や社内スキーマを外部サーバーへ一切送信しません。すべてのパースとコード生成はブラウザのローカルメモリ内で即座に完了します。

外部依存ゼロのネイティブFetch

Axios等の外部ライブラリを一切使わず、ブラウザ標準Fetch、Node.js 18+、Bun、Deno、Next.js Server Actionsでそのまま動作する軽量コードを出力します。

型安全なシリアライズ&エラーハンドリング

URLパスパラメータの自動置換、URLSearchParamsによるクエリ文字列変換、Multipart/FormData、カスタムヘッダー、構造化ApiErrorを完全自動化します。

技術リファレンス&アーキテクチャガイド

OpenAPI・Swagger ネイティブFetchクライアント自動生成 開発者向け技術リファレンス — リファレンスガイド

依存関係ゼロの標準Fetch APIを活用したTypeScriptクライアントコードを生成。クエリ文字列のシリアライズ、ヘッダー設定、型定義を自動完結。

主要パラメータ&設定項目

architecture'class' | 'functional'

クライアントのアーキテクチャを指定。共通設定を持つOOPクラス形式、またはTree-shakingに最適化された個別関数形式を選択可能。

初期値: 'class'
unwrapResponse'direct' | 'envelope'

戻り値の構造を指定。パース済みデータのみを直接返す形式(Promise<T>)か、HTTPメタデータを含む形式({ data, status, headers })を選択。

初期値: 'direct'
includeJsdocboolean

OpenAPIの概要、詳細説明、パラメータ情報をJSDocコメントとして各TypeScriptメソッドに埋め込むかどうかを指定。

初期値: true
strictNullChecksboolean

TypeScriptのstrictモードに準拠し、オプショナルプロパティおよび厳格なnull許容型(T | null)を適用。

初期値: true
includeTimeoutboolean

AbortControllerを利用したタイムアウト機能(ミリ秒指定)とリクエスト中断ハンドリングを自動生成。

初期値: true
includeMockStubsboolean

オフラインテストやUIプロトタイピングに役立つモックデータおよびスタブクライアント実装を生成。

初期値: false

プロの活用テクニック&推奨設定

Functionalモードでバンドルサイズを極小化

マイクロフロントエンドやエッジ環境(Cloudflare Workers等)では「Functional SDK」を選択してください。RollupやWebpack、Vite等のバンドラが未使用エンドポイントをTree-shakingで自動除去し、バンドルサイズを最小化できます。

Next.js App Routerとのネイティブ連携

生成されたメソッドのRequestInit引数に next: { revalidate: 60, tags: ['cache-tag'] } や cache: 'no-store' を渡すことで、Next.jsのデータキャッシュとISRを直接制御できます。

型安全なエラーハンドリングの実現

「Full Response」形式を選択するか、生成された型定義付きApiError例外をtry/catchで捕捉することで、Axiosのインターセプターに頼ることなくクリーンにステータスコード別の分岐処理を記述できます。

よくあるトラブルと解決策

Swagger 2.0の古い定義(#/definitions/)が読み込めない

本パーサーはSwagger 2.0の #/definitions/ およびOpenAPI 3.xの #/components/schemas/ の両方を自動検出し、パスカルケースのTypeScriptインターフェースへ正規化します。

配列形式のクエリパラメータが正しく送信されない

バックエンド(Express、FastAPI、Spring等)の受け取り形式に合わせて、URLSearchParamsのexplode展開またはカンマ区切り設定を調整してください。

CORSエラーやCookie認証情報がブラウザから送信されない

クライアント初期化時または各リクエストオプションで { credentials: 'include' } を指定することで、同一/クロスオリジン間でのセッションCookie送信を有効化できます。

よくある質問 (FAQ)

Axiosではなく標準ネイティブFetchを採用するメリットは何ですか?▼

Web標準のFetch APIは最新ブラウザ、Node.js 18+、Bun、Deno、エッジ環境に標準搭載されています。Axiosや重厚なSDKジェネレータを排除することで、15〜40KBのバンドル容量削減とサプライチェーンリスク低減を実現できます。

パスパラメータやクエリパラメータはどのようにシリアライズされますか?▼

URLパスパラメータ(例:/users/{id})はencodeURIComponentで安全に補間され、クエリパラメータはURLSearchParamsによりundefinedやnull値を自動除外して安全に文字列化されます。

社内非公開のAPI仕様書が外部サーバーへ送信される危険はありますか?▼

一切ありません。仕様書のYAML/JSON構文解析からAST変換、TypeScriptコード生成まで、すべてブラウザローカルのメモリ内で100%完結します。

React HooksやTanStack Queryと連携できますか?▼

はい。「React Hooks」タブを選択することで、TanStack Query(React Query)やSWRでそのまま活用できるカスタムフックおよびフェッチャー関数を出力できます。

HTTPエラー(4xx/5xx)はどのようにハンドリングされますか?▼

Fetch APIはHTTPエラーステータスでもPromiseを拒否しないため、生成コード側で response.ok を判定し、レスポンス本文を含めた型付き ApiError を自動的にスローします。

関連するおすすめ開発ツール

すべてのツール →
Drizzle ORM スキーマから SQL CREATE TABLE DDL 生成ツール開発ツール

Drizzle ORM の pgTable、mysqlTable、sqliteTable 定義を高精度に解析し、実行可能な SQL CREATE TABLE マイグレーションスクリプトへと変換します。

ツールを開く→
GitHub Actions CI/CD ワークフロー YAML 生成ガイド開発ツール

Node.js、Go、Python、Docker ビルド、ユニットテスト、自動リリースに対応した本番向け GitHub Actions ワークフロー YAML パイプラインを安全かつ迅速に構築します。

ツールを開く→
Linux Logrotate 設定ファイル生成ツール (保持期間 & 圧縮設定ガイド)開発ツール

日次・週次ローテーション、gzip圧縮、dateext、ファイルサイズ制限、postrotateスクリプトを含む本番環境用 /etc/logrotate.d/ 設定ファイルを安全に生成。

ツールを開く→
Ubuntu Netplan ネットワーク設定 YAML 生成ツール開発ツール

Ubuntu 20.04/22.04/24.04 向けの Netplan YAML 設定(静的IP、DHCP、DNSネームサーバー、ゲートウェイルート、仮想ブリッジ、BOND構成)をブラウザ上で安全に生成。

ツールを開く→
SQL DDL から Python SQLAlchemy 2.0 モデル生成ツール開発ツール

SQL の CREATE TABLE 文を、最新の Mapped および mapped_column 型注釈を備えた堅牢な Python SQLAlchemy 2.0 DeclarativeBase モデルへ即座に変換します。

ツールを開く→
SQL DDLからGolang GORM構造体モデル生成ツール開発ツール

SQLのCREATE TABLEスキーマからGORMタグ、JSONタグ、適切なGo型マッピングを備えたGolang構造体(struct)モデルを瞬時に自動生成します。

ツールを開く→