From 4ce4aebdb0c1af9f5872b8c582a35f37df6a4e8c Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Wed, 14 Aug 2024 07:45:13 +0900 Subject: [PATCH 01/24] docs(ja): openapi-typescript, about --- docs/ja/about.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 docs/ja/about.md diff --git a/docs/ja/about.md b/docs/ja/about.md new file mode 100644 index 000000000..aa963be1c --- /dev/null +++ b/docs/ja/about.md @@ -0,0 +1,60 @@ +--- +title: openapi-typescriptについて +description: このプロジェクトに関する追加情報 +--- + + + +# openapi-typescriptについて + +## 利用者 + +- [**Bigcommerce**](https://github.com/bigcommerce/bigcommerce-api-node): BigCommerce API 用の Node SDK +- [**Budibase**](https://github.com/Budibase/budibase): 内部ツール、ワークフロー、および管理ダッシュボードを作成するためのローコードプラットフォーム +- [**Fedora `fmn`**](https://github.com/fedora-infra/fmn): Fedora メッセージインフラストラクチャのツールと API +- [**Fingerprint**](https://github.com/fingerprintjs/fingerprintjs-pro-server-api-node-sdk): 大規模なアプリケーション向けのデバイスフィンガープリンティング +- [**Google Firebase CLI**](https://github.com/firebase/firebase-tools): Google Firebase プラットフォーム用の公式 CLI +- [**GitHub Octokit**](https://github.com/octokit): GitHub API の公式 SDK +- [**Lotus**](https://github.com/uselotus/lotus): オープンソースの価格設定およびパッケージングインフラストラクチャ +- [**Jitsu**](https://github.com/jitsucom/jitsu): モダンでオープンソースのデータ収集/データパイプライン +- [**Medusa**](https://github.com/medusajs/medusa): デジタルコマースの構築ブロック +- [**Netlify**](https://netlify.com): モダンな開発プラットフォーム +- [**Nuxt**](https://github.com/unjs/nitro): 直感的な Vue フレームワーク +- [**Relevance AI**](https://github.com/RelevanceAI/relevance-js-sdk): AI チェーンの構築と展開 +- [**Revolt**](https://github.com/revoltchat/api): オープンソースのユーザー優先チャットプラットフォーム +- [**Spacebar**](https://github.com/spacebarchat): 無料でオープンソースの自ホスト可能な Discord 互換のチャット/音声/ビデオプラットフォーム +- [**Supabase**](https://github.com/supabase/supabase): オープンソースの Firebase 代替 +- [**Twitter API**](https://github.com/twitterdev/twitter-api-typescript-sdk): Twitter API の公式 SDK + +## プロジェクトの目標 + +1. 任意の有効な OpenAPI スキーマを TypeScript 型に変換できるようにすること。どんなに複雑なスキーマでも対応可能です。 +2. 生成される型は静的に解析可能で、実行時の依存関係がない(ただし、[enum](https://www.typescriptlang.org/docs/handbook/enums.html) のような例外はあります)。 +3. 生成された型は、元のスキーマにできるだけ一致し、元の大文字形式などを保持します。 +4. 型の生成 は Node.js だけで実行可能であり、(Java、Python などは不要)どんな環境でも実行できます。 +5. ファイルからの OpenAPI スキーマのフェッチや、ローカルおよびリモートサーバーからのフェッチをサポートします。 + +## 比較 + +### vs. swagger-codegen + +openapi-typescript は、swagger-codegen の軽量で使いやすい代替手段として作成されており、Java ランタイムや OpenAPI サーバーを実行する必要はありません。また、大規模なクライアントサイドコードも生成しません。実際、openapi-typescript が生成するすべてのコードは、**実行時の依存関係がない静的型** であり、最大のパフォーマンスと最小のクライアント負荷を実現します。 + +### vs. openapi-typescript-codegen + +openapi-typescript-codegen は、元の swagger-codegen の Node.js 代替手段ですが、実際には同じものです。openapi-typescript は、openapi-typescript-codegen と同様に、**実行時の依存関係がない** という利点を持っていますが、openapi-typescript-codegen は、スキーマの複雑さに応じて `250 kB` 以上になるかなり大きなバンドルを生成する可能性があります。 + +### vs. tRPC + +[tRPC](https://trpc.io/) は、強い設計方針を持ったサーバーとクライアントの両方で型の安全性を提供するフレームワークです。これは、サーバーとクライアントの両方が tRPC で記述されていることを要求します(つまり、バックエンドが Node.js を使用しています)。 + +このユースケースに合っているならば、素晴らしい体験ができるでしょう!しかし、他のすべての場合において、openapi-typescript(および openapi-fetch)は、あらゆる技術選択に適応できる、より柔軟で低レベルなソリューションです(コストなしで段階的に導入することさえできます)。 + +## 貢献者 + +これらの素晴らしい貢献者がいなければ、このライブラリは存在しなかったでしょう: + + From 24532b754742e58622e0a5115d49b2aed7bd2f6b Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Wed, 14 Aug 2024 10:03:21 +0900 Subject: [PATCH 02/24] docs(ja): openapi-typescript, advanced --- docs/ja/advanced.md | 457 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 457 insertions(+) create mode 100644 docs/ja/advanced.md diff --git a/docs/ja/advanced.md b/docs/ja/advanced.md new file mode 100644 index 000000000..367637bb0 --- /dev/null +++ b/docs/ja/advanced.md @@ -0,0 +1,457 @@ +--- +title: 高度な使い方 +description: 高度な使い方、ヒント、テクニック、ベストプラクティス +--- + +# 高度な使い方 + +高度な使い方やさまざまなトピックについて説明します。これは _多くの人のための_ 緩やかな提案であり、もしあなたの設定に合わない場合は、ご自由に無視してください。 + +## デバッグ + +デバッグを有効にするには、環境変数 `DEBUG=openapi-ts:*` を以下のように設定します: + +```sh +$ DEBUG=openapi-ts:* npx openapi-typescript schema.yaml -o my-types.ts +``` + +特定の種類のデバッグメッセージのみを表示するには、`DEBUG=openapi-ts:[scope]` を設定します。利用可能なスコープには、`redoc` 、`lint` 、`bundle` 、`ts` があります。 + +出力が `stdout` の場合、デバッグメッセージは抑制されることに注意してください。 + +## 列挙型の拡張 + +`x-enum-varnames` は、対応する値に別の列挙型名を定義するために使用されます。これは列挙項目の名前を定義するために使用されます。 + +`x-enum-descriptions` は、各値に対して個別の説明を提供するために使用できます。これは、コード内のコメント(Javaの場合はjavadocのようなもの)として使用されます。 + +`x-enum-descriptions`および`x-enum-varnames`は、それぞれ列挙型と同じ数の項目を含むリストであることが期待されます。リスト内の項目の順序は重要です:位置を使用してこれらを結びつけます。 + +例: + +::: code-group + +```yaml [my-openapi-3-schema.yaml] +ErrorCode: + type: integer + format: int32 + enum: + - 100 + - 200 + - 300 + x-enum-varnames: + - Unauthorized + - AccessDenied + - Unknown + x-enum-descriptions: + - "ユーザーは認証されていません" + - "ユーザーにはこのリソースへのアクセス権がありません" + - "何かがうまくいきませんでした" +``` + +::: + +これは、次のようになります: + +::: code-group + +```ts [my-openapi-3-schema.d.ts] +enum ErrorCode { + // ユーザーは認証されていません + Unauthorized = 100 + // ユーザーにはこのリソースへのアクセス権がありません + AccessDenied = 200 + // 何かがうまくいきませんでした + Unknown = 300 +} +``` + +::: + +この方法で生成するには、[コマンドライン](cli.md#flags)で `--enum` を指定する必要があります。 + +または、`x-enumNames`および`x-enumDescriptions`([NSwag/NJsonSchema](https://github.com/RicoSuter/NJsonSchema/wiki/Enums#enum-names-and-descriptions))も使用できます。 + +## スタイルガイド + +型生成を改善するためのいくつかの推奨項目を紹介します。 + +### Redocly ルール + +TypeScript生成におけるエラーを減らすために、[Redocly config](https://redocly.com/docs/cli/rules/built-in-rules/)で次の組み込みルールを適用することをお勧めします: + +| ルール | 設定 | 理由 | +| :-------------------------------------------------------------------------------------------- | :----------------: | :------------------------------- | +| [operation-operationId-unique](https://redocly.com/docs/cli/rules/built-in-rules/#operations) | `error` | 無効なTS生成の防止 | +| [operation-parameters-unique](https://redocly.com/docs/cli/rules/built-in-rules/#parameters) | `error` | パラメータの欠落防止 | +| [path-not-include-query](https://redocly.com/docs/cli/rules/built-in-rules/#parameters) | `error` | パラメータの欠落防止 | +| [spec](https://redocly.com/docs/cli/rules/built-in-rules/#special-rules) | `3.0` または `3.1` | より良いスキーマチェックの有効化 | + +### JSでの`snake_case`のサポート + +言語ごとに好まれる構文スタイルは異なります。いくつか例を挙げると: + +- `snake_case` +- `SCREAMING_SNAKE_CASE` +- `camelCase` +- `PascalCase` +- `kebab-case` + +JSのスタイルガイドが推奨するように、APIレスポンスを`camelCase`にリネームしたくなるかもしれません。しかし、リネームは時間の無駄になるだけでなく、次のような保守上の問題を引き起こすため、**リネームを避ける**ことをお勧めします: + +- ❌ 生成された型(たとえばopenapi-typescriptが生成した型)は、手動で入力する必要がある +- ❌ リネームは実行時に発生するため、アプリケーションが隠れた変更を行う際に遅延を引き起こす +- ❌ 名前変更ツールを構築し、維持(およびテスト)する必要がある +- ❌ APIが `requestBodies `に `snake_case` を必要とする場合、すべての作業を各APIリクエストで元に戻さなければならない + +代わりに、「一貫性」をより包括的な概念と見なし、JSスタイルの規約に従うよりもAPIスキーマをそのまま保持することが優れていると認識してください。 + +### TSConfigで `noUncheckedIndexedAccess` を有効にする + +TSConfigで `compilerOptions.noUncheckedIndexedAccess`([ドキュメント](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess))を有効にして、`additionalProperties` キーを `T | undefined` として型付けするようにします。 + +[Additional Properties](https://swagger.io/docs/specification/data-models/dictionaries/)(dictionaries)のデフォルトの動作は、 `Record` という型を生成しますが、これはnull参照エラーを引き起こしやすくなります。TypeScriptは、キーが存在するかどうかを事前に確認せずに任意のキーにアクセスできるため、スペルミスやキーが実際に存在しない場合を防ぐことはできません。 + +### スキーマでの明確な指定 + +openapi-typescriptは**決して `any` 型を生成しません**。どのような型でも、スキーマで明確に定義されていない限り、実際には存在しないものと見なされます。そのため、可能な限り具体的に指定することが重要です。以下に、`additionalProperties` を最大限に活用する方法の例を示します: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
スキーマ生成される型
+ ❌ 悪い + + +```yaml +type: object +``` + + + +```ts +Record; +``` + +
+ ❌ 不十分 + + +```yaml +type: object +additionalProperties: true +``` + + + +```ts +Record; +``` + +
+ ✅ 良い + + +```yaml +type: object +additionalProperties: + type: string +``` + + + +```ts +Record; +``` + +
+ +また、**タプル型**についても、スキーマでその型を明示することで、より良い結果が得られます。これは、`[x, y]` 座標のタプルを型付けする最良の方法です: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 SchemaGenerated Type
+ ❌ 悪い + + +```yaml +type: array +``` + + + +```ts +unknown[] +``` + +
+ ❌ 不十分 + + +```yaml +type: array +items: + type: number +``` + + + +```ts +number[] +``` + +
+ ✅ 良い + + +```yaml +type: array +items: + type: number +maxItems: 2 +minItems: 2 +``` + +— または — + +```yaml +type: array +items: + type: number +prefixItems: + - number + - number +``` + + + +```ts +[number, number]; +``` + +
+ +### `oneOf`を単独で使用する + +OpenAPIのコンポジションツール(`oneOf` / `anyOf` / `allOf`)は、スキーマ内のコード量を減らしながら柔軟性を最大化する強力なツールです。しかし、TypeScriptの共用体型は[XOR](https://en.wikipedia.org/wiki/Exclusive_or)を提供しないため、`oneOf` に直接マッピングすることはできません。そのため、oneOfは単独で使用し、他のコンポジションメソッドやプロパティと組み合わせないことが推奨されます。例えば: + +#### ❌ Bad + +::: code-group + +```yaml [my-openapi-3-schema.yaml] +Pet: + type: object + properties: + type: + type: string + enum: + - cat + - dog + - rabbit + - snake + - turtle + name: + type: string + oneOf: + - $ref: "#/components/schemas/Cat" + - $ref: "#/components/schemas/Dog" + - $ref: "#/components/schemas/Rabbit" + - $ref: "#/components/schemas/Snake" + - $ref: "#/components/schemas/Turtle" +``` + +::: + +これは、TypeScriptのユニオンとインターセクションの両方を組み合わせた次のような型が生成されます。これは有効なTypeScriptですが、複雑であり、推論が意図した通りに機能しない可能性があります。しかし、最も問題となるのは、TypeScriptがtypeプロパティを通じて区別できないことです。 + +::: code-group + +```ts [my-openapi-3-schema.d.ts] + Pet: ({ + /** @enum {string} */ + type?: "cat" | "dog" | "rabbit" | "snake" | "turtle"; + name?: string; + }) & (components["schemas"]["Cat"] | components["schemas"]["Dog"] | components["schemas"]["Rabbit"] | components["schemas"]["Snake"] | components["schemas"]["Turtle"]); +``` + +::: + +#### ✅ Better + +::: code-group + +```yaml [my-openapi-3-schema.yaml] +Pet: + oneOf: + - $ref: "#/components/schemas/Cat" + - $ref: "#/components/schemas/Dog" + - $ref: "#/components/schemas/Rabbit" + - $ref: "#/components/schemas/Snake" + - $ref: "#/components/schemas/Turtle" +PetCommonProperties: + type: object + properties: + name: + type: string +Cat: + allOf: + - "$ref": "#/components/schemas/PetCommonProperties" + type: + type: string + enum: + - cat +``` + +::: + +生成された型は単純化されるだけでなく、TypeScriptが `type` を使用して区別できるようになります(`Cat` には `type` として単一の列挙値 `"cat"` が指定されています)。 + +::: code-group + +```ts [my-openapi-3-schema.d.ts] +Pet: components["schemas"]["Cat"] | components["schemas"]["Dog"] | components["schemas"]["Rabbit"] | components["schemas"]["Snake"] | components["schemas"]["Turtle"]; +Cat: { type?: "cat"; } & components["schemas"]["PetCommonProperties"]; +``` + +::: + +_注: 任意で、`Pet` に `discriminator.propertyName: "type"` を指定することもできます([ドキュメント](https://spec.openapis.org/oas/v3.1.0#discriminator-object))。これにより、自動的に `type` キーが生成されますが、明示性が低くなります。_ + +スキーマでは任意の方法でコンポジションを使用することが許可されていますが、生成された型を確認し、ユニオンやインターセクションをより簡潔に表現できる方法がないか検討することは重要です。 `oneOf` の使用を制限することが唯一の方法ではありませんが、しばしば最大の効果をもたらします。 + +## JSONSchema $defs の注意点 + +[JSONSchema $defs](https://json-schema.org/understanding-json-schema/structuring.html#defs) はサブスキーマの定義をどこにでも提供するために使用できます。ただし、これらが常にTypeScriptにスムーズに変換されるとは限りません。例えば、次のような場合は動作します: + +::: code-group + +```yaml [my-openapi-3-schema.yaml] +components: + schemas: + DefType: + type: object # ✅ `type: "object"` の場合、$defs を定義するのは問題ありません。 + $defs: + myDefType: + type: string + MyType: + type: object + properties: + myType: + $ref: "#/components/schemas/DefType/$defs/myDefType" +``` + +::: + +これは次のようなTypeScriptに変換されます: + +::: code-group + +```ts [my-openapi-3-schema.d.ts] +export interface components { + schemas: { + DefType: { + $defs: { + myDefType: string; + }; + }; + MyType: { + myType?: components["schemas"]["DefType"]["$defs"]["myDefType"]; // ✅ 正常に動作します + }; + }; +} +``` + +::: + +しかし、これは動作しません: + +::: code-group + +```yaml [my-openapi-3-schema.yaml] +components: + schemas: + DefType: + type: string # ❌ これは $defs を保持しません。 + $defs: + myDefType: + type: string + MyType: + properties: + myType: + $ref: "#/components/schemas/DefType/$defs/myDefType" +``` + +::: + +なぜなら、次のように変換されるからです: + +::: code-group + +```ts [my-openapi-3-schema.d.ts] +export interface components { + schemas: { + DefType: string; + MyType: { + myType?: components["schemas"]["DefType"]["$defs"]["myDefType"]; // ❌ プロパティ '$defs' は型 'String' に存在しません。 + }; + }; +} +``` + +::: + +そのため、$defs を定義する場所には注意が必要です。最終的に生成される型から $defs が消えてしまう可能性があります。 + +::: tip + +不安な場合は、$defs をルートスキーマレベルで定義するのが安全です。 + +::: From 013c9d42d7a8904eb57a3bf37e9e915013861469 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Wed, 14 Aug 2024 11:06:54 +0900 Subject: [PATCH 03/24] docs(ja): openapi-typescript, cli --- docs/ja/cli.md | 207 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 docs/ja/cli.md diff --git a/docs/ja/cli.md b/docs/ja/cli.md new file mode 100644 index 000000000..f663a0c68 --- /dev/null +++ b/docs/ja/cli.md @@ -0,0 +1,207 @@ +--- +title: openapi-typescript CLI +description: 最も簡単かつ迅速に型を生成する方法 +--- + +# CLI + +CLI は、openapi-typescript を使用する最も一般的な方法です。CLI は JSON および YAML を解析でき、[Redocly CLI](https://redocly.com/docs/cli/commands/lint/) を使用してスキーマを検証することもできます。ローカルおよびリモートのスキーマを解析可能です(基本認証もサポートしています)。 + +## OpenAPI スキーマを TypeScript に変換する + +### 単一スキーマ + +スキーマを変換する最も簡単な方法は、入力スキーマ(JSON または YAML)を指定し、`--output`(`-o`)で出力先を指定することです: + +```bash +npx openapi-typescript schema.yaml -o schema.ts + +# 🚀 schema.yaml -> schema.ts [50ms] +``` + +```bash +npx openapi-typescript https://petstore3.swagger.io/api/v3/openapi.yaml -o petstore.d.ts + +# 🚀 https://petstore3.swagger.io/api/v3/openapi.yaml -> petstore.d.ts [250ms] +``` + +### 複数のスキーマ + +複数のスキーマを変換するには、プロジェクトのルートディレクトリに `redocly.yaml` ファイルを作成し、[APIs を定義します](https://redocly.com/docs/cli/configuration/)。`apis` の下に、それぞれのスキーマに一意の名前とオプションのバージョンを指定します(名前は一意であれば問題ありません)。`root` 値をスキーマのエントリーポイントとして設定し、これが主な入力として機能します。出力には、`x-openapi-ts.output` を設定します: + +::: code-group + +```yaml [my-openapi-3-schema.yaml] +apis: + core@v2: + root: ./openapi/openapi.yaml + x-openapi-ts: + output: ./openapi/openapi.ts + external@v1: + root: ./openapi/external.yaml + x-openapi-ts: + output: ./openapi/external.ts +``` + +::: + +::: tip + +これにより、スキーマの 1:1 入力:出力が保持されます。複数のスキーマを1つにまとめるには、Redocly の [bundle コマンド](https://redocly.com/docs/resources/multi-file-definitions/#bundle)を使用してください。 + +::: + +プロジェクト内に `apis` を含む `redocly.yaml` ファイルがあれば、CLI で入力/出力パラメータを省略できます: + +```bash +npx openapi-typescript +``` + +::: warning + +以前のバージョンではワイルドカードがサポートされていましたが、v7 では廃止され、代わりに `redocly.yaml` が使用されるようになりました。これにより、各スキーマの出力先をより詳細に制御でき、各スキーマに固有の設定を適用することができます。 + +::: + +## Redocly config + +openapi-typescript を使用するには `redocly.yaml` ファイルは必須ではありません。デフォルトでは、組み込みの `"minimal"` 設定を拡張します。ただし、カスタム検証ルールや[複数のスキーマ](#複数のスキーマ)の型を構築したい場合には使用をお勧めします。CLI はプロジェクトのルートディレクトリで `redocly.yaml` を自動的に見つけようとしますが、`--redoc` フラグを使用してその場所を指定することもできます: + +```bash +npx openapi-typescript --redocly ./path/to/redocly.yaml +``` + +Redoclyの設定オプションについての詳細は [Redoclyのドキュメント](https://redocly.com/docs/cli/configuration/)をご覧ください。 + +## 認証 + +非公開スキーマの認証は、[Redocly config](https://redocly.com/docs/cli/configuration/#resolve-non-public-or-non-remote-urls)で処理します。次のようにヘッダーや基本認証を追加できます: + +::: code-group + +```yaml [my-openap-3-schema.yaml] +resolve: + http: + headers: + - matches: https://api.example.com/v2/** + name: X-API-KEY + envVariable: SECRET_KEY + - matches: https://example.com/*/test.yaml + name: Authorization + envVariable: SECRET_AUTH +``` + +::: + +その他のオプションについては、[Redocly ドキュメント](https://redocly.com/docs/cli/configuration/#resolve-non-public-or-non-remote-urls)をご参照ください。 + +## フラグ + +CLI は以下のフラグをサポートしています: + +| フラグ | エイリアス | デフォルト | 説明 | +| :--------------------------------- | :--------- | :--------: | :------------------------------------------------------------------------------------------------------- | +| `--help` | | | インラインヘルプメッセージを表示し終了します | +| `--version` | | | このライブラリのバージョンを表示し終了します | +| `--output [location]` | `-o` | (stdout) | 出力ファイルを保存する場所を指定します | +| `--redocly [location]` | | | `redocly.yaml` ファイルへのパスを指定します (詳細は [複数スキーマ](#複数のスキーマ) を参照) | +| `--additional-properties` | | `false` | `additionalProperties: false` がないすべてのスキーマオブジェクトに任意のプロパティを許可します | +| `--alphabetize` | | `false` | 型をアルファベット順にソートします | +| `--array-length` | | `false` | 配列の `minItems` / `maxItems` を使用してタプルを生成します | +| `--default-non-nullable` | | `true` | デフォルト値を持つスキーマオブジェクトを、パラメータを除き、非null型として扱います | +| `--properties-required-by-default` | | `false` | `required` がないスキーマオブジェクトを、すべてのプロパティが必須であるかのように扱います | +| `--empty-objects-unknown` | | `false` | 指定されたプロパティも `additionalProperties` もないスキーマオブジェクトに任意のプロパティを許可します | +| `--enum` | | `false` | 文字列の共用体ではなく、[TS enums](https://www.typescriptlang.org/docs/handbook/enums.html) を生成します | +| `--enum-values` | | `false` | enumの値を配列としてエクスポートします | +| `--dedupe-enums` | | `false` | `--enum=true` が設定されている場合、enumの重複を排除します | +| `--check` | | `false` | 生成された型が最新であることを確認します | +| `--exclude-deprecated` | | `false` | 型から廃止されたフィールドを除外します | +| `--export-type` | `-t` | `false` | `interface` の代わりに `type` をエクスポートします | +| `--immutable` | | `false` | 不変の型(readonlyプロパティおよびreadonly配列)を生成します | +| `--path-params-as-types` | | `false` | `paths` オブジェクトで動的な文字列の参照を許可します | + +### pathParamsAsTypes + +デフォルトでは、URL はスキーマに記載された通りに保持されます: + +::: code-group + +```ts [my-openapi-3-schema.d.ts] +export interface paths { + "/user/{user_id}": components["schemas"]["User"]; +} +``` + +::: + +つまり、型の参照も正確な URL に一致する必要があります。 + +::: code-group + +```ts [src/my-project.ts] +import type { paths } from "./my-openapi-3-schema"; + +const url = `/user/${id}`; +type UserResponses = paths["/user/{user_id}"]["responses"]; +``` + +::: + +しかし、`--path-params-as-types` オプションを有効にすると、次のように動的な参照を利用することができます。 + +::: code-group + +```ts [src/my-project.ts] +import type { paths } from "./my-openapi-3-schema"; + +const url = `/user/${id}`; +type UserResponses = paths[url]["responses"]; // 自動的に `paths['/user/{user_id}']` に一致します +``` + +::: + +これは人為的な例ですが、この機能を使用して、フェッチクライアントやアプリケーション内の他の便利な場所で、URLに基づいて型を自動的に推論することができます。 + +_ありがとう, [@Powell-v2](https://github.com/Powell-v2)!_ + +### arrayLength + +このオプションは、配列タイプが `minItems` または `maxItems` を指定している場合にタプルを生成するのに便利です。 + +例えば、以下のスキーマが与えられた場合: + +::: code-group + +```yaml [my-openapi-3-schema.yaml] +components: + schemas: + TupleType + type: array + items: + type: string + minItems: 1 + maxItems: 2 +``` + +::: + +`--array-length` を有効にすると、型が次のように変更されます: + +::: code-group + +```ts [my-openapi-3-schema.d.ts] +export interface components { + schemas: { + TupleType: string[]; // [!code --] + TupleType: [string] | [string, string]; // [!code ++] + }; +} +``` + +::: + +これにより、配列の長さに対するより明示的な型チェックが可能になります。 + +_注: この機能には適切な制限があります。例えば `maxItems: 100` の場合は、単純に `string[];` に戻ります。_ + +_ありがとう, [@kgtkr](https://github.com/kgtkr)!_ From fbcaec351896b0878df66071d9bd38dbab785bec Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Wed, 14 Aug 2024 12:31:38 +0900 Subject: [PATCH 04/24] docs(ja): openapi-typescript, examples --- docs/ja/examples.md | 238 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 docs/ja/examples.md diff --git a/docs/ja/examples.md b/docs/ja/examples.md new file mode 100644 index 000000000..ebf6e51a3 --- /dev/null +++ b/docs/ja/examples.md @@ -0,0 +1,238 @@ +--- +title: 使用例 +description: openapi-typescriptを実際のアプリケーションで使用する例 +--- + +# 使用例 + +openapi-typescriptで生成された型は汎用性が高く、さまざまな方法で利用できます。これらの例は包括的なものではありませんが、アプリケーションでの使用方法についてのアイデアを刺激することを期待しています。 + +## データフェッチ + +データを取得する際には、**自動的に型付けされたfetchラッパー**を使用すると、簡単かつ安全に行えます: + +- [openapi-fetch](/ja/openapi-fetch/) (推奨) +- [openapi-typescript-fetch](https://www.npmjs.com/package/openapi-typescript-fetch) by [@ajaishankar](https://github.com/ajaishankar) + +::: tip + +良いfetchラッパーは**ジェネリクスの使用は避ける**べきです。ジェネリクスは多くのタイプ指定が必要で、エラーを隠してしまう可能性があります! + +::: + +## Hono + +[Hono](https://hono.dev/)は、Node.js用のモダンなサーバーフレームワークで、エッジ環境(例:[Cloudflare Workers](https://developers.cloudflare.com/workers/))や標準コンテナに簡単にデプロイできます。また、TypeScriptが組み込まれており、生成された型と非常に相性が良いです。 + +[CLIを使用して型を生成](/ja/introduction)した後、各エンドポイントに適切な `paths` レスポンスを渡します: + +::: code-group + +```ts [src/my-project.ts] +import { Hono } from "hono"; +import { components, paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成 + +const app = new Hono(); + +/** /users */ +app.get("/users", async (ctx) => { + try { + const users = db.get("SELECT * from users"); + return ctx.json< + paths["/users"]["responses"][200]["content"]["application/json"] + >(users); + } catch (err) { + return ctx.json({ + status: 500, + message: err ?? "エラーが発生しました", + }); + } +}); + +export default app; +``` + +::: tip + +サーバー環境ではデータベースクエリや他のエンドポイントとのやり取りがあり、TypeScriptが検査できない部分があるため型チェックが難しくなり得ます。しかし、ジェネリクスを使用することで、TypeScriptがキャッチできる明らかなエラーについて警告を受けることができるようになります(そして、スタック内の多くのものが型を持っていることに気付くかもしれません!)。 + +::: + +## Mock-Service-Worker (MSW) + +[Mock Service Worker (MSW)](https://mswjs.io) を使用してAPIモックを定義している場合、**小さくて自動的に型付けされたラッパー**をMSWと合わせて使用することで、OpenAPI仕様が変更された際にAPIモックのコンフリクトを簡単に解決できます。最終的には、アプリケーションのAPIクライアントとAPIモックの**両方**に同じレベルの信頼を持つことができます。 + +`openapi-typescript` と `openapi-fetch` のようなfetchラッパーを使用することで、アプリケーションのAPIクライアントがOpenAPI仕様とコンフリクトしないように保証できます。 + +しかし、APIクライアントの問題を簡単に解決できる一方で、コンフリクトについて警告するメカニズムがないため、APIモックを"手動で"調整する必要があります。 + +以下のラッパーは、`openapi-typescript` と完璧に連携しますのでお勧めします: + +- [openapi-msw](https://www.npmjs.com/package/openapi-msw) by [@christoph-fricke](https://github.com/christoph-fricke) + +## テスト用モック + +最も一般的なテストの誤検知の原因の一つは、モックが実際のAPIレスポンスと一致していない場合です。 + +`openapi-typescript` は、最小限の労力でこれを防ぐための素晴らしい方法を提供します。以下に、OpenAPIスキーマに一致するようにすべてのモックを型チェックするためのヘルパー関数を書く一例を示します(ここでは[vitest](https://vitest.dev/)や[vitest-fetch-mock](https://www.npmjs.com/package/vitest-fetch-mock)を使用しますが、同じ原則が他の設定にも適用できます): + +次のようなオブジェクト構造でモックを定義し、一度に複数のエンドポイントをモックすることを考えてみましょう: + +```ts +{ + [pathname]: { + [HTTP method]: { status: [status], body: { …[何らかのモックデータ] } }; + } +} +``` + +生成された型を使用して、指定されたパス + HTTPメソッド + ステータスコードに対して正しいデータ形状を推論できます。テストの例は以下のようになります: + +::: code-group + +```ts [my-test.test.ts] +import { mockResponses } from "../test/utils"; + +describe("My API test", () => { + it("mocks correctly", async () => { + mockResponses({ + "/users/{user_id}": { + // ✅ 正常な 200 レスポンス + get: { status: 200, body: { id: "user-id", name: "User Name" } }, + // ✅ 正常な 403 レスポンス + delete: { status: 403, body: { code: "403", message: "Unauthorized" } }, + }, + "/users": { + // ✅ 正常な 201 レスポンス + put: { 201: { status: "success" } }, + }, + }); + + // テスト 1: GET /users/{user_id}: 200 + await fetch("/users/user-123"); + + // テスト 2: DELETE /users/{user_id}: 403 + await fetch("/users/user-123", { method: "DELETE" }); + + // テスト 3: PUT /users: 200 + await fetch("/users", { + method: "PUT", + body: JSON.stringify({ id: "new-user", name: "New User" }), + }); + + // テストをクリーンアップ + fetchMock.resetMocks(); + }); +}); +``` + +::: + +_注: この例では、標準の `fetch()` 関数を使用していますが、[openapi-fetch](/ja/openapi-fetch/) を含む他の fetch ラッパーも、何の変更も加えずに代わりに使用できます。_ + +以下のコードは、`test/utils.ts` ファイルに記述し、必要に応じてプロジェクトにコピー&ペーストして使用することができます(シンプルさを保つために隠しています)。 + +
+📄 test/utils.ts + +::: code-group + +```ts [test/utils.ts] +import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typescript + +// 設定 +// ⚠️ 重要: ここを変更してください!これはすべてのURLにプレフィックスを追加します +const BASE_URL = "https://myapi.com/v1"; +// 設定終了 + +// 型ヘルパー — これらはTSルックアップを改善するためのものです。無視しても構いません +type FilterKeys = { + [K in keyof Obj]: K extends Matchers ? Obj[K] : never; +}[keyof Obj]; +type PathResponses = T extends { responses: any } ? T["responses"] : unknown; +type OperationContent = T extends { content: any } ? T["content"] : unknown; +type MediaType = `${string}/${string}`; +type MockedResponse = + FilterKeys, MediaType> extends never + ? { status: Status; body?: never } + : { + status: Status; + body: FilterKeys, MediaType>; + }; + +/** + * fetch()呼び出しをモックし、OpenAPIスキーマに基づいて型を指定します + */ +export function mockResponses(responses: { + [Path in keyof Partial]: { + [Method in keyof Partial]: MockedResponse< + PathResponses + >; + }; +}) { + fetchMock.mockResponse((req) => { + const mockedPath = findPath( + req.url.replace(BASE_URL, ""), + Object.keys(responses) + )!; + // 注意: ここでの型は省略されており、この関数は`void`を返すシグネチャを持っています。重要なのはパラメータのシグネチャです。 + if (!mockedPath || (!responses as any)[mockedPath]) + throw new Error(`No mocked response for ${req.url}`); // モックされていない応答の場合はエラーをスローします(必要に応じて動作を変更してください) + const method = req.method.toLowerCase(); + if (!(responses as any)[mockedPath][method]) + throw new Error(`${req.method} called but not mocked on ${mockedPath}`); // 同様に、他の部分がモックされていない場合もエラーをスローします + if (!(responses as any)[mockedPath][method]) { + throw new Error(`${req.method} called but not mocked on ${mockedPath}`); + } + const { status, body } = (responses as any)[mockedPath][method]; + return { status, body: JSON.stringify(body) }; + }); +} + +// 現実的なURL(/users/123)をOpenAPIパス(/users/{user_id})にマッチさせるヘルパー関数 +export function findPath( + actual: string, + testPaths: string[] +): string | undefined { + const url = new URL( + actual, + actual.startsWith("http") ? undefined : "http://testapi.com" + ); + const actualParts = url.pathname.split("/"); + for (const p of testPaths) { + let matched = true; + const testParts = p.split("/"); + if (actualParts.length !== testParts.length) continue; // 長さが異なる場合は自動的に一致しない + for (let i = 0; i < testParts.length; i++) { + if (testParts[i]!.startsWith("{")) continue; // パスパラメータ({user_id})は常に一致とみなされる + if (actualParts[i] !== testParts[i]) { + matched = false; + break; + } + } + if (matched) return p; + } +} +``` + +::: + +::: info 追加の説明 + +このコードはかなり複雑です! 大部分は詳細な実装なので無視しても構いません。重要な仕掛けが行われているのは、`mockResponses(…)` 関数のシグネチャです。ここには、この構造と私たちの設計との直接的なリンクがあることに気づくでしょう。その後、残りのコードは、ランタイムが期待通りに動作するように調整するためのものです。 + +::: + +```ts +export function mockResponses(responses: { + [Path in keyof Partial]: { + [Method in keyof Partial]: MockedResponse< + PathResponses + >; + }; +}); +``` + +
+ +これで、スキーマが更新されるたびに、**すべてのモックデータが正しく型チェックされる**ようになります 🎉。これは、堅牢で正確なテストを確保するための大きな一歩です。 From 18fd6a32630c4be28739269f6c226264b64a5e31 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Wed, 14 Aug 2024 12:42:59 +0900 Subject: [PATCH 05/24] docs(ja): openapi-typescript, index --- docs/ja/index.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 docs/ja/index.md diff --git a/docs/ja/index.md b/docs/ja/index.md new file mode 100644 index 000000000..d71afd47a --- /dev/null +++ b/docs/ja/index.md @@ -0,0 +1,53 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: "OpenAPI TypeScript" + tagline: "OpenAPI 3.0/3.1 スキーマを TypeScriptの型に変換し、型安全なフェッチングを可能にします。" + actions: + - theme: brand + text: "始める" + link: /ja/introduction + - theme: alt + text: "GitHubで見る" + link: https://github.com/openapi-ts/openapi-typescript + +features: + - title: "超高速" + details: "静的な TypeScript 型は、実行時に影響を与えず、クライアントの負担もありません。" + - title: "型安全" + details: "OpenAPI スキーマを使用して、セットアップやテストなしでコード全体を型チェックします。" + - title: "どこでも実行可能" + details: "TypeScript が実行できる場所ならどこでも使用可能。どのスタックやフレームワークでも動作します。" +--- + +
+ +### 利用者 + +
    +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
+ +
+ +
+ +### スポンサー + +
+ +
+ +[OpenCollective](https://opencollective.com/openapi-ts) でスポンサーになり、このプロジェクトを支援しましょう! + + + +
From 97dc0838feadd156f22b7a6cafac3e5704e54e85 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Wed, 14 Aug 2024 12:45:28 +0900 Subject: [PATCH 06/24] docs: fix invalid url --- docs/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/introduction.md b/docs/introduction.md index 09081941e..cff0f2ac2 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -7,7 +7,7 @@ description: Quickstart openapi-typescript turns [OpenAPI 3.0 & 3.1](https://spec.openapis.org/oas/latest.html) schemas into TypeScript quickly using Node.js. No Java/node-gyp/running OpenAPI servers necessary. -The code is [MIT-licensed](https://github.com/openapi-ts/openapi-typescript/blob/main/packages/openapi-typescript/LICENSE") and free for use. +The code is [MIT-licensed](https://github.com/openapi-ts/openapi-typescript/blob/main/packages/openapi-typescript/LICENSE) and free for use. ::: tip From 6bc7c6968c8a9abc0a55d6886c84f687d410ae55 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Wed, 14 Aug 2024 13:01:22 +0900 Subject: [PATCH 07/24] docs(ja): openapi-typescript, introduction --- docs/ja/introduction.md | 112 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 docs/ja/introduction.md diff --git a/docs/ja/introduction.md b/docs/ja/introduction.md new file mode 100644 index 000000000..d14c02d13 --- /dev/null +++ b/docs/ja/introduction.md @@ -0,0 +1,112 @@ +--- +title: openapi-typescript +description: クイックスタート +--- + +openapi-typescript + +openapi-typescriptは、[OpenAPI 3.0 & 3.1](https://spec.openapis.org/oas/latest.html) スキーマをNode.jsを使用して素早くTypeScriptに変換します。Java/node-gyp/OpenAPIサーバーの実行は不要です。 + +このコードは[MITライセンス](https://github.com/openapi-ts/openapi-typescript/blob/main/packages/openapi-typescript/LICENSE)で保護されており、無料で利用可能です。 + +::: tip + +OpenAPI初心者ですか?Speakeasyの [Intro to OpenAPI](https://www.speakeasyapi.dev/openapi) は、初心者にも分かりやすいガイドで、OpenAPIの「なぜ」と「どのように」を説明しています。 + +::: + +## 特徴 + +- ✅ OpenAPI 3.0および3.1をサポート([discriminators](https://spec.openapis.org/oas/v3.1.0#discriminator-object)のような高度な機能を含む) +- ✅ 従来のコード生成より優れている**ランタイムなしの型**を生成 +- ✅ YAMLまたはJSONから、ローカルまたはリモートでスキーマを読み込む +- ✅ 巨大なスキーマであってもミリ秒単位で型を生成 + +_注: OpenAPI 2.xはバージョン `5.x` およびそれ以前でサポートされています_ + +## 使用例 + +👀 [使用例を見る](https://github.com/openapi-ts/openapi-typescript/blob/main/packages/openapi-typescript/examples/) + +## セットアップ + +このライブラリを使用するには、最新バージョンの [Node.js](https://nodejs.org) がインストールされている必要があります(20.x以上を推奨)。インストールしたら、以下のコマンドをプロジェクトで実行してください: + +```bash +npm i -D openapi-typescript typescript +``` + +次に、`tsconfig.json` ファイルに以下を追加して、型を正しく読み込めるようにします: + +::: code-group + +```json [tsconfig.json] +{ + "compilerOptions": { + "module": "ESNext", // または "NodeNext" // [!code ++] + "moduleResolution": "Bundler" // または "NodeNext" // [!code ++] + } +} +``` + +::: + +::: tip 強く推奨 + +さらに、以下の設定を追加すると型の安全性が向上します: + +::: code-group + +```json [tsconfig.json] +{ + "compilerOptions": { + "noUncheckedIndexedAccess": true // [!code ++] + } +} +``` + +::: + +## 基本的な使い方 + +まず、`npx openapi-typescript` を実行してローカルの型ファイルを生成します。最初に入力スキーマ(JSON または YAML)を指定し、保存する場所を `--output` (`-o`)で指定します: + +```bash +# ローカルスキーマ +npx openapi-typescript ./path/to/my/schema.yaml -o ./path/to/my/schema.d.ts +# 🚀 ./path/to/my/schema.yaml -> ./path/to/my/schema.d.ts [7ms] + +# リモートスキーマ +npx openapi-typescript https://myapi.dev/api/v1/openapi.yaml -o ./path/to/my/schema.d.ts +# 🚀 https://myapi.dev/api/v1/openapi.yaml -> ./path/to/my/schema.d.ts [250ms] +``` + +次に、TypeScript プロジェクトで必要に応じて型をインポートします: + +::: code-group + +```ts [src/my-project.ts] +import type { paths, components } from "./my-openapi-3-schema"; // openapi-typescript によって生成 + +// スキーマオブジェクト +type MyType = components["schemas"]["MyType"]; + +// パスパラメータ +type EndpointParams = paths["/my/endpoint"]["parameters"]; + +// レスポンスオブジェクト +type SuccessResponse = + paths["/my/endpoint"]["get"]["responses"][200]["content"]["application/json"]["schema"]; +type ErrorResponse = + paths["/my/endpoint"]["get"]["responses"][500]["content"]["application/json"]["schema"]; +``` + +::: + +ここから、これらの型を以下の用途(ただし、これに限定されません)で使用できます: + +- OpenAPI対応のfetchクライアント(例:[openapi-fetch](/ja/openapi-fetch/))を使用 +- 他のAPIリクエストボディやレスポンスの型のアサート +- API型に基づいたコアビジネスロジックの構築 +- モックテストデータが現在のスキーマと一致していることを確認 +- 任意のnpmパッケージ(クライアントSDKなど)にAPI型をパッケージ化する From 8a8626e9ff230c8d84ee5e2392fdb98f403f6b12 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Wed, 14 Aug 2024 13:37:23 +0900 Subject: [PATCH 08/24] docs(ja): openapi-typescript, migration-guide --- docs/ja/migration-guide.md | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 docs/ja/migration-guide.md diff --git a/docs/ja/migration-guide.md b/docs/ja/migration-guide.md new file mode 100644 index 000000000..b12cc9e05 --- /dev/null +++ b/docs/ja/migration-guide.md @@ -0,0 +1,56 @@ +--- +title: マイグレーションガイド +description: openapi-typescript のバージョン間の移行 +--- + +# 7.x への移行 + +7.x リリースには、注意すべきいくつかの軽微な破壊的変更があります: + +### 認証 / リモートスキーマの取得 + +7.x では、すべてのリモートスキーマの取得が [Redocly CLI](https://redocly.com/docs/developer-portal/guides/reference-docs-integration-advanced/#authentication) によって処理されます。これにより、認証設定を `redocly.config.yml` 設定ファイルに[移行](https://redocly.com/docs/developer-portal/guides/reference-docs-integration-advanced/#authentication)する必要があります([ドキュメント](https://redocly.com/docs/developer-portal/guides/reference-docs-integration-advanced/#authentication)を参照)。 + +### TypeScript AST + +7.x では、単純な文字列変換の代わりに TypeScript AST が導入されました。これにより、Node.js のコア API が TypeScript AST を返すようになり、`transform()` および `postTransform()` オプションも影響を受けます。[Node.js API のドキュメントが、関連する例と共に更新されています](./node)。 + +### defaultNonNullable: デフォルトで true + +CLI および Node.js API では、`--default-non-nullable` の動作がデフォルトで有効になりました。これにより、スキーマオブジェクトに `default` 値がある場合、それは `required` として扱われます(パラメータを除く)。 + +### Redocly 設定ファイルによるグロビングの置き換え + +7.x では複数のスキーマを一度に生成することができますが、特定の命名スキーマに従うことを強制するグロビングの代わりに、`redocly.config.yaml` ファイルを宣言して、各入力スキーマとその関連する生成された型の保存場所を指定します。これにより、複数のスキーマの命名と整理に柔軟性が生まれます。 + +便利なことに、`redocly.config.yml` ファイルを宣言しておけば、引数なしで CLI コマンドを実行できます([ドキュメント](./cli#redoc-config)参照): + +```sh +npx openapi-typescript +``` + +### Node.js API のinputの型 + +7.x ではinputの型が調整され、より予測可能で汎用的になりました。 + +```ts +import openapiTS from "openapi-typescript"; + +await openapiTS(input); +``` + +| Input | 6.x | 7.x | +| :------------ | :-------------: | :------: | +| JSON (object) | `Object` | `Object` | +| JSON (string) | (未サポート) | `string` | +| YAML (string) | (未サポート) | `string` | +| Local file | `string \| URL` | `URL` | +| Remote file | `string \| URL` | `URL` | + +最大の変更点は `string` の扱いです。6.x では、string はローカルまたはリモートのファイルパスを指す可能性がありましたが、これは予測不可能でした。というのも、ローカルファイルパスの場合、Node が呼び出された場所に依存していたからです。7.x では、**すべてのファイルパスは [URL](https://nodejs.org/api/url.html) である必要があります**(ローカルパスの場合、`new URL('./path/to/my/schema', import.meta.url)` または `new URL('file:///absolute/path/to/my/schema')` を使用)。これにより、 `string` タイプがインライン YAML(または JSON)を扱えるようになりました(6.x ではサポートされていませんでした)。 + +[詳細は更新されたドキュメントを参照](./node#usage)。 + +--- + +[完全な変更履歴はこちら](https://github.com/openapi-ts/openapi-typescript/blob/6.x/packages/openapi-typescript/CHANGELOG.md) From 36245c6b9380548b9df87bc1ba9d1aa1289e2b33 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Wed, 14 Aug 2024 14:16:36 +0900 Subject: [PATCH 09/24] docs(ja): openapi-typescript, node --- docs/ja/node.md | 263 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 docs/ja/node.md diff --git a/docs/ja/node.md b/docs/ja/node.md new file mode 100644 index 000000000..19a023a37 --- /dev/null +++ b/docs/ja/node.md @@ -0,0 +1,263 @@ +--- +title: openapi-typescript Node.js API +description: プログラムでの使用と無限の柔軟性。 +--- + +# Node.js API + +Node APIは、動的に生成されたスキーマを扱う場合や、より大きなアプリケーションのコンテキスト内で使用する場合に役立ちます。メモリからスキーマをロードするためにJSONフレンドリーなオブジェクトを渡すか、ローカルファイルやリモートURLからスキーマをロードするために文字列を渡します。 + +## セットアップ + +```bash +npm i --save-dev openapi-typescript typescript +``` + +::: tip 推奨 + +最適な体験を得るために、 `"type": "module"` を `package.json` に追加して Node ESM を使用してください([ドキュメント](https://nodejs.org/api/esm.html#enabling)) + +::: + +## 使用方法 + +Node.js APIは、`URL`、`string`、またはJSONオブジェクトを入力として受け付けます: + +| Type | Description | Example | +| :------: | :--------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------- | +| `URL` | ローカルまたはリモートファイルを読み取る | `await openapiTS(new URL('./schema.yaml', import.meta.url))`
`await openapiTS(new URL('https://myapi.com/v1/openapi.yaml'))` | +| `string` | 動的なYAMLまたはJSONを読み取る | `await openapiTS('openapi: "3.1" … ')` | +| `JSON` | 動的なJSONを読み取る | `await openapiTS({ openapi: '3.1', … })` | + +また、 `Readable` ストリームや`Buffer` 型も受け付け、これらは文字列として解決されます(ドキュメント全体が必要でないと検証、バンドル、型生成ができません)。 + +Node APIはTypeScript ASTを返す `Promise` を返します。その後、必要に応じてASTをトラバース、操作、または修正できます。 + +TypeScript ASTを文字列に変換するには、[TypeScriptのプリンターのラッパー](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#re-printing-sections-of-a-typescript-file)である `astToString()` ヘルパーを使用できます: + +::: code-group + +```ts [src/my-project.ts] +import fs from "node:fs"; +import openapiTS, { astToString } from "openapi-typescript"; + +const ast = await openapiTS(new URL("./my-schema.yaml", import.meta.url)); +const contents = astToString(ast); + +// (任意)ファイルに書き込み +fs.writeFileSync("./my-schema.ts", contents); +``` + +::: + +### Redoc config + +Redoc configはopenapi-typescriptを使用するために必須ではありません。デフォルトでは `"minimal"` ビルトイン設定を拡張しますが、デフォルト設定を変更したい場合は、完全に初期化されたRedoc configをNode APIに提供する必要があります。これを行うには、`@redocly/openapi-core` のヘルパーを使用できます: + +::: code-group + +```ts [src/my-project.ts] +import { createConfig, loadConfig } from "@redocly/openapi-core"; +import openapiTS from "openapi-typescript"; + +// オプション1:メモリ内で設定を作成 +const redocly = await createConfig( + { + apis: { + "core@v2": { … }, + "external@v1": { … }, + }, + }, + { extends: ["recommended"] }, +); + +// オプション2:redocly.yamlファイルから読み込み +const redocly = await loadConfig({ configPath: "redocly.yaml" }); + +const ast = await openapiTS(mySchema, { redocly }); +``` + +::: + +## Options + +Node APIは、 `camelCase` 形式で[CLI フラグ](./cli#options) すべてをサポートしており、以下の追加オプションも利用可能です: + +| 名前 | タイプ | デフォルト | Description | +| :-------------- | :-------------: | :-------------: | :--------------------------------------------------------------------------------------- | +| `transform` | `Function` | | Override the default Schema Object ➝ TypeScript transformer in certain scenarios | +| `postTransform` | `Function` | | `transform` と同じだが、TypeScript変換後に実行される | +| `silent` | `boolean` | `false` | 警告メッセージを非表示にする(致命的なエラーは表示されます) | +| `cwd` | `string \| URL` | `process.cwd()` | (オプション)必要に応じてリモート$refの解決を支援するために現在の作業ディレクトリを指定 | +| `inject` | `string` | | ファイルの先頭に任意のTypeScript型を注入 | + +### transform / postTransform + +`transform()` と `postTransform()` オプションを使用して、デフォルトのスキーマオブジェクト変換を独自のものに上書きできます。これは、スキーマの特定の部分に対して非標準的な変更を提供する場合に役立ちます。 + +- `transform()` はTypeScriptへの **変換前** に実行されます(OpenAPIノードを扱います) +- `postTransform()` はTypeScriptへの **変換後** に実行されます(TypeScript ASTを扱います) + +#### 例: `Date` 型 + +例えば、スキーマに次のプロパティが含まれているとします: + +```yaml +properties: + updated_at: + type: string + format: date-time +``` + +デフォルトでは、openapiTSは`updated_at?: string;`を生成します。これは、`"date-time"`がどのフォーマットを意味するのかが明確でないためです(フォーマットは標準化されておらず、任意の形式にできるため)。しかし、独自のカスタムフォーマッタを提供することで、これを改善できます。例えば次のようにします: + +::: code-group + +```ts [src/my-project.ts] +import openapiTS from "openapi-typescript"; +import ts from "typescript"; + +const DATE = ts.factory.createTypeReferenceNode( + ts.factory.createIdentifier("Date") +); // `Date` +const NULL = ts.factory.createLiteralTypeNode(ts.factory.createNull()); // `null` + +const ast = await openapiTS(mySchema, { + transform(schemaObject, metadata) { + if (schemaObject.format === "date-time") { + return schemaObject.nullable + ? ts.factory.createUnionTypeNode([DATE, NULL]) + : DATE; + } + }, +}); +``` + +::: + +その結果、以下のようになります: + +::: code-group + +```yaml [my-openapi-3-schema.yaml] +updated_at?: string; // [!code --] +updated_at: Date | null; // [!code ++] +``` + +::: + +#### 例: `Blob` 型 + +もう一つの一般的な変換は、リクエストの `body` が `multipart/form-data` で、いくつかの `Blob` フィールドを持つファイルアップロードの場合です。例えば次のようなスキーマがあります + +::: code-group + +```yaml [my-openapi-3-schema.yaml] +Body_file_upload: + type: object; + properties: + file: + type: string; + format: binary; +``` + +::: + +同じパターンを使用して型を変換します: + +::: code-group + +```ts [src/my-project.ts] +import openapiTS from "openapi-typescript"; +import ts from "typescript"; + +const BLOB = ts.factory.createTypeReferenceNode( + ts.factory.createIdentifier("Blob") +); // `Blob` +const NULL = ts.factory.createLiteralTypeNode(ts.factory.createNull()); // `null` + +const ast = await openapiTS(mySchema, { + transform(schemaObject, metadata) { + if (schemaObject.format === "binary") { + return schemaObject.nullable + ? ts.factory.createUnionTypeNode([BLOB, NULL]) + : BLOB; + } + }, +}); +``` + +::: + +fileプロパティが正しく型付けされた差分は次のようになります: + +::: code-group + +```ts [my-openapi-3-schema.d.ts] +file?: string; // [!code --] +file: Blob | null; // [!code ++] +``` + +::: + +#### 例: プロパティに "?" トークンを追加 + +上記の `transform` 関数では、オプションの"?"トークンを持つプロパティを作成することはできません。しかし、transform関数は異なる戻りオブジェクトを受け入れることもでき、これを使用してプロパティに”?“トークンを追加することができます。以下はその例です: + +::: code-group + +```yaml [my-openapi-3-schema.yaml] +Body_file_upload: + type: object; + properties: + file: + type: string; + format: binary; + required: true; +``` + +::: + +ここではスキーマプロパティを持つオブジェクトを返しますが、これに加えて `questionToken` プロパティを追加し、プロパティに"?"トークンを追加します。 + +::: code-group + +```ts [src/my-project.ts] +import openapiTS from "openapi-typescript"; +import ts from "typescript"; + +const BLOB = ts.factory.createTypeReferenceNode( + ts.factory.createIdentifier("Blob") +); // `Blob` +const NULL = ts.factory.createLiteralTypeNode(ts.factory.createNull()); // `null` + +const ast = await openapiTS(mySchema, { + transform(schemaObject, metadata) { + if (schemaObject.format === "binary") { + return { + schema: schemaObject.nullable + ? ts.factory.createUnionTypeNode([BLOB, NULL]) + : BLOB, + questionToken: true, + }; + } + }, +}); +``` + +::: + +`file` プロパティが正しく型付けされ、"?"トークンが追加された結果の差分は次のとおりです: + +::: code-group + +```ts [my-openapi-3-schema.d.ts] +file: Blob; // [!code --] +file?: Blob | null; // [!code ++] +``` + +::: + +スキーマ内の任意の[Schema Object](https://spec.openapis.org/oas/latest.html#schema-object)は、このフォーマッタを通じて処理されます(リモートのものも含まれます!)。また、追加のコンテキストが役立つ場合があるので、`metadata` パラメータも必ず確認してください。 + +`format`のチェック以外にも、これを利用する方法は多数あります。この関数は **string** を返す必要があるため、任意のTypeScriptコード(独自のカスタム型も含む)を生成することができます。 From c84b3f2ba54c9cff98ab7facf51ecc9ffcd4d66d Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Wed, 14 Aug 2024 15:28:18 +0900 Subject: [PATCH 10/24] docs(ja): openapi-fetch, about --- docs/ja/openapi-fetch/about.md | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 docs/ja/openapi-fetch/about.md diff --git a/docs/ja/openapi-fetch/about.md b/docs/ja/openapi-fetch/about.md new file mode 100644 index 000000000..783aaf5b8 --- /dev/null +++ b/docs/ja/openapi-fetch/about.md @@ -0,0 +1,48 @@ +--- +title: openapi-fetch について +description: openapi-fetch プロジェクトの目標、比較など +--- + + + +# openapi-fetch について + +## プロジェクトの目標 + +1. 型は厳密で、最小限のジェネリクスで OpenAPI スキーマから自動的に推論されるべきです。 +2. ネイティブの Fetch API を尊重しつつ、(`await res.json()` などの)ボイラープレートを削減すること。 +3. 可能な限り軽量で高性能であること。 + +## 比較 + +### vs. Axios + +[Axios](https://axios-http.com) は、OpenAPI スキーマに対して自動的に型チェックを行うことはできません。さらに、それを実現する簡単な方法もありません。Axios は、インターセプターや高度なキャンセルなど、openapi-fetch よりも多くの機能を備えています。 + +### vs. tRPC + +[tRPC](https://trpc.io/) は、バックエンドとフロントエンドが両方とも TypeScript (Node.js) で書かれているプロジェクト向けです。openapi-fetch はユニバーサルであり、OpenAPI 3.x スキーマに従う任意のバックエンドと連携することができます。 + +### vs. openapi-typescript-fetch + +[openapi-typescript-fetch](https://github.com/ajaishankar/openapi-typescript-fetch) は、openapi-fetch よりも前に開発され、目的はほぼ同じですが、主に構文が異なります(つまり、選択は好みに依存します): + +- openapi-typescript-fetch は非 OK 応答の場合に例外を投げます(そのため、`try/catch` でラップする必要があります)。これに対して openapi-fetch は Fetch API 仕様に従い、例外を投げません。 +- openapi-typescript-fetch の構文は冗長で、チェーン(`.path(…).method(…).create()`)に依存します。 + +### vs. openapi-typescript-codegen + +[openapi-typescript-codegen](https://github.com/ferdikoomen/openapi-typescript-codegen) はコード生成ライブラリであり、openapi-fetch の「コード生成なし」アプローチとは根本的に異なります。openapi-fetch は、ビルド時に静的な TypeScript 型チェックを行い、クライアントの負担を増やさず、ランタイムでのパフォーマンスに影響を与えません。従来のコード生成は、クライアントの負担を増やし、ランタイムを遅くする何百(あるいは何千)もの異なる関数を生成します。 + +### vs. Swagger Codegen + +Swagger Codegen は Swagger/OpenAPI の元祖のコード生成プロジェクトであり、他のコード生成アプローチと同様にサイズの膨張やランタイムのパフォーマンス問題があります。さらに、Swagger Codegen は Java ランタイムが必要ですが、openapi-typescript/openapi-fetch はネイティブの Node.js プロジェクトとしてその必要がありません。 + +## 貢献者 + +これらの素晴らしい貢献者がいなければ、このライブラリは存在しなかったでしょう: + + From e16bfb21e7043c72e3253374eb5a087e971aa5d5 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 12:06:23 +0900 Subject: [PATCH 11/24] docs(ja): openapi-fetch, api --- docs/ja/advanced.md | 4 +- docs/ja/openapi-fetch/api.md | 261 +++++++++++++++++++++++++++++++++++ 2 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 docs/ja/openapi-fetch/api.md diff --git a/docs/ja/advanced.md b/docs/ja/advanced.md index 367637bb0..42c69dd99 100644 --- a/docs/ja/advanced.md +++ b/docs/ja/advanced.md @@ -282,7 +282,7 @@ prefixItems: OpenAPIのコンポジションツール(`oneOf` / `anyOf` / `allOf`)は、スキーマ内のコード量を減らしながら柔軟性を最大化する強力なツールです。しかし、TypeScriptの共用体型は[XOR](https://en.wikipedia.org/wiki/Exclusive_or)を提供しないため、`oneOf` に直接マッピングすることはできません。そのため、oneOfは単独で使用し、他のコンポジションメソッドやプロパティと組み合わせないことが推奨されます。例えば: -#### ❌ Bad +#### ❌ 悪い ::: code-group @@ -324,7 +324,7 @@ Pet: ::: -#### ✅ Better +#### ✅ 良い ::: code-group diff --git a/docs/ja/openapi-fetch/api.md b/docs/ja/openapi-fetch/api.md new file mode 100644 index 000000000..8e248cd4a --- /dev/null +++ b/docs/ja/openapi-fetch/api.md @@ -0,0 +1,261 @@ +--- +title: API +description: openapi-fetch API +--- + +# API + +## createClient + +**createClient** は、すべての後続のfetch呼び出しに対するデフォルト設定を以下のオプションで指定できます。 + +```ts +createClient(options); +``` + +| Name | Type | Description | +| :---------------- | :-------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `baseUrl` | `string` | すべてのfetch URLにこのオプションで指定されたプレフィックスを付与します (例. `"https://myapi.dev/v1/"`) | +| `fetch` | `fetch` | リクエストに使用するFetchインスタンス (デフォルト: `globalThis.fetch`) | +| `querySerializer` | QuerySerializer | (任意) [querySerializer](#queryserializer) を提供します | +| `bodySerializer` | BodySerializer | (任意) [bodySerializer](#bodyserializer) を提供します | +| (Fetch options) | | 有効なすべてのfetchオプション(`headers`, `mode`, `cache`, `signal` など)を指定可能です。([ドキュメント](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options)) | + +## Fetch オプション + +以下のオプションは、すべてのリクエストメソッド(`.GET()`、`.POST()` など)に適用されます。 + +```ts +client.GET("/my-url", options); +``` + +| Name | Type | Description | +| :---------------- | :---------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `params` | ParamsObject | エンドポイントの [path](https://swagger.io/specification/#parameter-locations) と [query](https://swagger.io/specification/#parameter-locations) パラメータ。 | +| `body` | `{ [name]:value }` | エンドポイントの [requestBody](https://spec.openapis.org/oas/latest.html#request-body-object) データ。 | +| `querySerializer` | QuerySerializer | (任意) [querySerializer](#queryserializer) を提供します | +| `bodySerializer` | BodySerializer | (任意) [bodySerializer](#bodyserializer) を提供します | +| `parseAs` | `"json"` \| `"text"` \| `"arrayBuffer"` \| `"blob"` \| `"stream"` | (任意) [組み込みのインスタンスメソッド](https://developer.mozilla.org/en-US/docs/Web/API/Response#instance_methods) を使用してレスポンスを解析します(デフォルト: "json") (デフォルト: `"json"`). `"stream"` は解析をスキップし、未処理のストリームを返します。 | +| `fetch` | `fetch` | リクエストに使用するFetchインスタンス (デフォルト: `createClient` で指定されたfetch) | +| `middleware` | `Middleware[]` | [ドキュメントを参照](/openapi-fetch/middleware-auth) | +| (Fetch options) | | 有効なすべてのfetchオプション(`headers`, `mode`, `cache`, `signal`など) ([ドキュメント](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options)) | + +## wrapAsPathBasedClient + +**wrapAsPathBasedClient** は、`createClient()` の結果を[Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)ベースのクライアントにラップして、パスに基づく呼び出しを可能にします。 + +```ts +const client = createClient(clientOptions); +const pathBasedClient = wrapAsPathBasedClient(client); + +pathBasedClient["/my-url"].GET(fetchOptions); +``` + +`fetchOptions` はベースクライアントと同じです。 + +Pathベースのクライアントは型推論の向上に役立ちますが、Proxyを使用するためランタイムのコストがかかります。 + +**createPathBasedClient** は `createClient` と `wrapAsPathBasedClient` を結合した便利なメソッドで、パスに基づく呼び出しスタイルを使用したい場合にのみ使用します。 + +```ts +const client = createPathBasedClient(clientOptions); + +client["/my-url"].GET(fetchOptions); +``` + +これはミドルウェアを使用できないことに注意してください。ミドルウェアが必要な場合は、完全な形式を使用する必要があります。 + +```ts +const client = createClient(clientOptions); + +client.use(...); + +const pathBasedClient = wrapAsPathBasedClient(client); + +client.use(...); // クライアント参照は共有されるため、ミドルウェアは伝播します。 + +pathBasedClient["/my-url"].GET(fetchOptions); +``` + +## querySerializer + +OpenAPIは、パラメータに対してオブジェクトや配列をシリアライズする際に、[さまざまな方法をサポート](https://swagger.io/docs/specification/serialization/#query)しています(文字列、数値、ブール値などのプリミティブ型は常に同じ方法で処理されます)。デフォルトでは、このライブラリは配列を `style: "form"`, `explode: true` でシリアライズし、オブジェクトを `style: "deepObject"`, `explode: true` でシリアライズしますが、`querySerializer` オプションを使用して、この動作をカスタマイズすることができます(すべてのリクエストに対して `createClient()` で指定するか、個別のリクエストに対してのみ指定することができます)。 + +### オブジェクト構文 + +openapi-fetchは、一般的なシリアル化方法を標準で提供しています: + +| Option | Type | Description | +| :-------------- | :---------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `array` | SerializerOptions | 配列の `style` と `explode` を設定します ([ドキュメント](https://swagger.io/docs/specification/serialization/#query))。 デフォルト: `{ style: "form", explode: true }` | +| `object` | SerializerOptions | オブジェクトの `style` と `explode` を設定します ([ドキュメント](https://swagger.io/docs/specification/serialization/#query))。 デフォルト: `{ style: "deepObject", explode: true }` | +| `allowReserved` | `boolean` | URLエンコードをスキップするためには `true` に設定します(⚠️ リクエストが壊れる可能性があります) ([ドキュメント](https://swagger.io/docs/specification/serialization/#query))。 デフォルト: `false` | + +```ts +const client = createClient({ + querySerializer: { + array: { + style: "pipeDelimited", // "form" (デフォルト) | "spaceDelimited" | "pipeDelimited" + explode: true, + }, + object: { + style: "form", // "form" | "deepObject" (デフォルト) + explode: true, + }, + }, +}); +``` + +#### 配列のstyles + +| Style | Array `id = [3, 4, 5]` | +| :--------------------------- | :---------------------- | +| form | `/users?id=3,4,5` | +| **form (exploded, default)** | `/users?id=3&id=4&id=5` | +| spaceDelimited | `/users?id=3%204%205` | +| spaceDelimited (exploded) | `/users?id=3&id=4&id=5` | +| pipeDelimited | `/users?id=3\|4\|5` | +| pipeDelimited (exploded) | `/users?id=3&id=4&id=5` | + +#### オブジェクトのstyles + +| Style | Object `id = {"role": "admin", "firstName": "Alex"}` | +| :----------------------- | :--------------------------------------------------- | +| form | `/users?id=role,admin,firstName,Alex` | +| form (exploded) | `/users?role=admin&firstName=Alex` | +| **deepObject (default)** | `/users?id[role]=admin&id[firstName]=Alex` | + +::: tip + +**deepObject** は常に個別指定なので、`explode: true` または `explode: false` を設定しても、生成される出力は同じです。 + +::: + +### 別の関数構文 + +バックエンドが標準のシリアル化方法のいずれかを使用しない場合、 `querySerializer` に関数を渡して、文字列全体を自分でシリアル化することができます。paramsに深くネストされたオブジェクトや配列を処理する場合は、この方法を使用する必要があります。 + +```ts +const client = createClient({ + querySerializer(queryParams) { + const search = []; + for (const name in queryParams) { + const value = queryParams[name]; + if (Array.isArray(value)) { + for (const item of value) { + s.push(`${name}[]=${encodeURIComponent(item)}`); + } + } else { + s.push(`${name}=${encodeURLComponent(value)}`); + } + } + return search.join(","); // ?tags[]=food,tags[]=california,tags[]=healthy + }, +}); +``` + +::: warning + +自分でシリアライズする場合、文字列は記述されたままの状態で保持されるため、特殊文字をエスケープするには [encodeURI](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI) または [encodeURIComponent](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) を呼び出す必要があります。 + +::: + +## bodySerializer + +[querySerializer](#queryserializer)と同様に、bodySerializerを使用するとデフォルトの [JSON.stringify()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) の動作を変更したい場合に、requestBodyのシリアライズ方法をカスタマイズできます。これはおそらく、`multipart/form-data` を使用する際にのみ必要となるでしょう。 + +```ts +const { data, error } = await client.PUT("/submit", { + body: { + name: "", + query: { version: 2 }, + }, + bodySerializer(body) { + const fd = new FormData(); + for (const name in body) { + fd.append(name, body[name]); + } + return fd; + }, +}); +``` + +## Pathのシリアライズ + +openapi-fetchは、[3.1仕様書に記載されている](https://swagger.io/docs/specification/serialization/#path)ように、pathのシリアライズをサポートしています。これは、OpenAPIスキーマ内の特定のフォーマットに基づいて自動的に行われます。 + +| Template | Style | Primitive `id = 5` | Array `id = [3, 4, 5]` | Object `id = {"role": "admin", "firstName": "Alex"}` | +| :---------------- | :------------------- | :----------------- | :----------------------- | :--------------------------------------------------- | +| **`/users/{id}`** | **simple (default)** | **`/users/5`** | **`/users/3,4,5`** | **`/users/role,admin,firstName,Alex`** | +| `/users/{id*}` | simple (exploded) | `/users/5` | `/users/3,4,5` | `/users/role=admin,firstName=Alex` | +| `/users/{.id}` | label | `/users/.5` | `/users/.3,4,5` | `/users/.role,admin,firstName,Alex` | +| `/users/{.id*}` | label (exploded) | `/users/.5` | `/users/.3.4.5` | `/users/.role=admin.firstName=Alex` | +| `/users/{;id}` | matrix | `/users/;id=5` | `/users/;id=3,4,5` | `/users/;id=role,admin,firstName,Alex` | +| `/users/{;id*}` | matrix (exploded) | `/users/;id=5` | `/users/;id=3;id=4;id=5` | `/users/;role=admin;firstName=Alex` | + +## ミドルウェア + +ミドルウェアは、リクエストとレスポンスを監視および変更できる `onRequest()` と `onResponse()` のコールバックを持つオブジェクトです。 + +```ts +import createClient from "openapi-fetch"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptによって生成された型をインポート + +const myMiddleware: Middleware = { + async onRequest({ request, options }) { + // "foo" ヘッダーを設定 + request.headers.set("foo", "bar"); + return request; + }, + async onResponse({ request, response, options }) { + const { body, ...resOptions } = res; + // レスポンスのステータスを変更 + return new Response(body, { ...resOptions, status: 200 }); + }, +}; + +const client = createClient({ baseUrl: "https://myapi.dev/v1/" }); + +// ミドルウェアを登録 +client.use(myMiddleware); +``` + +### API + +#### Parameters + +各ミドルウェアのコールバックは、以下の内容を持つ `options` オブジェクトを受け取ります。 + +| Name | Type | Description | +| :----------- | :-------------- | :-------------------------------------------------------------------------------------------------- | +| `request` | `Request` | エンドポイントに送信される現在の `Request` オブジェクト。 | +| `response` | `Response` | エンドポイントから返された `Response` オブジェクト(`onRequest` の場合は `undefined` になります)。 | +| `schemaPath` | `string` | 呼び出された元の OpenAPI パス(例. `/users/{user_id}`)。 | +| `params` | `Object` | `GET()` や `POST()` などに渡された元の `params` オブジェクト。 | +| `id` | `string` | このリクエストのランダムでユニークなID。 | +| `options` | `ClientOptions` | `createClient()` に渡された読み取り専用のオプション。 | + +#### Response + +各ミドルウェアのコールバックは以下を返すことができます: + +- **onRequest** リクエストを変更する `Request` またはそのままにする場合は `undefined`(スキップ)。 +- **onResponse** レスポンスを変更する `Response` またはそのままにする場合は `undefined`(スキップ)。 + +### ミドルウェアの削除 + +ミドルウェアを削除するには、`client.eject(middleware)` を呼び出します: + +```ts{9} +const myMiddleware = { + // … +}; + +// ミドルウェアを登録 +client.use(myMiddleware); + +// ミドルウェアを削除 +client.eject(myMiddleware); +``` + +追加のガイドと例については、[Middleware & Auth](/openapi-fetch/middleware-auth) を参照してください。 From 80a5bce09b4b34551a0fdc467ed5e7ef45b1aba0 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 12:25:13 +0900 Subject: [PATCH 12/24] docs(ja): openapi-fetch, examples --- docs/ja/openapi-fetch/examples.md | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 docs/ja/openapi-fetch/examples.md diff --git a/docs/ja/openapi-fetch/examples.md b/docs/ja/openapi-fetch/examples.md new file mode 100644 index 000000000..c1bcc06ed --- /dev/null +++ b/docs/ja/openapi-fetch/examples.md @@ -0,0 +1,37 @@ +--- +title: openapi-fetch 使用例 +--- + +# 使用例 + +openapi-fetchを他のフレームワークやライブラリと組み合わせて使用するコード例 + +## React + React Query + +[React Query](https://tanstack.com/query/latest) は、Reactでopenapi-fetchを使用するための理想的なラッパーです。わずか13 kBのサイズで、クライアントサイドのキャッシュ機能を提供し、クライアントの負担を増やすことなく利用できます。また、その優れた型推論機能により、openapi-fetchの型が最小限の設定で完全に保持されます。 + +[GitHubでコード例を見る](https://github.com/openapi-ts/openapi-typescript/tree/main/packages/openapi-fetch/examples/react-query) + +## Next.js + +[Next.js](https://nextjs.org/) は、React向けの最も人気のあるSSR(サーバーサイドレンダリング)フレームワークです。[React Query](#react--react-query) はクライアントサイドでのデータ取得に推奨されていますが、この例では、Next.jsの[サーバーサイドでのデータ取得機能](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#fetching-data-on-the-server-with-fetch)を利用し、ビルトインのキャッシュ機能を活用する方法を示しています。 + +[GitHubでコード例を見る](https://github.com/openapi-ts/openapi-typescript/tree/main/packages/openapi-fetch/examples/nextjs) + +## Svelte / SvelteKit + +[SvelteKit](https://kit.svelte.dev) の自動型推論機能は、クライアントサイドでのデータ取得や[ページデータの取得](https://kit.svelte.dev/docs/load#page-data)において、openapi-fetchの型を簡単に活用できます。また、追加のライブラリを必要とせずに動作します。SvelteKitは、ロード関数内で[カスタムフェッチ](https://kit.svelte.dev/docs/load#making-fetch-requests)を使用することを推奨しており、これは[フェッチオプション](/openapi-fetch/api#fetch-options)で実現できます。 + +_注: SvelteKitを使用しない場合でも、`src/routes/+page.svelte` 内のルート例は、SvelteKitの機能を使用しておらず、どのようなセットアップにも適用可能です。_ + +[GitHubでコード例を見る](https://github.com/openapi-ts/openapi-typescript/tree/main/packages/openapi-fetch/examples/sveltekit) + +## Vue 3 + +[Vue 3](https://vuejs.org/) は大規模なエコシステムを持つ人気のフレームワークです。Vue 3のComposition APIは、関心の分離やリアクティビティを容易にするため、openapi-fetchと非常に相性が良いです。 + +[GitHubでコード例を見る](https://github.com/openapi-ts/openapi-typescript/tree/main/packages/openapi-fetch/examples/vue-3) + +--- + +他の例も歓迎しています!あなたの使用例を[PRとして提出](https://github.com/openapi-ts/openapi-typescript/pulls)してください。 \ No newline at end of file From ca4a6c93da6e7722ce06e8eddce9cb03f4fadc36 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 14:26:24 +0900 Subject: [PATCH 13/24] docs(ja): openapi-fetch, index --- docs/ja/openapi-fetch/index.md | 200 +++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 docs/ja/openapi-fetch/index.md diff --git a/docs/ja/openapi-fetch/index.md b/docs/ja/openapi-fetch/index.md new file mode 100644 index 000000000..f42db0a0a --- /dev/null +++ b/docs/ja/openapi-fetch/index.md @@ -0,0 +1,200 @@ +--- +title: openapi-fetch +--- + +openapi-fetch + +openapi-fetchは、あなたのOpenAPIスキーマを取り込み、型安全なfetchクライアントを提供します。このライブラリはわずか **6 kb** で、ほとんどのランタイムを持たず、React、Vue、Svelte、あるいはバニラJSとも動作します。 + +| ライブラリ | サイズ (min) | “GET” リクエスト\* | +| :------------------------- | -----------: | :----------------------- | +| openapi-fetch | `6 kB` | `300k` ops/s (最速) | +| openapi-typescript-fetch | `4 kB` | `150k` ops/s (2倍遅い) | +| axios | `32 kB` | `225k` ops/s (1.3倍遅い) | +| superagent | `55 kB` | `50k` ops/s (6倍遅い) | +| openapi-typescript-codegen | `367 kB` | `100k` ops/s (3倍遅い) | + +_\* [ベンチマークはおおよそのものです](https://github.com/openapi-ts/openapi-typescript/blob/main/packages/openapi-fetch/test/index.bench.js) 。実際のパフォーマンスはマシンやブラウザによって異なる場合があります。ライブラリ間の相対的なパフォーマンスはより信頼性があります。_ + +このシンタックスは、React QueryやApollo Clientのような人気のライブラリにインスパイアされたものでありながら、すべての装飾を省き、6 kbというコンパクトなパッケージに収まっています。 + +::: code-group + +```ts [src/my-project.ts] +import createClient from "openapi-fetch"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const client = createClient({ baseUrl: "https://myapi.dev/v1/" }); + +const { + data, // 2XXレスポンスの場合のみ存在 + error, // 4XXまたは5XXレスポンスの場合のみ存在 +} = await client.GET("/blogposts/{post_id}", { + params: { + path: { post_id: "123" }, + }, +}); + +await client.PUT("/blogposts", { + body: { + title: "新しい投稿", + }, +}); +``` + +::: + +`data` と `error` は型チェックが行われ、VS Codeや他のTypeScript対応IDEでIntellisenseによる補完が利用可能です。同様に、リクエストの `body` もフィールドが型チェックされ、必要なパラメータが不足している場合や型の不一致がある場合にはエラーが発生します。 + +`GET()`, `PUT()`, `POST()` などは、ネイティブの [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) の薄いラッパーとして動作します([任意の呼び出しに変更することも可能です](/openapi-fetch/api#create-client))。 + +ここで重要なのは、ジェネリクスや手動の型指定が一切不要で、エンドポイントのリクエストとレスポンスが自動的に推論されることです。これは、エンドポイントの型安全性を大幅に向上させます。なぜなら、**手動でのアサーションはバグの原因となり得るからです**!これにより、次のような問題がすべて解消されます: + +- ✅ URLやパラメータのタイプミスが起こらない +- ✅ すべてのパラメータ、リクエストボディ、レスポンスが型チェックされ、スキーマと100%一致する +- ✅ APIの手動での型指定が不要 +- ✅ バグを隠す可能性がある `any` 型の排除 +- ✅ バグを隠す可能性がある `as` 型の上書きも排除 +- ✅ これらすべてが**5 kb**のクライアントパッケージで実現 🎉 + +## セットアップ + +このライブラリと [openapi-typescript](/introduction) をインストールします: + +```bash +npm i openapi-fetch +npm i -D openapi-typescript typescript +``` + +::: tip 強く推奨 + +`tsconfig.json`で [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) を有効にしてください ([ドキュメント](/advanced#enable-nouncheckedindexaccess-in-your-tsconfigjson)) + +::: + +次に、openapi-typescriptを使用してOpenAPIスキーマからTypeScriptの型を生成します: + +```bash +npx openapi-typescript ./path/to/api/v1.yaml -o ./src/lib/api/v1.d.ts +``` + +最後に、プロジェクトで **型チェックを実行** してください。これは、`tsc --noEmit` を [npm scripts](https://docs.npmjs.com/cli/v9/using-npm/scripts) に追加することで可能です: + +::: code-group + +```json{3} [package.json] +{ + "scripts": { + "test:ts": "tsc --noEmit" + } +} +``` + +::: + +そして、CIで `npm run test:ts` を実行して型エラーを検出します。 + +::: tip + +`tsc --noEmit` を使用して型エラーをチェックし、リンターやビルドコマンドに依存しないようにしてください。TypeScriptコンパイラ自体ほど正確に型チェックを行えるものはありません。 +::: + +## 基本的な使用方法 + +openapi-fetchを従来のコード生成ツールよりも使用する最大の利点は、ドキュメントが不要であることです。openapi-fetchは、どの関数をインポートするか、あるいはその関数がどのパラメータを受け取るかを探す代わりに、既存のOpenAPIドキュメントを活用することを推奨しています: + +![OpenAPI schema example](/assets/openapi-schema.png) + +::: code-group + +```ts [src/my-project.ts] +import createClient from "openapi-fetch"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const client = createClient({ baseUrl: "https://myapi.dev/v1/" }); + +const { data, error } = await client.GET("/blogposts/{post_id}", { + params: { + path: { post_id: "my-post" }, + query: { version: 2 }, + }, +}); + +const { data, error } = await client.PUT("/blogposts", { + body: { + title: "New Post", + body: "

New post body

", + publish_date: new Date("2023-03-01T12:00:00Z").getTime(), + }, +}); +``` + +::: + +1. HTTPメソッドは `createClient()` から直接取得します。 +2. `GET()` , `PUT()` , などに希望するpathを渡します。 +3. TypeScriptが欠落しているものや無効なものがあれば有用なエラーを返します。 + +### Pathname + +`GET()` , `PUT()` , `POST()` などのpathnameは、スキーマと厳密に一致している必要があります。例では、URLは `/blogposts/{post_id}` です。このライブラリは、すべての `path` パラメータをすぐに置き換え、それらが型チェックされるようにします。 + +::: tip + +openapi-fetchはURLから型を推論します。動的な実行時の値よりも静的な文字列値を優先してください。例: + +- ✅ `"/blogposts/{post_id}"` +- ❌ `[...pathParts].join("/") + "{post_id}"` + +::: + +このライブラリはまた、**label** および **matrix** のシリアライゼーションスタイルもサポートしています([ドキュメント](https://swagger.io/docs/specification/serialization/#path))。 + +### Request + +`GET()` リクエストには、[タイプごとにパラメータをグループ化する](https://spec.openapis.org/oas/latest.html#parameter-object) `params` オブジェクトが必要です( `path`または `query` )。必須のパラメータが欠けている場合や、型が間違っている場合には、型エラーが発生します。 + +`POST()` リクエストでは、必要な [requestBody](https://spec.openapis.org/oas/latest.html#request-body-object) データを提供する `body` オブジェクトが必要でした。 + +### Response + +すべてのメソッドは**data**、**error**および **response**を持つオブジェクトを返します。 + +```ts +const { data, error, response } = await client.GET("/url"); +``` + +| Object | Response | +| :--------- | :------------------------------------------------------------------------------------------------------------------------------ | +| `data` | OKの場合 `2xx` レスポンス、そうでない場合 `undefined` | +| `error` | OKでない場合 `5xx` 、`4xx` 、または `default` レスポンス、それ以外は `undefined` | +| `response` | [オリジナルのレスポンス](https://developer.mozilla.org/en-US/docs/Web/API/Response)であり、`status`, `headers` などを含みます。 | + +### Path-property スタイル + +パスをプロパティとして選択する方が好ましい場合は、パスベースのクライアントを作成できます: + +```ts +import { createPathBasedClient } from "openapi-fetch"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const client = createPathBasedClient({ + baseUrl: "https://myapi.dev/v1", +}); + +client["/blogposts/{post_id}"].GET({ + params: { post_id: "my-post" }, + query: { version: 2 }, +}); +``` + +これにはパフォーマンスの影響があり、ミドルウェアを直接アタッチすることはできません。 +詳細については、[`wrapAsPathBasedClient`](/openapi-fetch/api#wrapAsPathBasedClient) を参照してください。 + +## サポート + +| プラットフォーム | サポート | +| :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------ | +| **ブラウザ** | [fetch API サポートを参照](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#browser_compatibility) (主要なブラウザで広く利用可能) | +| **Node** | >= 18.0.0 | +| **TypeScript** | >= 4.7 (>= 5.0 recommended) | From 922ddf22afcb2d5bbe82800429686ceb7ccce9bb Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 14:39:10 +0900 Subject: [PATCH 14/24] docs(ja): openapi-fetch, middleware-auth --- docs/ja/openapi-fetch/middleware-auth.md | 177 +++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 docs/ja/openapi-fetch/middleware-auth.md diff --git a/docs/ja/openapi-fetch/middleware-auth.md b/docs/ja/openapi-fetch/middleware-auth.md new file mode 100644 index 000000000..73a469f8c --- /dev/null +++ b/docs/ja/openapi-fetch/middleware-auth.md @@ -0,0 +1,177 @@ +--- +title: ミドルウェアと認証 +--- + +# ミドルウェアと認証 + +ミドルウェアは、すべてのフェッチに対してリクエスト、レスポンス、またはその両方を修正するために使用できます。最も一般的なユースケースの1つは認証ですが、ロギングやテレメトリ、エラーのスロー、特定のエッジケースの処理にも使用できます。 + +## ミドルウェア + +各ミドルウェアは、リクエストやレスポンスを監視および/または変更するための `onRequest()` および `onResponse()` コールバックを提供できます。 + +::: code-group + +```ts [src/my-project.ts] +import createClient from "openapi-fetch"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const myMiddleware: Middleware = { + async onRequest({ request, options }) { + // "foo" ヘッダーを設定 + request.headers.set("foo", "bar"); + return request; + }, + async onResponse({ request, response, options }) { + const { body, ...resOptions } = response; + // レスポンスのステータスを変更 + return new Response(body, { ...resOptions, status: 200 }); + }, +}; + +const client = createClient({ baseUrl: "https://myapi.dev/v1/" }); + +// ミドルウェアを登録 +client.use(myMiddleware); +``` + +::: + +::: tip + +ミドルウェアが登録される順序は重要です。リクエストに対しては、`onRequest()` が登録順に呼び出されます。レスポンスに対しては、`onResponse()` が逆順で呼び出されます。これにより、最初のミドルウェアがリクエストに対して最初に作用し、最終的なレスポンスを制御することができます。 + +::: + +### スキップ + +特定の条件下でミドルウェアをスキップしたい場合は、可能な限り早く `return` してください。 + +```ts +onRequest({ schemaPath }) { + if (schemaPath !== "/projects/{project_id}") { + return undefined; + } + // … +} +``` + +これにより、リクエストやレスポンスが変更されず、次のミドルウェアハンドラ(ある場合)に処理が渡されます。内部のコールバックやオブザーバーライブラリは必要ありません。 + +### エラーのスロー + +ミドルウェアは、通常 `fetch()` がスローしないエラーをスローするためにも使用できます。これは [TanStack Query](https://tanstack.com/query/latest) などのライブラリで便利です。 + +```ts +onResponse({ response }) { + if (response.error) { + throw new Error(response.error.message); + } +} +``` + +### ミドルウェアの削除 + +ミドルウェアを削除するには、`client.eject(middleware)` を呼び出します。 + +```ts{9} +const myMiddleware = { + // … +}; + +// ミドルウェアを登録 +client.use(myMiddleware); + +// ミドルウェアを削除 +client.eject(myMiddleware); +``` + +### ステートフルな処理 + +ミドルウェアはネイティブの `Request` と `Response` インスタンスを使用するため、[ボディはステートフル](https://developer.mozilla.org/en-US/docs/Web/API/Response/bodyUsed)であることを覚えておくことが重要です。つまり、 + +- 変更する場合は**新しいインスタンスを作成する** (`new Request()` / `new Response()`) +- 変更しない場合は**クローンする** (`res.clone().json()`) + +デフォルトでは、`openapi-fetch` はパフォーマンスのためにリクエストやレスポンスをクローン**しません**。クリーンなコピーを作成するのはあなた次第です。 + + +```ts +const myMiddleware: Middleware = { + onResponse({ response }) { + const data = await response.json(); // [!code --] + const data = await response.clone().json(); // [!code ++] + return undefined; + }, +}; +``` + +## 認証 + +このライブラリは特定の認証設定には依存しないため、任意の [Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) 設定と組み合わせて使用することができます。しかし、認証を容易にするためのいくつかの提案を以下に示します。 + +### ベーシック認証 + +この基本的な例では、各リクエストで最新のトークンを取得するためにミドルウェアを使用します。この例では、アクセストークンがJavaScriptモジュールの状態で保持されており、クライアントアプリケーションには安全ですが、サーバーアプリケーションでは避けるべきです。 + +::: code-group + +```ts [src/my-project.ts] +import createClient, { type Middleware } from "openapi-fetch"; +import type { paths } from "./my-openapi-3-schema"; + +let accessToken: string | undefined = undefined; + +const authMiddleware: Middleware = { + async onRequest({ request }) { + // トークンが存在しない場合は取得 + if (!accessToken) { + const authRes = await someAuthFunc(); + if (authRes.accessToken) { + accessToken = authRes.accessToken; + } else { + // 認証エラーの処理 + } + } + + // (任意)トークンが期限切れになった場合のロジックを追加 + + // すべてのリクエストにAuthorizationヘッダーを追加 + request.headers.set("Authorization", `Bearer ${accessToken}`); + return request; + }, +}; + +const client = createClient({ baseUrl: "https://myapi.dev/v1/" }); +client.use(authMiddleware); + +const authRequest = await client.GET("/some/auth/url"); +``` + +::: + +### 条件付き認証 + +特定のルートには認証が不要な場合、ミドルウェアでそれを処理することもできます: + +::: code-group + +```ts [src/my-project.ts] +const UNPROTECTED_ROUTES = ["/v1/login", "/v1/logout", "/v1/public/"]; + +const authMiddleware = { + onRequest({ schemaPath, request }) { + if ( + UNPROTECTED_ROUTES.some((pathname) => schemaPath.startsWith(pathname)) + ) { + return undefined; // 特定のパスに対してはリクエストを変更しない + } + + // その他のパスには期待通りにAuthorizationヘッダーを設定 + request.headers.set("Authorization", `Bearer ${accessToken}`); + return request; + }, +}; +``` + +::: From f7761bf6d54b028eb390b9c18b28d17fa45b6320 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 14:52:43 +0900 Subject: [PATCH 15/24] docs(ja): openapi-fetch, testing --- docs/ja/openapi-fetch/api.md | 2 +- docs/ja/openapi-fetch/testing.md | 90 ++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 docs/ja/openapi-fetch/testing.md diff --git a/docs/ja/openapi-fetch/api.md b/docs/ja/openapi-fetch/api.md index 8e248cd4a..8fdfdc2bf 100644 --- a/docs/ja/openapi-fetch/api.md +++ b/docs/ja/openapi-fetch/api.md @@ -199,7 +199,7 @@ openapi-fetchは、[3.1仕様書に記載されている](https://swagger.io/doc ```ts import createClient from "openapi-fetch"; -import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptによって生成された型をインポート +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 const myMiddleware: Middleware = { async onRequest({ request, options }) { diff --git a/docs/ja/openapi-fetch/testing.md b/docs/ja/openapi-fetch/testing.md new file mode 100644 index 000000000..9dc744f35 --- /dev/null +++ b/docs/ja/openapi-fetch/testing.md @@ -0,0 +1,90 @@ +--- +title: テスト +--- + +# テスト + +openapi-fetchのテストは、[Vitest](https://vitest.dev/) や Jest のような TypeScript をサポートするテストランナーで行うのが最適です。 + +## リクエストのモック + +リクエストをテストするには、`fetch` オプションに `vi.fn()`(Vitest)や `jest.fn()`(Jest)などのスパイ関数を渡すことができます。 + +::: code-group + +```ts [src/my-project.test.ts] +import createClient from "openapi-fetch"; +import { expect, test, vi } from "vitest"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +test("my request", async () => { + const mockFetch = vi.fn(); + const client = createClient({ + baseUrl: "https://my-site.com/api/v1/", + fetch: mockFetch, + }); + + const reqBody = { name: "test" }; + await client.PUT("/tag", { body: reqBody }); + + const req = mockFetch.mock.calls[0][0]; + expect(req.url).toBe("/tag"); + expect(await req.json()).toEqual(reqBody); +}); +``` + +::: + +## レスポンスのモック + +テストでAPIレスポンスをモックするには、[Mock Service Worker](https://mswjs.io/) の使用を強くお勧めします。 + +::: code-group + +```ts [src/my-project.test.ts] +import { http, HttpResponse } from "msw"; +import { setupServer } from "msw/node"; +import createClient from "openapi-fetch"; +import { afterEach, beforeAll, expect, test } from "vitest"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const server = setupServer(); + +beforeAll(() => { + // NOTE: server.listenは、`createClient`が使用される前に呼び出される必要があります。 + // これにより、mswが自身の`fetch`バージョンをインジェクトしてリクエストをインターセプトできます。 + server.listen({ + onUnhandledRequest: (request) => { + throw new Error( + `No request handler found for ${request.method} ${request.url}` + ); + }, + }); +}); + +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +test("my API call", async () => { + const rawData = { test: { data: "foo" } }; + + const BASE_URL = "https://my-site.com"; + + server.use( + http.get(`${BASE_URL}/api/v1/foo`, () => + HttpResponse.json(rawData, { status: 200 }) + ) + ); + + const client = createClient({ + baseUrl: BASE_URL, + }); + + const { data, error } = await client.GET("/api/v1/foo"); + + expect(data).toEqual(rawData); + expect(error).toBeUndefined(); +}); +``` + +::: From dd19bb0fccf9bba3a185c0f9948ad2855711f31c Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 15:21:39 +0900 Subject: [PATCH 16/24] docs(ja): openapi-react-query, about --- docs/ja/openapi-react-query/about.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 docs/ja/openapi-react-query/about.md diff --git a/docs/ja/openapi-react-query/about.md b/docs/ja/openapi-react-query/about.md new file mode 100644 index 000000000..73ff71e6b --- /dev/null +++ b/docs/ja/openapi-react-query/about.md @@ -0,0 +1,23 @@ +--- +title: About openapi-react-query +description: openapi-react-query Project Goals and contributors +--- + + + +# 概要 + +## プロジェクトの目標 + +1. 型は厳格であり、必要最小限のジェネリクスでOpenAPIスキーマから自動的に推論されるべきです。 +2. 元の `@tanstack/react-query` API を尊重しつつ、ボイラープレートを減らします。 +3. できるだけ軽量でパフォーマンスが高くなるようにします。 + +## 貢献者 + +これらの素晴らしい貢献者がいなければ、このライブラリは存在しなかったでしょう: + + From c41d31851dd6fe6d5c576b95f36c9cb5a5b3856e Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 15:40:11 +0900 Subject: [PATCH 17/24] docs(ja): openapi-react-query, index --- docs/ja/openapi-react-query/index.md | 110 +++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 docs/ja/openapi-react-query/index.md diff --git a/docs/ja/openapi-react-query/index.md b/docs/ja/openapi-react-query/index.md new file mode 100644 index 000000000..1579e20f0 --- /dev/null +++ b/docs/ja/openapi-react-query/index.md @@ -0,0 +1,110 @@ +--- +title: openapi-react-query +--- + +# Introduction + +openapi-react-queryは、[@tanstack/react-query](https://tanstack.com/query/latest/docs/framework/react/overview) と連携してOpenAPIスキーマを扱うための、1kbの型安全な軽量ラッパーです。 + +これは [openapi-fetch](../openapi-fetch/)] および [openapi-typescript](../introduction) を使用することで、以下のすべての機能が提供されます: + +- ✅ URLやパラメータのタイプミスが起こらない +- ✅ すべてのパラメータ、リクエストボディ、レスポンスが型チェックされ、スキーマと100%一致する +- ✅ APIの手動での型指定が不要 +- ✅ バグを隠す可能性がある `any` 型の排除 +- ✅ バグを隠す可能性がある `as` 型の上書きも排除 + +::: code-group + +```tsx [src/my-component.ts] +import createFetchClient from "openapi-fetch"; +import createClient from "openapi-react-query"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const fetchClient = createFetchClient({ + baseUrl: "https://myapi.dev/v1/", +}); +const $api = createClient(fetchClient); + +const MyComponent = () => { + const { data, error, isLoading } = $api.useQuery( + "get", + "/blogposts/{post_id}", + { + params: { + path: { post_id: 5 }, + }, + } + ); + + if (isLoading || !data) return "Loading..."; + + if (error) return `An error occured: ${error.message}`; + + return
{data.title}
; +}; +``` + +::: + +## セットアップ + +このライブラリを [openapi-fetch](../openapi-fetch/) および [openapi-typescript](../introduction) と一緒にインストールします: + +```bash +npm i openapi-react-query openapi-fetch +npm i -D openapi-typescript typescript +``` + +::: tip 強く推奨 + +`tsconfig.json`で [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) を有効にしてください ([ドキュメント](/advanced#enable-nouncheckedindexaccess-in-your-tsconfigjson)) + +::: + +次に、openapi-typescript を使用してOpenAPIスキーマからTypeScriptの型を生成します: + +```bash +npx openapi-typescript ./path/to/api/v1.yaml -o ./src/lib/api/v1.d.ts +``` + +## 基本的な使い方 + +スキーマから型が生成されたら、[fetchクライアント](../introduction.md)とreact-queryクライアントを作成し、APIにクエリを実行できます。 + +::: code-group + +```tsx [src/my-component.ts] +import createFetchClient from "openapi-fetch"; +import createClient from "openapi-react-query"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const fetchClient = createFetchClient({ + baseUrl: "https://myapi.dev/v1/", +}); +const $api = createClient(fetchClient); + +const MyComponent = () => { + const { data, error, isLoading } = $api.useQuery( + "get", + "/blogposts/{post_id}", + { + params: { + path: { post_id: 5 }, + }, + } + ); + + if (isLoading || !data) return "Loading..."; + + if (error) return `An error occured: ${error.message}`; + + return
{data.title}
; +}; +``` + +::: + +::: tip +`createFetchClient` に関する詳細は [openapi-fetch ドキュメント](../openapi-fetch/index.md) をご覧ください。 +::: From 097e9442deab868320f592eb3d950027add07fe1 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 15:57:15 +0900 Subject: [PATCH 18/24] docs(ja): openapi-react-query, use-mutation --- docs/ja/openapi-react-query/use-mutation.md | 68 +++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 docs/ja/openapi-react-query/use-mutation.md diff --git a/docs/ja/openapi-react-query/use-mutation.md b/docs/ja/openapi-react-query/use-mutation.md new file mode 100644 index 000000000..75fce3a9d --- /dev/null +++ b/docs/ja/openapi-react-query/use-mutation.md @@ -0,0 +1,68 @@ +--- +title: useMutation +--- + +# {{ $frontmatter.title }} + +`useMutation` メソッドを使用すると、react-query本来の [useMutation](https://tanstack.com/query/latest/docs/framework/react/guides/mutations) を利用できます。 + +- resultは本来の関数と同じです。 +- `mutationKey` は `[method, path]`です。 +- `data` と `error` は完全に型付けされています。 + +::: tip +`useMutation` に関する詳細は、[@tanstack/react-query ドキュメント](https://tanstack.com/query/latest/docs/framework/react/guides/mutations) で確認できます。 +::: + +## 使用例 + +::: code-group + +```tsx [src/app.tsx] +import { $api } from "./api"; + +export const App = () => { + const { mutate } = $api.useMutation("patch", "/users"); + + return ( + + ); +}; +``` + +```ts [src/api.ts] +import createFetchClient from "openapi-fetch"; +import createClient from "openapi-react-query"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const fetchClient = createFetchClient({ + baseUrl: "https://myapi.dev/v1/", +}); +export const $api = createClient(fetchClient); +``` + +::: + +## Api + +```tsx +const query = $api.useQuery(method, path, options, queryOptions, queryClient); +``` + +**引数** + +- `method` **(必須)** + - リクエストに使用するHTTPメソッド + - このメソッドがキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 +- `path` **(必須)** + - リクエストに使用するパス名 + - スキーマ内で指定されたメソッドに対応する利用可能なパスでなければなりません。 + - パス名はキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 +- `queryOptions` + - 本来の useMutation オプション + - [See more information](https://tanstack.com/query/latest/docs/framework/react/reference/useMutation) +- `queryClient` + - 本来の queryClient オプション + - [See more information](https://tanstack.com/query/latest/docs/framework/react/reference/useMutation) From 46d825d95a9d9465fdc9849c5cd6d750836a37af Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 16:38:05 +0900 Subject: [PATCH 19/24] docs(ja): openapi-react-query, use-query --- docs/ja/openapi-react-query/use-query.md | 75 ++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 docs/ja/openapi-react-query/use-query.md diff --git a/docs/ja/openapi-react-query/use-query.md b/docs/ja/openapi-react-query/use-query.md new file mode 100644 index 000000000..fcdeb428f --- /dev/null +++ b/docs/ja/openapi-react-query/use-query.md @@ -0,0 +1,75 @@ +--- +title: useQuery +--- +# {{ $frontmatter.title }} + +`useQuery` メソッドを使用すると、react-query本来の [useQuery](https://tanstack.com/query/latest/docs/framework/react/guides/queries) を利用できます。 + +- resultは本来の関数と同じです。 +- `functionKey` は `[method, path, params]` です。 +- `data` と `error` は完全に型付けされています。 +- 第4引数としてクエリオプションを渡すことができます。 + +::: tip +`useQuery` に関する詳細は、[@tanstack/react-query ドキュメント](https://tanstack.com/query/latest/docs/framework/react/guides/queries) で確認できます。 +::: + +## 使用例 + +::: code-group + +```tsx [src/app.tsx] +import { $api } from "./api"; + +export const App = () => { + const { data, error, isLoading } = $api.useQuery("get", "/users/{user_id}", { + params: { + path: { user_id: 5 }, + }, + }); + + if (!data || isLoading) return "Loading..."; + if (error) return `An error occured: ${error.message}`; + + return
{data.firstname}
; +}; +``` + +```ts [src/api.ts] +import createFetchClient from "openapi-fetch"; +import createClient from "openapi-react-query"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const fetchClient = createFetchClient({ + baseUrl: "https://myapi.dev/v1/", +}); +export const $api = createClient(fetchClient); +``` + +::: + +## Api + +```tsx +const query = $api.useQuery(method, path, options, queryOptions, queryClient); +``` + +**引数** + +- `method` **(必須)** + - リクエストに使用するHTTPメソッド + - このメソッドがキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 +- `path` **(必須)** + - リクエストに使用するパス名 + - スキーマ内で指定されたメソッドに対応する利用可能なパスでなければなりません。 + - パス名はキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 +- `options` + - リクエストに使用するfetchオプション + - OpenAPIスキーマがパラメータを要求する場合のみ必要です。 + - オプションの `params` はキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 +- `queryOptions` + - 本来の `useQuery` オプション + - [詳細はこちら](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery) +- `queryClient` + - 本来の `queryClient` オプション + - [詳細はこちら](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery) From ba8fbdeac2321bfb46fac7137a5b27d96a1ccc90 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 16:38:15 +0900 Subject: [PATCH 20/24] docs(ja): openapi-react-query, use-suspense-query --- .../openapi-react-query/use-suspense-query.md | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 docs/ja/openapi-react-query/use-suspense-query.md diff --git a/docs/ja/openapi-react-query/use-suspense-query.md b/docs/ja/openapi-react-query/use-suspense-query.md new file mode 100644 index 000000000..20ae88e67 --- /dev/null +++ b/docs/ja/openapi-react-query/use-suspense-query.md @@ -0,0 +1,88 @@ +--- +title: useSuspenseQuery +--- + +# {{ $frontmatter.title }} + +`useSuspenseQuery` メソッドを使用すると、react-query本来の [useSuspenseQuery](https://tanstack.com/query/latest/docs/framework/react/guides/suspense)を利用できます。 + +- resultは本来の関数と同じです。 +- `functionKey` は `[method, path, params]` です。 +- `data` と `error` は完全に型付けされています。 +- 第4引数としてクエリオプションを渡すことができます。 + +::: tip +`useSuspenseQuery` に関する詳細は、[@tanstack/react-query ドキュメント](https://tanstack.com/query/latest/docs/framework/react/guides/suspense) で確認できます。 +::: + +## 使用例 + +::: code-group + +```tsx [src/app.tsx] +import { ErrorBoundary } from "react-error-boundary"; +import { $api } from "./api"; + +const MyComponent = () => { + const { data } = $api.useSuspenseQuery("get", "/users/{user_id}", { + params: { + path: { user_id: 5 }, + }, + }); + + return
{data.firstname}
; +}; + +export const App = () => { + return ( + `Error: ${error.message}`}> + + + ); +}; +``` + +```ts [src/api.ts] +import createFetchClient from "openapi-fetch"; +import createClient from "openapi-react-query"; +import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typescript + +const fetchClient = createFetchClient({ + baseUrl: "https://myapi.dev/v1/", +}); +export const $api = createClient(fetchClient); +``` + +::: + +## Api + +```tsx +const query = $api.useSuspenseQuery( + method, + path, + options, + queryOptions, + queryClient +); +``` + +**引数** + +- `method` **(必須)** + - リクエストに使用するHTTPメソッド + - このメソッドがキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 +- `path` **(必須)** + - リクエストに使用するパス名 + - スキーマ内で指定されたメソッドに対応する利用可能なパスでなければなりません。 + - パス名はキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 +- `options` + - リクエストに使用するfetchオプション + - OpenAPIスキーマがパラメータを要求する場合のみ必要です。 + - オプションの `params` はキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 +- `queryOptions` + - 本来の `useSuspenseQuery` オプション + - [詳細はこちら](https://tanstack.com/query/latest/docs/framework/react/reference/useSuspenseQuery) +- `queryClient` + - 本来の `queryClient` オプション + - [詳細はこちら](https://tanstack.com/query/latest/docs/framework/react/reference/useSuspenseQuery) From 11ed757ace89162e9019d067ca0077a681665de2 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Thu, 15 Aug 2024 20:40:40 +0900 Subject: [PATCH 21/24] feat: add vitepress `ja` config --- docs/.vitepress/config.ts | 2 + docs/.vitepress/ja.ts | 112 ++++++++++++++++++++++++++++++++++++ docs/.vitepress/shared.ts | 3 +- docs/data/contributors.json | 2 +- 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 docs/.vitepress/ja.ts diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 6193dfb5b..42177cdb0 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -1,6 +1,7 @@ import { defineConfig } from "vitepress"; import en from "./en"; import zh from "./zh"; +import ja from "./ja"; import shared from "./shared"; // https://vitepress.dev/reference/site-config @@ -9,5 +10,6 @@ export default defineConfig({ locales: { root: { label: "English", ...en }, zh: { label: "简体中文", ...zh }, + ja: { label: "日本語", ...ja }, }, }); diff --git a/docs/.vitepress/ja.ts b/docs/.vitepress/ja.ts new file mode 100644 index 000000000..b69da2bb4 --- /dev/null +++ b/docs/.vitepress/ja.ts @@ -0,0 +1,112 @@ +import { defineConfig, type DefaultTheme } from "vitepress"; + +export default defineConfig({ + lang: "ja", + description: "OpenAPI 3.0および3.1のスキーマをTypeScriptで使用する方法。", + themeConfig: { + nav: [ + { + text: "バージョン", + items: [ + { text: "7.x", link: "/ja/introduction" }, + { text: "6.x", link: "/6.x/introduction" }, + ], + }, + ], + sidebar: { + "/ja/": [ + { + text: "openapi-typescript (7.x)", + items: [ + { text: "イントロダクション", link: "/ja/introduction" }, + { text: "CLI", link: "/ja/cli" }, + { text: "Node.js API", link: "/ja/node" }, + { text: "使用例", link: "/ja/examples" }, + { text: "6.xからのマイグレーション", link: "/ja/migration-guide" }, + { text: "高度な機能", link: "/ja/advanced" }, + { text: "概要", link: "/ja/about" }, + ], + }, + { + text: "openapi-fetch", + items: [ + { text: "始める", link: "/ja/openapi-fetch/" }, + { + text: "ミドルウェア & 認証", + link: "/ja/openapi-fetch/middleware-auth", + }, + { text: "テスト", link: "/ja/openapi-fetch/testing" }, + { text: "使用例", link: "/ja/openapi-fetch/examples" }, + { text: "API", link: "/ja/openapi-fetch/api" }, + { text: "概要", link: "/ja/openapi-fetch/about" }, + ], + }, + { + text: "openapi-react-query", + items: [ + { text: "始める", link: "/ja/openapi-react-query/" }, + { text: "useQuery", link: "/ja/openapi-react-query/use-query" }, + { text: "useMutation", link: "/ja/openapi-react-query/use-mutation " }, + { text: "useSuspenseQuery", link: "/ja/openapi-react-query/use-suspense-query" }, + { text: "概要", link: "/ja/openapi-react-query/about" }, + ], + }, + ], + }, + + docFooter: { + prev: "前のページ", + next: "次のページ", + }, + outline: { + label: "目次", + }, + footer: { + message: + 'MITライセンス に基づいて配布されています', + }, + }, +}); + +export const jaSearch: DefaultTheme.AlgoliaSearchOptions["locales"] = { + ja: { + placeholder: "ドキュメントを検索", + translations: { + button: { + buttonText: "検索", + buttonAriaLabel: "検索", + }, + modal: { + searchBox: { + resetButtonTitle: "クエリをクリア", + resetButtonAriaLabel: "クエリをクリア", + cancelButtonText: "キャンセル", + cancelButtonAriaLabel: "キャンセル", + }, + startScreen: { + recentSearchesTitle: "最近の検索", + noRecentSearchesText: "最近の検索履歴はありません", + saveRecentSearchButtonTitle: "最近の検索に保存", + removeRecentSearchButtonTitle: "最近の検索から削除", + favoriteSearchesTitle: "お気に入り", + removeFavoriteSearchButtonTitle: "お気に入りから削除", + }, + errorScreen: { + titleText: "結果を取得できません", + helpText: "ネットワーク接続を確認してください", + }, + footer: { + selectText: "選択", + navigateText: "移動", + closeText: "閉じる", + }, + noResultsScreen: { + noResultsText: "関連する結果が見つかりません", + suggestedQueryText: "別のクエリを試してみてください", + reportMissingResultsText: "このクエリに結果があるべきだと思いますか?", + reportMissingResultsLinkText: "フィードバックを送信", + }, + }, + }, + }, +}; \ No newline at end of file diff --git a/docs/.vitepress/shared.ts b/docs/.vitepress/shared.ts index 564fed5f6..3d457933a 100644 --- a/docs/.vitepress/shared.ts +++ b/docs/.vitepress/shared.ts @@ -1,5 +1,6 @@ import type { UserConfig } from "vitepress"; import { zhSearch } from "./zh"; +import { jaSearch } from "./ja"; const HOSTNAME = "https://openapi-ts.dev"; @@ -31,7 +32,7 @@ const shared: UserConfig = { appId: "NA92XVKBVS", apiKey: "4f3ce9ca7edc3b83c209e6656ab29eb8", indexName: "openapi-ts", - locales: { ...zhSearch }, + locales: { ...zhSearch, ...jaSearch }, }, }, socialLinks: [ diff --git a/docs/data/contributors.json b/docs/data/contributors.json index 9c7b7014c..9154a0f44 100644 --- a/docs/data/contributors.json +++ b/docs/data/contributors.json @@ -1 +1 @@ -{"openapi-typescript":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723439859660},{"username":"psmyrdek","name":"Przemek Smyrdek","avatar":"https://avatars.githubusercontent.com/u/6187417?v=4","links":[{"icon":"github","link":"https://github.com/psmyrdek"}],"lastFetch":1723439859780},{"username":"enmand","name":"Dan Enman","avatar":"https://avatars.githubusercontent.com/u/432487?v=4","links":[{"icon":"github","link":"https://github.com/enmand"}],"lastFetch":1723439859929},{"username":"atlefren","name":"Atle Frenvik Sveen","avatar":"https://avatars.githubusercontent.com/u/1829927?v=4","links":[{"icon":"github","link":"https://github.com/atlefren"}],"lastFetch":1723439860035},{"username":"tpdewolf","name":"Tim de Wolf","avatar":"https://avatars.githubusercontent.com/u/4455209?v=4","links":[{"icon":"github","link":"https://github.com/tpdewolf"}],"lastFetch":1723439860140},{"username":"tombarton","name":"Tom Barton","avatar":"https://avatars.githubusercontent.com/u/6222711?v=4","links":[{"icon":"github","link":"https://github.com/tombarton"}],"lastFetch":1723439860249},{"username":"svnv","name":"Sven Nicolai Viig","avatar":"https://avatars.githubusercontent.com/u/1080888?v=4","links":[{"icon":"github","link":"https://github.com/svnv"}],"lastFetch":1723439860355},{"username":"sorin-davidoi","name":"Sorin Davidoi","avatar":"https://avatars.githubusercontent.com/u/2109702?v=4","links":[{"icon":"github","link":"https://github.com/sorin-davidoi"}],"lastFetch":1723439860466},{"username":"scvnathan","name":"Nathan Schneirov","avatar":"https://avatars.githubusercontent.com/u/73474?v=4","links":[{"icon":"github","link":"https://github.com/scvnathan"}],"lastFetch":1723439860680},{"username":"lbenie","name":"Lucien Bénié","avatar":"https://avatars.githubusercontent.com/u/7316046?v=4","links":[{"icon":"github","link":"https://github.com/lbenie"}],"lastFetch":1723439860803},{"username":"bokub","name":"Boris K","avatar":"https://avatars.githubusercontent.com/u/17952318?v=4","links":[{"icon":"github","link":"https://github.com/bokub"}],"lastFetch":1723439860940},{"username":"antonk52","name":"Anton Kastritskii","avatar":"https://avatars.githubusercontent.com/u/5817809?v=4","links":[{"icon":"github","link":"https://github.com/antonk52"}],"lastFetch":1723439861068},{"username":"tshelburne","name":"Tim Shelburne","avatar":"https://avatars.githubusercontent.com/u/1202267?v=4","links":[{"icon":"github","link":"https://github.com/tshelburne"}],"lastFetch":1723439861184},{"username":"typeofweb","name":"Michał Miszczyszyn","avatar":"https://avatars.githubusercontent.com/u/1338731?v=4","links":[{"icon":"github","link":"https://github.com/typeofweb"}],"lastFetch":1723439861292},{"username":"skh-","name":"Sam K Hall","avatar":"https://avatars.githubusercontent.com/u/1292598?v=4","links":[{"icon":"github","link":"https://github.com/skh-"}],"lastFetch":1723439861400},{"username":"BlooJeans","name":"Matt Jeanes","avatar":"https://avatars.githubusercontent.com/u/1751182?v=4","links":[{"icon":"github","link":"https://github.com/BlooJeans"}],"lastFetch":1723439861512},{"username":"selbekk","name":"Kristofer Giltvedt Selbekk","avatar":"https://avatars.githubusercontent.com/u/1307267?v=4","links":[{"icon":"github","link":"https://github.com/selbekk"}],"lastFetch":1723439861648},{"username":"Mause","name":"Elliana May","avatar":"https://avatars.githubusercontent.com/u/1405026?v=4","links":[{"icon":"github","link":"https://github.com/Mause"}],"lastFetch":1723439861899},{"username":"henhal","name":"Henrik Hall","avatar":"https://avatars.githubusercontent.com/u/9608258?v=4","links":[{"icon":"github","link":"https://github.com/henhal"}],"lastFetch":1723439862015},{"username":"gr2m","name":"Gregor Martynus","avatar":"https://avatars.githubusercontent.com/u/39992?v=4","links":[{"icon":"github","link":"https://github.com/gr2m"}],"lastFetch":1723439862129},{"username":"samdbmg","name":"Sam Mesterton-Gibbons","avatar":"https://avatars.githubusercontent.com/u/408983?v=4","links":[{"icon":"github","link":"https://github.com/samdbmg"}],"lastFetch":1723439862243},{"username":"rendall","name":"Rendall","avatar":"https://avatars.githubusercontent.com/u/293263?v=4","links":[{"icon":"github","link":"https://github.com/rendall"}],"lastFetch":1723439862358},{"username":"robertmassaioli","name":"Robert Massaioli","avatar":"https://avatars.githubusercontent.com/u/149178?v=4","links":[{"icon":"github","link":"https://github.com/robertmassaioli"}],"lastFetch":1723439862473},{"username":"jankuca","name":"Jan Kuča","avatar":"https://avatars.githubusercontent.com/u/367262?v=4","links":[{"icon":"github","link":"https://github.com/jankuca"}],"lastFetch":1723439862713},{"username":"th-m","name":"Thomas Valadez","avatar":"https://avatars.githubusercontent.com/u/13792029?v=4","links":[{"icon":"github","link":"https://github.com/th-m"}],"lastFetch":1723439862847},{"username":"asithade","name":"Asitha de Silva","avatar":"https://avatars.githubusercontent.com/u/3814354?v=4","links":[{"icon":"github","link":"https://github.com/asithade"}],"lastFetch":1723439862976},{"username":"misha-erm","name":"Misha","avatar":"https://avatars.githubusercontent.com/u/8783498?v=4","links":[{"icon":"github","link":"https://github.com/misha-erm"}],"lastFetch":1723439863091},{"username":"radist2s","name":"Alex Batalov","avatar":"https://avatars.githubusercontent.com/u/725645?v=4","links":[{"icon":"github","link":"https://github.com/radist2s"}],"lastFetch":1723439863322},{"username":"FedeBev","name":"Federico Bevione","avatar":"https://avatars.githubusercontent.com/u/22151395?v=4","links":[{"icon":"github","link":"https://github.com/FedeBev"}],"lastFetch":1723439863434},{"username":"yamacent","name":"Daisuke Yamamoto","avatar":"https://avatars.githubusercontent.com/u/8544439?v=4","links":[{"icon":"github","link":"https://github.com/yamacent"}],"lastFetch":1723439863539},{"username":"dnalborczyk","name":null,"avatar":"https://avatars.githubusercontent.com/u/2903325?v=4","links":[{"icon":"github","link":"https://github.com/dnalborczyk"}],"lastFetch":1723439863645},{"username":"FabioWanner","name":null,"avatar":"https://avatars.githubusercontent.com/u/46821078?v=4","links":[{"icon":"github","link":"https://github.com/FabioWanner"}],"lastFetch":1723439863760},{"username":"ashsmith","name":"Ash Smith","avatar":"https://avatars.githubusercontent.com/u/1086841?v=4","links":[{"icon":"github","link":"https://github.com/ashsmith"}],"lastFetch":1723439863899},{"username":"mehalter","name":"Micah Halter","avatar":"https://avatars.githubusercontent.com/u/1591837?v=4","links":[{"icon":"github","link":"https://github.com/mehalter"}],"lastFetch":1723439864036},{"username":"Chrg1001","name":"chrg1001","avatar":"https://avatars.githubusercontent.com/u/40189653?v=4","links":[{"icon":"github","link":"https://github.com/Chrg1001"}],"lastFetch":1723439864145},{"username":"sharmarajdaksh","name":"Dakshraj Sharma","avatar":"https://avatars.githubusercontent.com/u/33689528?v=4","links":[{"icon":"github","link":"https://github.com/sharmarajdaksh"}],"lastFetch":1723439864256},{"username":"shuluster","name":"Shaosu Liu","avatar":"https://avatars.githubusercontent.com/u/1707910?v=4","links":[{"icon":"github","link":"https://github.com/shuluster"}],"lastFetch":1723439864357},{"username":"FDiskas","name":"Vytenis","avatar":"https://avatars.githubusercontent.com/u/468006?v=4","links":[{"icon":"github","link":"https://github.com/FDiskas"}],"lastFetch":1723439864534},{"username":"ericzorn93","name":"Eric Zorn","avatar":"https://avatars.githubusercontent.com/u/22532542?v=4","links":[{"icon":"github","link":"https://github.com/ericzorn93"}],"lastFetch":1723439864771},{"username":"mbelsky","name":"Max Belsky","avatar":"https://avatars.githubusercontent.com/u/3923527?v=4","links":[{"icon":"github","link":"https://github.com/mbelsky"}],"lastFetch":1723439864900},{"username":"techbech","name":"Peter Bech","avatar":"https://avatars.githubusercontent.com/u/1520592?v=4","links":[{"icon":"github","link":"https://github.com/techbech"}],"lastFetch":1723439865012},{"username":"rustyconover","name":"Rusty Conover","avatar":"https://avatars.githubusercontent.com/u/731941?v=4","links":[{"icon":"github","link":"https://github.com/rustyconover"}],"lastFetch":1723439865126},{"username":"bunkscene","name":"Dave Carlson","avatar":"https://avatars.githubusercontent.com/u/2693678?v=4","links":[{"icon":"github","link":"https://github.com/bunkscene"}],"lastFetch":1723439865269},{"username":"ottomated","name":null,"avatar":"https://avatars.githubusercontent.com/u/31470743?v=4","links":[{"icon":"github","link":"https://github.com/ottomated"}],"lastFetch":1723439865394},{"username":"sadfsdfdsa","name":"Artem Shuvaev","avatar":"https://avatars.githubusercontent.com/u/28733669?v=4","links":[{"icon":"github","link":"https://github.com/sadfsdfdsa"}],"lastFetch":1723439865516},{"username":"ajaishankar","name":null,"avatar":"https://avatars.githubusercontent.com/u/328008?v=4","links":[{"icon":"github","link":"https://github.com/ajaishankar"}],"lastFetch":1723439865653},{"username":"dominikdosoudil","name":"Dominik Dosoudil","avatar":"https://avatars.githubusercontent.com/u/15929942?v=4","links":[{"icon":"github","link":"https://github.com/dominikdosoudil"}],"lastFetch":1723439865777},{"username":"kgtkr","name":"kgtkr","avatar":"https://avatars.githubusercontent.com/u/17868838?v=4","links":[{"icon":"github","link":"https://github.com/kgtkr"}],"lastFetch":1723439865887},{"username":"berzi","name":null,"avatar":"https://avatars.githubusercontent.com/u/32619123?v=4","links":[{"icon":"github","link":"https://github.com/berzi"}],"lastFetch":1723439866003},{"username":"PhilipTrauner","name":"Philip Trauner","avatar":"https://avatars.githubusercontent.com/u/9287847?v=4","links":[{"icon":"github","link":"https://github.com/PhilipTrauner"}],"lastFetch":1723439866185},{"username":"Powell-v2","name":"Pavel Yermolin","avatar":"https://avatars.githubusercontent.com/u/25308326?v=4","links":[{"icon":"github","link":"https://github.com/Powell-v2"}],"lastFetch":1723439866298},{"username":"duncanbeevers","name":"Duncan Beevers","avatar":"https://avatars.githubusercontent.com/u/7367?v=4","links":[{"icon":"github","link":"https://github.com/duncanbeevers"}],"lastFetch":1723439866406},{"username":"tkukushkin","name":"Timofei Kukushkin","avatar":"https://avatars.githubusercontent.com/u/1482516?v=4","links":[{"icon":"github","link":"https://github.com/tkukushkin"}],"lastFetch":1723439866508},{"username":"Semigradsky","name":"Dmitry Semigradsky","avatar":"https://avatars.githubusercontent.com/u/1198848?v=4","links":[{"icon":"github","link":"https://github.com/Semigradsky"}],"lastFetch":1723439866672},{"username":"MrLeebo","name":"Jeremy Liberman","avatar":"https://avatars.githubusercontent.com/u/2754163?v=4","links":[{"icon":"github","link":"https://github.com/MrLeebo"}],"lastFetch":1723439866807},{"username":"axelhzf","name":"Axel Hernández Ferrera","avatar":"https://avatars.githubusercontent.com/u/175627?v=4","links":[{"icon":"github","link":"https://github.com/axelhzf"}],"lastFetch":1723439866924},{"username":"imagoiq","name":"Loïc Fürhoff","avatar":"https://avatars.githubusercontent.com/u/12294151?v=4","links":[{"icon":"github","link":"https://github.com/imagoiq"}],"lastFetch":1723439867037},{"username":"BTMPL","name":"Bartosz Szczeciński","avatar":"https://avatars.githubusercontent.com/u/247153?v=4","links":[{"icon":"github","link":"https://github.com/BTMPL"}],"lastFetch":1723439867175},{"username":"HiiiiD","name":"Marco Salomone","avatar":"https://avatars.githubusercontent.com/u/61231210?v=4","links":[{"icon":"github","link":"https://github.com/HiiiiD"}],"lastFetch":1723439867304},{"username":"yacinehmito","name":"Yacine Hmito","avatar":"https://avatars.githubusercontent.com/u/6893840?v=4","links":[{"icon":"github","link":"https://github.com/yacinehmito"}],"lastFetch":1723439867416},{"username":"sajadtorkamani","name":"Sajad Torkamani","avatar":"https://avatars.githubusercontent.com/u/9380313?v=4","links":[{"icon":"github","link":"https://github.com/sajadtorkamani"}],"lastFetch":1723439867525},{"username":"mvdbeek","name":"Marius van den Beek","avatar":"https://avatars.githubusercontent.com/u/6804901?v=4","links":[{"icon":"github","link":"https://github.com/mvdbeek"}],"lastFetch":1723439867677},{"username":"sgrimm","name":"Steven Grimm","avatar":"https://avatars.githubusercontent.com/u/1248649?v=4","links":[{"icon":"github","link":"https://github.com/sgrimm"}],"lastFetch":1723439867781},{"username":"Swiftwork","name":"Erik Hughes","avatar":"https://avatars.githubusercontent.com/u/455178?v=4","links":[{"icon":"github","link":"https://github.com/Swiftwork"}],"lastFetch":1723439868084},{"username":"mtth","name":"Matthieu Monsch","avatar":"https://avatars.githubusercontent.com/u/1216372?v=4","links":[{"icon":"github","link":"https://github.com/mtth"}],"lastFetch":1723439868189},{"username":"mitchell-merry","name":"Mitchell Merry","avatar":"https://avatars.githubusercontent.com/u/8567231?v=4","links":[{"icon":"github","link":"https://github.com/mitchell-merry"}],"lastFetch":1723439868298},{"username":"qnp","name":"François Risoud","avatar":"https://avatars.githubusercontent.com/u/6012554?v=4","links":[{"icon":"github","link":"https://github.com/qnp"}],"lastFetch":1723439868428},{"username":"shoffmeister","name":null,"avatar":"https://avatars.githubusercontent.com/u/3868036?v=4","links":[{"icon":"github","link":"https://github.com/shoffmeister"}],"lastFetch":1723439868556},{"username":"liangskyli","name":"liangsky","avatar":"https://avatars.githubusercontent.com/u/31531283?v=4","links":[{"icon":"github","link":"https://github.com/liangskyli"}],"lastFetch":1723439868682},{"username":"happycollision","name":"Don Denton","avatar":"https://avatars.githubusercontent.com/u/3663628?v=4","links":[{"icon":"github","link":"https://github.com/happycollision"}],"lastFetch":1723439868787},{"username":"ysmood","name":"Yad Smood","avatar":"https://avatars.githubusercontent.com/u/1415488?v=4","links":[{"icon":"github","link":"https://github.com/ysmood"}],"lastFetch":1723439868961},{"username":"barakalon","name":"barak","avatar":"https://avatars.githubusercontent.com/u/12398927?v=4","links":[{"icon":"github","link":"https://github.com/barakalon"}],"lastFetch":1723439869068},{"username":"horaklukas","name":"Lukáš Horák","avatar":"https://avatars.githubusercontent.com/u/996088?v=4","links":[{"icon":"github","link":"https://github.com/horaklukas"}],"lastFetch":1723439869178},{"username":"pvanagtmaal","name":null,"avatar":"https://avatars.githubusercontent.com/u/5946464?v=4","links":[{"icon":"github","link":"https://github.com/pvanagtmaal"}],"lastFetch":1723439869297},{"username":"toomuchdesign","name":"Andrea Carraro","avatar":"https://avatars.githubusercontent.com/u/4573549?v=4","links":[{"icon":"github","link":"https://github.com/toomuchdesign"}],"lastFetch":1723439869404},{"username":"psychedelicious","name":"psychedelicious","avatar":"https://avatars.githubusercontent.com/u/4822129?v=4","links":[{"icon":"github","link":"https://github.com/psychedelicious"}],"lastFetch":1723439869512},{"username":"tkrotoff","name":"Tanguy Krotoff","avatar":"https://avatars.githubusercontent.com/u/643434?v=4","links":[{"icon":"github","link":"https://github.com/tkrotoff"}],"lastFetch":1723439869626},{"username":"pimveldhuisen","name":"Pim Veldhuisen","avatar":"https://avatars.githubusercontent.com/u/3043834?v=4","links":[{"icon":"github","link":"https://github.com/pimveldhuisen"}],"lastFetch":1723439869732},{"username":"asvishnyakov","name":"Aleksandr Vishniakov","avatar":"https://avatars.githubusercontent.com/u/6369252?v=4","links":[{"icon":"github","link":"https://github.com/asvishnyakov"}],"lastFetch":1723439869844},{"username":"SchabaJo","name":null,"avatar":"https://avatars.githubusercontent.com/u/138689813?v=4","links":[{"icon":"github","link":"https://github.com/SchabaJo"}],"lastFetch":1723439869957},{"username":"AhsanFazal","name":"Ahsan Fazal","avatar":"https://avatars.githubusercontent.com/u/7458046?v=4","links":[{"icon":"github","link":"https://github.com/AhsanFazal"}],"lastFetch":1723439870148},{"username":"ElForastero","name":"Eugene Dzhumak","avatar":"https://avatars.githubusercontent.com/u/5102818?v=4","links":[{"icon":"github","link":"https://github.com/ElForastero"}],"lastFetch":1723439870258},{"username":"msgadi","name":"Mohammed Gadi","avatar":"https://avatars.githubusercontent.com/u/9037086?v=4","links":[{"icon":"github","link":"https://github.com/msgadi"}],"lastFetch":1723439870388},{"username":"muttonchop","name":"Adam K","avatar":"https://avatars.githubusercontent.com/u/1037657?v=4","links":[{"icon":"github","link":"https://github.com/muttonchop"}],"lastFetch":1723439870510},{"username":"christoph-fricke","name":"Christoph Fricke","avatar":"https://avatars.githubusercontent.com/u/23103835?v=4","links":[{"icon":"github","link":"https://github.com/christoph-fricke"}],"lastFetch":1723439870624},{"username":"JorrinKievit","name":"Jorrin","avatar":"https://avatars.githubusercontent.com/u/43169049?v=4","links":[{"icon":"github","link":"https://github.com/JorrinKievit"}],"lastFetch":1723439870769},{"username":"WickyNilliams","name":"Nick Williams","avatar":"https://avatars.githubusercontent.com/u/1091390?v=4","links":[{"icon":"github","link":"https://github.com/WickyNilliams"}],"lastFetch":1723439870887},{"username":"hrsh7th","name":"hrsh7th","avatar":"https://avatars.githubusercontent.com/u/629908?v=4","links":[{"icon":"github","link":"https://github.com/hrsh7th"}],"lastFetch":1723439871068},{"username":"davidleger95","name":"David Leger","avatar":"https://avatars.githubusercontent.com/u/10498708?v=4","links":[{"icon":"github","link":"https://github.com/davidleger95"}],"lastFetch":1723439871191},{"username":"phk422","name":"Hongkun Peng","avatar":"https://avatars.githubusercontent.com/u/59734322?v=4","links":[{"icon":"github","link":"https://github.com/phk422"}],"lastFetch":1723439871300},{"username":"mzronek","name":"Matthias Zronek","avatar":"https://avatars.githubusercontent.com/u/3847700?v=4","links":[{"icon":"github","link":"https://github.com/mzronek"}],"lastFetch":1723439871409},{"username":"raurfang","name":"Łukasz Wiśniewski","avatar":"https://avatars.githubusercontent.com/u/867241?v=4","links":[{"icon":"github","link":"https://github.com/raurfang"}],"lastFetch":1723439871522},{"username":"JeanRemiDelteil","name":"Jean-Rémi Delteil","avatar":"https://avatars.githubusercontent.com/u/9743907?v=4","links":[{"icon":"github","link":"https://github.com/JeanRemiDelteil"}],"lastFetch":1723439871697},{"username":"TzviPM","name":"Tzvi Melamed","avatar":"https://avatars.githubusercontent.com/u/1950680?v=4","links":[{"icon":"github","link":"https://github.com/TzviPM"}],"lastFetch":1723439871807},{"username":"LucaSchwan","name":"ehrenschwan","avatar":"https://avatars.githubusercontent.com/u/25820532?v=4","links":[{"icon":"github","link":"https://github.com/LucaSchwan"}],"lastFetch":1723439871923},{"username":"nzapponi","name":"Niccolo Zapponi","avatar":"https://avatars.githubusercontent.com/u/20582065?v=4","links":[{"icon":"github","link":"https://github.com/nzapponi"}],"lastFetch":1723439872041},{"username":"luchsamapparat","name":"Marvin Luchs","avatar":"https://avatars.githubusercontent.com/u/875017?v=4","links":[{"icon":"github","link":"https://github.com/luchsamapparat"}],"lastFetch":1723439872150},{"username":"nmacmunn","name":"Neil MacMunn","avatar":"https://avatars.githubusercontent.com/u/849964?v=4","links":[{"icon":"github","link":"https://github.com/nmacmunn"}],"lastFetch":1723439872266}],"openapi-fetch":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723439859666},{"username":"fergusean","name":null,"avatar":"https://avatars.githubusercontent.com/u/1029297?v=4","links":[{"icon":"github","link":"https://github.com/fergusean"}],"lastFetch":1723439859771},{"username":"shinzui","name":"Nadeem Bitar","avatar":"https://avatars.githubusercontent.com/u/519?v=4","links":[{"icon":"github","link":"https://github.com/shinzui"}],"lastFetch":1723439859878},{"username":"ezpuzz","name":"Emory Petermann","avatar":"https://avatars.githubusercontent.com/u/672182?v=4","links":[{"icon":"github","link":"https://github.com/ezpuzz"}],"lastFetch":1723439859988},{"username":"KotoriK","name":null,"avatar":"https://avatars.githubusercontent.com/u/52659125?v=4","links":[{"icon":"github","link":"https://github.com/KotoriK"}],"lastFetch":1723439860101},{"username":"fletchertyler914","name":"Tyler Fletcher","avatar":"https://avatars.githubusercontent.com/u/3344498?v=4","links":[{"icon":"github","link":"https://github.com/fletchertyler914"}],"lastFetch":1723439860230},{"username":"nholik","name":"Nicklos Holik","avatar":"https://avatars.githubusercontent.com/u/2022214?v=4","links":[{"icon":"github","link":"https://github.com/nholik"}],"lastFetch":1723439860351},{"username":"roj1512","name":null,"avatar":"https://avatars.githubusercontent.com/u/175297870?v=4","links":[{"icon":"github","link":"https://github.com/roj1512"}],"lastFetch":1723439860463},{"username":"nickcaballero","name":"Nick Caballero","avatar":"https://avatars.githubusercontent.com/u/355976?v=4","links":[{"icon":"github","link":"https://github.com/nickcaballero"}],"lastFetch":1723439860682},{"username":"hd-o","name":"Hadrian de Oliveira","avatar":"https://avatars.githubusercontent.com/u/58871222?v=4","links":[{"icon":"github","link":"https://github.com/hd-o"}],"lastFetch":1723439860844},{"username":"kecrily","name":"Percy Ma","avatar":"https://avatars.githubusercontent.com/u/45708948?v=4","links":[{"icon":"github","link":"https://github.com/kecrily"}],"lastFetch":1723439860959},{"username":"psychedelicious","name":"psychedelicious","avatar":"https://avatars.githubusercontent.com/u/4822129?v=4","links":[{"icon":"github","link":"https://github.com/psychedelicious"}],"lastFetch":1723439861091},{"username":"muttonchop","name":"Adam K","avatar":"https://avatars.githubusercontent.com/u/1037657?v=4","links":[{"icon":"github","link":"https://github.com/muttonchop"}],"lastFetch":1723439861222},{"username":"marcomuser","name":"Marco Muser","avatar":"https://avatars.githubusercontent.com/u/64737396?v=4","links":[{"icon":"github","link":"https://github.com/marcomuser"}],"lastFetch":1723439861374},{"username":"HugeLetters","name":"Evgenii Perminov","avatar":"https://avatars.githubusercontent.com/u/119697239?v=4","links":[{"icon":"github","link":"https://github.com/HugeLetters"}],"lastFetch":1723439861504},{"username":"Fumaz","name":"alex","avatar":"https://avatars.githubusercontent.com/u/45318608?v=4","links":[{"icon":"github","link":"https://github.com/Fumaz"}],"lastFetch":1723439861610},{"username":"darwish","name":"Mike Darwish","avatar":"https://avatars.githubusercontent.com/u/292570?v=4","links":[{"icon":"github","link":"https://github.com/darwish"}],"lastFetch":1723439861728},{"username":"kaechele","name":"Felix Kaechele","avatar":"https://avatars.githubusercontent.com/u/454490?v=4","links":[{"icon":"github","link":"https://github.com/kaechele"}],"lastFetch":1723439861901},{"username":"phk422","name":"Hongkun Peng","avatar":"https://avatars.githubusercontent.com/u/59734322?v=4","links":[{"icon":"github","link":"https://github.com/phk422"}],"lastFetch":1723439862018},{"username":"mikestopcontinues","name":"Mike Stop Continues","avatar":"https://avatars.githubusercontent.com/u/150434?v=4","links":[{"icon":"github","link":"https://github.com/mikestopcontinues"}],"lastFetch":1723439862124},{"username":"JE-Lee","name":"maurice","avatar":"https://avatars.githubusercontent.com/u/19794813?v=4","links":[{"icon":"github","link":"https://github.com/JE-Lee"}],"lastFetch":1723439862241},{"username":"vipentti","name":"Ville Penttinen","avatar":"https://avatars.githubusercontent.com/u/4726680?v=4","links":[{"icon":"github","link":"https://github.com/vipentti"}],"lastFetch":1723439862357},{"username":"armandabric","name":"Armand Abric","avatar":"https://avatars.githubusercontent.com/u/95120?v=4","links":[{"icon":"github","link":"https://github.com/armandabric"}],"lastFetch":1723439862470},{"username":"illright","name":"Lev Chelyadinov","avatar":"https://avatars.githubusercontent.com/u/15035286?v=4","links":[{"icon":"github","link":"https://github.com/illright"}],"lastFetch":1723439862715}],"openapi-react-query":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723439859665},{"username":"kerwanp","name":"Martin Paucot","avatar":"https://avatars.githubusercontent.com/u/36955373?v=4","links":[{"icon":"github","link":"https://github.com/kerwanp"}],"lastFetch":1723439859774},{"username":"yoshi2no","name":"yoshi2no","avatar":"https://avatars.githubusercontent.com/u/57059705?v=4","links":[{"icon":"github","link":"https://github.com/yoshi2no"}],"lastFetch":1723439859883}]} \ No newline at end of file +{"openapi-typescript":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723702317349},{"username":"psmyrdek","name":"Przemek Smyrdek","avatar":"https://avatars.githubusercontent.com/u/6187417?v=4","links":[{"icon":"github","link":"https://github.com/psmyrdek"}],"lastFetch":1723702317647},{"username":"enmand","name":"Dan Enman","avatar":"https://avatars.githubusercontent.com/u/432487?v=4","links":[{"icon":"github","link":"https://github.com/enmand"}],"lastFetch":1723702318029},{"username":"atlefren","name":"Atle Frenvik Sveen","avatar":"https://avatars.githubusercontent.com/u/1829927?v=4","links":[{"icon":"github","link":"https://github.com/atlefren"}],"lastFetch":1723702318256},{"username":"tpdewolf","name":"Tim de Wolf","avatar":"https://avatars.githubusercontent.com/u/4455209?v=4","links":[{"icon":"github","link":"https://github.com/tpdewolf"}],"lastFetch":1723702318502},{"username":"tombarton","name":"Tom Barton","avatar":"https://avatars.githubusercontent.com/u/6222711?v=4","links":[{"icon":"github","link":"https://github.com/tombarton"}],"lastFetch":1723702318738},{"username":"svnv","name":"Sven Nicolai Viig","avatar":"https://avatars.githubusercontent.com/u/1080888?v=4","links":[{"icon":"github","link":"https://github.com/svnv"}],"lastFetch":1723702319217},{"username":"sorin-davidoi","name":"Sorin Davidoi","avatar":"https://avatars.githubusercontent.com/u/2109702?v=4","links":[{"icon":"github","link":"https://github.com/sorin-davidoi"}],"lastFetch":1723702319563},{"username":"scvnathan","name":"Nathan Schneirov","avatar":"https://avatars.githubusercontent.com/u/73474?v=4","links":[{"icon":"github","link":"https://github.com/scvnathan"}],"lastFetch":1723702319771},{"username":"lbenie","name":"Lucien Bénié","avatar":"https://avatars.githubusercontent.com/u/7316046?v=4","links":[{"icon":"github","link":"https://github.com/lbenie"}],"lastFetch":1723702319988},{"username":"bokub","name":"Boris K","avatar":"https://avatars.githubusercontent.com/u/17952318?v=4","links":[{"icon":"github","link":"https://github.com/bokub"}],"lastFetch":1723702320216},{"username":"antonk52","name":"Anton Kastritskii","avatar":"https://avatars.githubusercontent.com/u/5817809?v=4","links":[{"icon":"github","link":"https://github.com/antonk52"}],"lastFetch":1723702320434},{"username":"tshelburne","name":"Tim Shelburne","avatar":"https://avatars.githubusercontent.com/u/1202267?v=4","links":[{"icon":"github","link":"https://github.com/tshelburne"}],"lastFetch":1723702320732},{"username":"typeofweb","name":"Michał Miszczyszyn","avatar":"https://avatars.githubusercontent.com/u/1338731?v=4","links":[{"icon":"github","link":"https://github.com/typeofweb"}],"lastFetch":1723702321095},{"username":"skh-","name":"Sam K Hall","avatar":"https://avatars.githubusercontent.com/u/1292598?v=4","links":[{"icon":"github","link":"https://github.com/skh-"}],"lastFetch":1723702321408},{"username":"BlooJeans","name":"Matt Jeanes","avatar":"https://avatars.githubusercontent.com/u/1751182?v=4","links":[{"icon":"github","link":"https://github.com/BlooJeans"}],"lastFetch":1723702321708},{"username":"selbekk","name":"Kristofer Giltvedt Selbekk","avatar":"https://avatars.githubusercontent.com/u/1307267?v=4","links":[{"icon":"github","link":"https://github.com/selbekk"}],"lastFetch":1723702321922},{"username":"Mause","name":"Elliana May","avatar":"https://avatars.githubusercontent.com/u/1405026?v=4","links":[{"icon":"github","link":"https://github.com/Mause"}],"lastFetch":1723702322222},{"username":"henhal","name":"Henrik Hall","avatar":"https://avatars.githubusercontent.com/u/9608258?v=4","links":[{"icon":"github","link":"https://github.com/henhal"}],"lastFetch":1723702322532},{"username":"gr2m","name":"Gregor Martynus","avatar":"https://avatars.githubusercontent.com/u/39992?v=4","links":[{"icon":"github","link":"https://github.com/gr2m"}],"lastFetch":1723702322836},{"username":"samdbmg","name":"Sam Mesterton-Gibbons","avatar":"https://avatars.githubusercontent.com/u/408983?v=4","links":[{"icon":"github","link":"https://github.com/samdbmg"}],"lastFetch":1723702323177},{"username":"rendall","name":"Rendall","avatar":"https://avatars.githubusercontent.com/u/293263?v=4","links":[{"icon":"github","link":"https://github.com/rendall"}],"lastFetch":1723702323406},{"username":"robertmassaioli","name":"Robert Massaioli","avatar":"https://avatars.githubusercontent.com/u/149178?v=4","links":[{"icon":"github","link":"https://github.com/robertmassaioli"}],"lastFetch":1723702323622},{"username":"jankuca","name":"Jan Kuča","avatar":"https://avatars.githubusercontent.com/u/367262?v=4","links":[{"icon":"github","link":"https://github.com/jankuca"}],"lastFetch":1723702323953},{"username":"th-m","name":"Thomas Valadez","avatar":"https://avatars.githubusercontent.com/u/13792029?v=4","links":[{"icon":"github","link":"https://github.com/th-m"}],"lastFetch":1723702324162},{"username":"asithade","name":"Asitha de Silva","avatar":"https://avatars.githubusercontent.com/u/3814354?v=4","links":[{"icon":"github","link":"https://github.com/asithade"}],"lastFetch":1723702324375},{"username":"misha-erm","name":"Misha","avatar":"https://avatars.githubusercontent.com/u/8783498?v=4","links":[{"icon":"github","link":"https://github.com/misha-erm"}],"lastFetch":1723702324593},{"username":"radist2s","name":"Alex Batalov","avatar":"https://avatars.githubusercontent.com/u/725645?v=4","links":[{"icon":"github","link":"https://github.com/radist2s"}],"lastFetch":1723702324809},{"username":"FedeBev","name":"Federico Bevione","avatar":"https://avatars.githubusercontent.com/u/22151395?v=4","links":[{"icon":"github","link":"https://github.com/FedeBev"}],"lastFetch":1723702325111},{"username":"yamacent","name":"Daisuke Yamamoto","avatar":"https://avatars.githubusercontent.com/u/8544439?v=4","links":[{"icon":"github","link":"https://github.com/yamacent"}],"lastFetch":1723702325327},{"username":"dnalborczyk","name":null,"avatar":"https://avatars.githubusercontent.com/u/2903325?v=4","links":[{"icon":"github","link":"https://github.com/dnalborczyk"}],"lastFetch":1723702325600},{"username":"FabioWanner","name":null,"avatar":"https://avatars.githubusercontent.com/u/46821078?v=4","links":[{"icon":"github","link":"https://github.com/FabioWanner"}],"lastFetch":1723702325914},{"username":"ashsmith","name":"Ash Smith","avatar":"https://avatars.githubusercontent.com/u/1086841?v=4","links":[{"icon":"github","link":"https://github.com/ashsmith"}],"lastFetch":1723702326314},{"username":"mehalter","name":"Micah Halter","avatar":"https://avatars.githubusercontent.com/u/1591837?v=4","links":[{"icon":"github","link":"https://github.com/mehalter"}],"lastFetch":1723702326537},{"username":"Chrg1001","name":"chrg1001","avatar":"https://avatars.githubusercontent.com/u/40189653?v=4","links":[{"icon":"github","link":"https://github.com/Chrg1001"}],"lastFetch":1723702326933},{"username":"sharmarajdaksh","name":"Dakshraj Sharma","avatar":"https://avatars.githubusercontent.com/u/33689528?v=4","links":[{"icon":"github","link":"https://github.com/sharmarajdaksh"}],"lastFetch":1723702327137},{"username":"shuluster","name":"Shaosu Liu","avatar":"https://avatars.githubusercontent.com/u/1707910?v=4","links":[{"icon":"github","link":"https://github.com/shuluster"}],"lastFetch":1723702327464},{"username":"FDiskas","name":"Vytenis","avatar":"https://avatars.githubusercontent.com/u/468006?v=4","links":[{"icon":"github","link":"https://github.com/FDiskas"}],"lastFetch":1723702327699},{"username":"ericzorn93","name":"Eric Zorn","avatar":"https://avatars.githubusercontent.com/u/22532542?v=4","links":[{"icon":"github","link":"https://github.com/ericzorn93"}],"lastFetch":1723702327943},{"username":"mbelsky","name":"Max Belsky","avatar":"https://avatars.githubusercontent.com/u/3923527?v=4","links":[{"icon":"github","link":"https://github.com/mbelsky"}],"lastFetch":1723702328234},{"username":"techbech","name":"Peter Bech","avatar":"https://avatars.githubusercontent.com/u/1520592?v=4","links":[{"icon":"github","link":"https://github.com/techbech"}],"lastFetch":1723702328459},{"username":"rustyconover","name":"Rusty Conover","avatar":"https://avatars.githubusercontent.com/u/731941?v=4","links":[{"icon":"github","link":"https://github.com/rustyconover"}],"lastFetch":1723702328679},{"username":"bunkscene","name":"Dave Carlson","avatar":"https://avatars.githubusercontent.com/u/2693678?v=4","links":[{"icon":"github","link":"https://github.com/bunkscene"}],"lastFetch":1723702328903},{"username":"ottomated","name":null,"avatar":"https://avatars.githubusercontent.com/u/31470743?v=4","links":[{"icon":"github","link":"https://github.com/ottomated"}],"lastFetch":1723702329170},{"username":"sadfsdfdsa","name":"Artem Shuvaev","avatar":"https://avatars.githubusercontent.com/u/28733669?v=4","links":[{"icon":"github","link":"https://github.com/sadfsdfdsa"}],"lastFetch":1723702329455},{"username":"ajaishankar","name":null,"avatar":"https://avatars.githubusercontent.com/u/328008?v=4","links":[{"icon":"github","link":"https://github.com/ajaishankar"}],"lastFetch":1723702329798},{"username":"dominikdosoudil","name":"Dominik Dosoudil","avatar":"https://avatars.githubusercontent.com/u/15929942?v=4","links":[{"icon":"github","link":"https://github.com/dominikdosoudil"}],"lastFetch":1723702330207},{"username":"kgtkr","name":"kgtkr","avatar":"https://avatars.githubusercontent.com/u/17868838?v=4","links":[{"icon":"github","link":"https://github.com/kgtkr"}],"lastFetch":1723702330515},{"username":"berzi","name":null,"avatar":"https://avatars.githubusercontent.com/u/32619123?v=4","links":[{"icon":"github","link":"https://github.com/berzi"}],"lastFetch":1723702330924},{"username":"PhilipTrauner","name":"Philip Trauner","avatar":"https://avatars.githubusercontent.com/u/9287847?v=4","links":[{"icon":"github","link":"https://github.com/PhilipTrauner"}],"lastFetch":1723702331230},{"username":"Powell-v2","name":"Pavel Yermolin","avatar":"https://avatars.githubusercontent.com/u/25308326?v=4","links":[{"icon":"github","link":"https://github.com/Powell-v2"}],"lastFetch":1723702331539},{"username":"duncanbeevers","name":"Duncan Beevers","avatar":"https://avatars.githubusercontent.com/u/7367?v=4","links":[{"icon":"github","link":"https://github.com/duncanbeevers"}],"lastFetch":1723702331757},{"username":"tkukushkin","name":"Timofei Kukushkin","avatar":"https://avatars.githubusercontent.com/u/1482516?v=4","links":[{"icon":"github","link":"https://github.com/tkukushkin"}],"lastFetch":1723702332153},{"username":"Semigradsky","name":"Dmitry Semigradsky","avatar":"https://avatars.githubusercontent.com/u/1198848?v=4","links":[{"icon":"github","link":"https://github.com/Semigradsky"}],"lastFetch":1723702332564},{"username":"MrLeebo","name":"Jeremy Liberman","avatar":"https://avatars.githubusercontent.com/u/2754163?v=4","links":[{"icon":"github","link":"https://github.com/MrLeebo"}],"lastFetch":1723702332870},{"username":"axelhzf","name":"Axel Hernández Ferrera","avatar":"https://avatars.githubusercontent.com/u/175627?v=4","links":[{"icon":"github","link":"https://github.com/axelhzf"}],"lastFetch":1723702333082},{"username":"imagoiq","name":"Loïc Fürhoff","avatar":"https://avatars.githubusercontent.com/u/12294151?v=4","links":[{"icon":"github","link":"https://github.com/imagoiq"}],"lastFetch":1723702333374},{"username":"BTMPL","name":"Bartosz Szczeciński","avatar":"https://avatars.githubusercontent.com/u/247153?v=4","links":[{"icon":"github","link":"https://github.com/BTMPL"}],"lastFetch":1723702333668},{"username":"HiiiiD","name":"Marco Salomone","avatar":"https://avatars.githubusercontent.com/u/61231210?v=4","links":[{"icon":"github","link":"https://github.com/HiiiiD"}],"lastFetch":1723702333997},{"username":"yacinehmito","name":"Yacine Hmito","avatar":"https://avatars.githubusercontent.com/u/6893840?v=4","links":[{"icon":"github","link":"https://github.com/yacinehmito"}],"lastFetch":1723702334409},{"username":"sajadtorkamani","name":"Sajad Torkamani","avatar":"https://avatars.githubusercontent.com/u/9380313?v=4","links":[{"icon":"github","link":"https://github.com/sajadtorkamani"}],"lastFetch":1723702334714},{"username":"mvdbeek","name":"Marius van den Beek","avatar":"https://avatars.githubusercontent.com/u/6804901?v=4","links":[{"icon":"github","link":"https://github.com/mvdbeek"}],"lastFetch":1723702335043},{"username":"sgrimm","name":"Steven Grimm","avatar":"https://avatars.githubusercontent.com/u/1248649?v=4","links":[{"icon":"github","link":"https://github.com/sgrimm"}],"lastFetch":1723702335327},{"username":"Swiftwork","name":"Erik Hughes","avatar":"https://avatars.githubusercontent.com/u/455178?v=4","links":[{"icon":"github","link":"https://github.com/Swiftwork"}],"lastFetch":1723702335660},{"username":"mtth","name":"Matthieu Monsch","avatar":"https://avatars.githubusercontent.com/u/1216372?v=4","links":[{"icon":"github","link":"https://github.com/mtth"}],"lastFetch":1723702335942},{"username":"mitchell-merry","name":"Mitchell Merry","avatar":"https://avatars.githubusercontent.com/u/8567231?v=4","links":[{"icon":"github","link":"https://github.com/mitchell-merry"}],"lastFetch":1723702336348},{"username":"qnp","name":"François Risoud","avatar":"https://avatars.githubusercontent.com/u/6012554?v=4","links":[{"icon":"github","link":"https://github.com/qnp"}],"lastFetch":1723702336558},{"username":"shoffmeister","name":null,"avatar":"https://avatars.githubusercontent.com/u/3868036?v=4","links":[{"icon":"github","link":"https://github.com/shoffmeister"}],"lastFetch":1723702336771},{"username":"liangskyli","name":"liangsky","avatar":"https://avatars.githubusercontent.com/u/31531283?v=4","links":[{"icon":"github","link":"https://github.com/liangskyli"}],"lastFetch":1723702337067},{"username":"happycollision","name":"Don Denton","avatar":"https://avatars.githubusercontent.com/u/3663628?v=4","links":[{"icon":"github","link":"https://github.com/happycollision"}],"lastFetch":1723702337283},{"username":"ysmood","name":"Yad Smood","avatar":"https://avatars.githubusercontent.com/u/1415488?v=4","links":[{"icon":"github","link":"https://github.com/ysmood"}],"lastFetch":1723702337581},{"username":"barakalon","name":"barak","avatar":"https://avatars.githubusercontent.com/u/12398927?v=4","links":[{"icon":"github","link":"https://github.com/barakalon"}],"lastFetch":1723702337800},{"username":"horaklukas","name":"Lukáš Horák","avatar":"https://avatars.githubusercontent.com/u/996088?v=4","links":[{"icon":"github","link":"https://github.com/horaklukas"}],"lastFetch":1723702338090},{"username":"pvanagtmaal","name":null,"avatar":"https://avatars.githubusercontent.com/u/5946464?v=4","links":[{"icon":"github","link":"https://github.com/pvanagtmaal"}],"lastFetch":1723702338311},{"username":"toomuchdesign","name":"Andrea Carraro","avatar":"https://avatars.githubusercontent.com/u/4573549?v=4","links":[{"icon":"github","link":"https://github.com/toomuchdesign"}],"lastFetch":1723702338605},{"username":"psychedelicious","name":"psychedelicious","avatar":"https://avatars.githubusercontent.com/u/4822129?v=4","links":[{"icon":"github","link":"https://github.com/psychedelicious"}],"lastFetch":1723702338854},{"username":"tkrotoff","name":"Tanguy Krotoff","avatar":"https://avatars.githubusercontent.com/u/643434?v=4","links":[{"icon":"github","link":"https://github.com/tkrotoff"}],"lastFetch":1723702339067},{"username":"pimveldhuisen","name":"Pim Veldhuisen","avatar":"https://avatars.githubusercontent.com/u/3043834?v=4","links":[{"icon":"github","link":"https://github.com/pimveldhuisen"}],"lastFetch":1723702339321},{"username":"asvishnyakov","name":"Aleksandr Vishniakov","avatar":"https://avatars.githubusercontent.com/u/6369252?v=4","links":[{"icon":"github","link":"https://github.com/asvishnyakov"}],"lastFetch":1723702339731},{"username":"SchabaJo","name":null,"avatar":"https://avatars.githubusercontent.com/u/138689813?v=4","links":[{"icon":"github","link":"https://github.com/SchabaJo"}],"lastFetch":1723702340034},{"username":"AhsanFazal","name":"Ahsan Fazal","avatar":"https://avatars.githubusercontent.com/u/7458046?v=4","links":[{"icon":"github","link":"https://github.com/AhsanFazal"}],"lastFetch":1723702340447},{"username":"ElForastero","name":"Eugene Dzhumak","avatar":"https://avatars.githubusercontent.com/u/5102818?v=4","links":[{"icon":"github","link":"https://github.com/ElForastero"}],"lastFetch":1723702340857},{"username":"msgadi","name":"Mohammed Gadi","avatar":"https://avatars.githubusercontent.com/u/9037086?v=4","links":[{"icon":"github","link":"https://github.com/msgadi"}],"lastFetch":1723702341267},{"username":"muttonchop","name":"Adam K","avatar":"https://avatars.githubusercontent.com/u/1037657?v=4","links":[{"icon":"github","link":"https://github.com/muttonchop"}],"lastFetch":1723702341509},{"username":"christoph-fricke","name":"Christoph Fricke","avatar":"https://avatars.githubusercontent.com/u/23103835?v=4","links":[{"icon":"github","link":"https://github.com/christoph-fricke"}],"lastFetch":1723702341880},{"username":"JorrinKievit","name":"Jorrin","avatar":"https://avatars.githubusercontent.com/u/43169049?v=4","links":[{"icon":"github","link":"https://github.com/JorrinKievit"}],"lastFetch":1723702342291},{"username":"WickyNilliams","name":"Nick Williams","avatar":"https://avatars.githubusercontent.com/u/1091390?v=4","links":[{"icon":"github","link":"https://github.com/WickyNilliams"}],"lastFetch":1723702342662},{"username":"hrsh7th","name":"hrsh7th","avatar":"https://avatars.githubusercontent.com/u/629908?v=4","links":[{"icon":"github","link":"https://github.com/hrsh7th"}],"lastFetch":1723702342901},{"username":"davidleger95","name":"David Leger","avatar":"https://avatars.githubusercontent.com/u/10498708?v=4","links":[{"icon":"github","link":"https://github.com/davidleger95"}],"lastFetch":1723702343122},{"username":"phk422","name":"Hongkun Peng","avatar":"https://avatars.githubusercontent.com/u/59734322?v=4","links":[{"icon":"github","link":"https://github.com/phk422"}],"lastFetch":1723702343337},{"username":"mzronek","name":"Matthias Zronek","avatar":"https://avatars.githubusercontent.com/u/3847700?v=4","links":[{"icon":"github","link":"https://github.com/mzronek"}],"lastFetch":1723702343551},{"username":"raurfang","name":"Łukasz Wiśniewski","avatar":"https://avatars.githubusercontent.com/u/867241?v=4","links":[{"icon":"github","link":"https://github.com/raurfang"}],"lastFetch":1723702343761},{"username":"JeanRemiDelteil","name":"Jean-Rémi Delteil","avatar":"https://avatars.githubusercontent.com/u/9743907?v=4","links":[{"icon":"github","link":"https://github.com/JeanRemiDelteil"}],"lastFetch":1723702344053},{"username":"TzviPM","name":"Tzvi Melamed","avatar":"https://avatars.githubusercontent.com/u/1950680?v=4","links":[{"icon":"github","link":"https://github.com/TzviPM"}],"lastFetch":1723702344340},{"username":"LucaSchwan","name":"ehrenschwan","avatar":"https://avatars.githubusercontent.com/u/25820532?v=4","links":[{"icon":"github","link":"https://github.com/LucaSchwan"}],"lastFetch":1723702344647},{"username":"nzapponi","name":"Niccolo Zapponi","avatar":"https://avatars.githubusercontent.com/u/20582065?v=4","links":[{"icon":"github","link":"https://github.com/nzapponi"}],"lastFetch":1723702344887},{"username":"luchsamapparat","name":"Marvin Luchs","avatar":"https://avatars.githubusercontent.com/u/875017?v=4","links":[{"icon":"github","link":"https://github.com/luchsamapparat"}],"lastFetch":1723702345116},{"username":"nmacmunn","name":"Neil MacMunn","avatar":"https://avatars.githubusercontent.com/u/849964?v=4","links":[{"icon":"github","link":"https://github.com/nmacmunn"}],"lastFetch":1723702345464}],"openapi-fetch":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723702317423},{"username":"fergusean","name":null,"avatar":"https://avatars.githubusercontent.com/u/1029297?v=4","links":[{"icon":"github","link":"https://github.com/fergusean"}],"lastFetch":1723702317672},{"username":"shinzui","name":"Nadeem Bitar","avatar":"https://avatars.githubusercontent.com/u/519?v=4","links":[{"icon":"github","link":"https://github.com/shinzui"}],"lastFetch":1723702318032},{"username":"ezpuzz","name":"Emory Petermann","avatar":"https://avatars.githubusercontent.com/u/672182?v=4","links":[{"icon":"github","link":"https://github.com/ezpuzz"}],"lastFetch":1723702318271},{"username":"KotoriK","name":null,"avatar":"https://avatars.githubusercontent.com/u/52659125?v=4","links":[{"icon":"github","link":"https://github.com/KotoriK"}],"lastFetch":1723702318483},{"username":"fletchertyler914","name":"Tyler Fletcher","avatar":"https://avatars.githubusercontent.com/u/3344498?v=4","links":[{"icon":"github","link":"https://github.com/fletchertyler914"}],"lastFetch":1723702318787},{"username":"nholik","name":"Nicklos Holik","avatar":"https://avatars.githubusercontent.com/u/2022214?v=4","links":[{"icon":"github","link":"https://github.com/nholik"}],"lastFetch":1723702319025},{"username":"roj1512","name":null,"avatar":"https://avatars.githubusercontent.com/u/175297870?v=4","links":[{"icon":"github","link":"https://github.com/roj1512"}],"lastFetch":1723702319230},{"username":"nickcaballero","name":"Nick Caballero","avatar":"https://avatars.githubusercontent.com/u/355976?v=4","links":[{"icon":"github","link":"https://github.com/nickcaballero"}],"lastFetch":1723702319560},{"username":"hd-o","name":"Hadrian de Oliveira","avatar":"https://avatars.githubusercontent.com/u/58871222?v=4","links":[{"icon":"github","link":"https://github.com/hd-o"}],"lastFetch":1723702319854},{"username":"kecrily","name":"Percy Ma","avatar":"https://avatars.githubusercontent.com/u/45708948?v=4","links":[{"icon":"github","link":"https://github.com/kecrily"}],"lastFetch":1723702320123},{"username":"psychedelicious","name":"psychedelicious","avatar":"https://avatars.githubusercontent.com/u/4822129?v=4","links":[{"icon":"github","link":"https://github.com/psychedelicious"}],"lastFetch":1723702320432},{"username":"muttonchop","name":"Adam K","avatar":"https://avatars.githubusercontent.com/u/1037657?v=4","links":[{"icon":"github","link":"https://github.com/muttonchop"}],"lastFetch":1723702320746},{"username":"marcomuser","name":"Marco Muser","avatar":"https://avatars.githubusercontent.com/u/64737396?v=4","links":[{"icon":"github","link":"https://github.com/marcomuser"}],"lastFetch":1723702321093},{"username":"HugeLetters","name":"Evgenii Perminov","avatar":"https://avatars.githubusercontent.com/u/119697239?v=4","links":[{"icon":"github","link":"https://github.com/HugeLetters"}],"lastFetch":1723702321404},{"username":"Fumaz","name":"alex","avatar":"https://avatars.githubusercontent.com/u/45318608?v=4","links":[{"icon":"github","link":"https://github.com/Fumaz"}],"lastFetch":1723702321716},{"username":"darwish","name":"Mike Darwish","avatar":"https://avatars.githubusercontent.com/u/292570?v=4","links":[{"icon":"github","link":"https://github.com/darwish"}],"lastFetch":1723702322033},{"username":"kaechele","name":"Felix Kaechele","avatar":"https://avatars.githubusercontent.com/u/454490?v=4","links":[{"icon":"github","link":"https://github.com/kaechele"}],"lastFetch":1723702322332},{"username":"phk422","name":"Hongkun Peng","avatar":"https://avatars.githubusercontent.com/u/59734322?v=4","links":[{"icon":"github","link":"https://github.com/phk422"}],"lastFetch":1723702322616},{"username":"mikestopcontinues","name":"Mike Stop Continues","avatar":"https://avatars.githubusercontent.com/u/150434?v=4","links":[{"icon":"github","link":"https://github.com/mikestopcontinues"}],"lastFetch":1723702322919},{"username":"JE-Lee","name":"maurice","avatar":"https://avatars.githubusercontent.com/u/19794813?v=4","links":[{"icon":"github","link":"https://github.com/JE-Lee"}],"lastFetch":1723702323179},{"username":"vipentti","name":"Ville Penttinen","avatar":"https://avatars.githubusercontent.com/u/4726680?v=4","links":[{"icon":"github","link":"https://github.com/vipentti"}],"lastFetch":1723702323388},{"username":"armandabric","name":"Armand Abric","avatar":"https://avatars.githubusercontent.com/u/95120?v=4","links":[{"icon":"github","link":"https://github.com/armandabric"}],"lastFetch":1723702323685},{"username":"illright","name":"Lev Chelyadinov","avatar":"https://avatars.githubusercontent.com/u/15035286?v=4","links":[{"icon":"github","link":"https://github.com/illright"}],"lastFetch":1723702323896}],"openapi-react-query":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723702317353},{"username":"kerwanp","name":"Martin Paucot","avatar":"https://avatars.githubusercontent.com/u/36955373?v=4","links":[{"icon":"github","link":"https://github.com/kerwanp"}],"lastFetch":1723702317570},{"username":"yoshi2no","name":"yoshi2no","avatar":"https://avatars.githubusercontent.com/u/57059705?v=4","links":[{"icon":"github","link":"https://github.com/yoshi2no"}],"lastFetch":1723702318027}]} \ No newline at end of file From 01421c2e64b5fcb7ee2222102f3eee202f1e49cb Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Sat, 17 Aug 2024 02:11:49 +0900 Subject: [PATCH 22/24] docs(ja): update content, fix typo and links --- docs/.vitepress/ja.ts | 6 +- docs/data/contributors.json | 2 +- docs/ja/about.md | 2 +- docs/ja/advanced.md | 28 +- docs/ja/cli.md | 18 +- docs/ja/examples.md | 248 +++++++++++++++++- docs/ja/index.md | 2 +- docs/ja/introduction.md | 10 +- docs/ja/migration-guide.md | 12 +- docs/ja/node.md | 30 +-- docs/ja/openapi-fetch/api.md | 68 ++--- docs/ja/openapi-fetch/examples.md | 2 +- docs/ja/openapi-fetch/index.md | 25 +- docs/ja/openapi-react-query/index.md | 10 +- docs/ja/openapi-react-query/use-mutation.md | 12 +- docs/ja/openapi-react-query/use-query.md | 15 +- .../openapi-react-query/use-suspense-query.md | 12 +- docs/node.md | 2 +- 18 files changed, 369 insertions(+), 135 deletions(-) diff --git a/docs/.vitepress/ja.ts b/docs/.vitepress/ja.ts index b69da2bb4..c68e6eedf 100644 --- a/docs/.vitepress/ja.ts +++ b/docs/.vitepress/ja.ts @@ -46,7 +46,7 @@ export default defineConfig({ items: [ { text: "始める", link: "/ja/openapi-react-query/" }, { text: "useQuery", link: "/ja/openapi-react-query/use-query" }, - { text: "useMutation", link: "/ja/openapi-react-query/use-mutation " }, + { text: "useMutation", link: "/ja/openapi-react-query/use-mutation" }, { text: "useSuspenseQuery", link: "/ja/openapi-react-query/use-suspense-query" }, { text: "概要", link: "/ja/openapi-react-query/about" }, ], @@ -61,9 +61,11 @@ export default defineConfig({ outline: { label: "目次", }, + sidebarMenuLabel: "メニュー", + returnToTopLabel: "最上部に戻る", footer: { message: - 'MITライセンス に基づいて配布されています', + 'MITライセンス に基づいて配布されています。', }, }, }); diff --git a/docs/data/contributors.json b/docs/data/contributors.json index 9154a0f44..caa4d48c0 100644 --- a/docs/data/contributors.json +++ b/docs/data/contributors.json @@ -1 +1 @@ -{"openapi-typescript":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723702317349},{"username":"psmyrdek","name":"Przemek Smyrdek","avatar":"https://avatars.githubusercontent.com/u/6187417?v=4","links":[{"icon":"github","link":"https://github.com/psmyrdek"}],"lastFetch":1723702317647},{"username":"enmand","name":"Dan Enman","avatar":"https://avatars.githubusercontent.com/u/432487?v=4","links":[{"icon":"github","link":"https://github.com/enmand"}],"lastFetch":1723702318029},{"username":"atlefren","name":"Atle Frenvik Sveen","avatar":"https://avatars.githubusercontent.com/u/1829927?v=4","links":[{"icon":"github","link":"https://github.com/atlefren"}],"lastFetch":1723702318256},{"username":"tpdewolf","name":"Tim de Wolf","avatar":"https://avatars.githubusercontent.com/u/4455209?v=4","links":[{"icon":"github","link":"https://github.com/tpdewolf"}],"lastFetch":1723702318502},{"username":"tombarton","name":"Tom Barton","avatar":"https://avatars.githubusercontent.com/u/6222711?v=4","links":[{"icon":"github","link":"https://github.com/tombarton"}],"lastFetch":1723702318738},{"username":"svnv","name":"Sven Nicolai Viig","avatar":"https://avatars.githubusercontent.com/u/1080888?v=4","links":[{"icon":"github","link":"https://github.com/svnv"}],"lastFetch":1723702319217},{"username":"sorin-davidoi","name":"Sorin Davidoi","avatar":"https://avatars.githubusercontent.com/u/2109702?v=4","links":[{"icon":"github","link":"https://github.com/sorin-davidoi"}],"lastFetch":1723702319563},{"username":"scvnathan","name":"Nathan Schneirov","avatar":"https://avatars.githubusercontent.com/u/73474?v=4","links":[{"icon":"github","link":"https://github.com/scvnathan"}],"lastFetch":1723702319771},{"username":"lbenie","name":"Lucien Bénié","avatar":"https://avatars.githubusercontent.com/u/7316046?v=4","links":[{"icon":"github","link":"https://github.com/lbenie"}],"lastFetch":1723702319988},{"username":"bokub","name":"Boris K","avatar":"https://avatars.githubusercontent.com/u/17952318?v=4","links":[{"icon":"github","link":"https://github.com/bokub"}],"lastFetch":1723702320216},{"username":"antonk52","name":"Anton Kastritskii","avatar":"https://avatars.githubusercontent.com/u/5817809?v=4","links":[{"icon":"github","link":"https://github.com/antonk52"}],"lastFetch":1723702320434},{"username":"tshelburne","name":"Tim Shelburne","avatar":"https://avatars.githubusercontent.com/u/1202267?v=4","links":[{"icon":"github","link":"https://github.com/tshelburne"}],"lastFetch":1723702320732},{"username":"typeofweb","name":"Michał Miszczyszyn","avatar":"https://avatars.githubusercontent.com/u/1338731?v=4","links":[{"icon":"github","link":"https://github.com/typeofweb"}],"lastFetch":1723702321095},{"username":"skh-","name":"Sam K Hall","avatar":"https://avatars.githubusercontent.com/u/1292598?v=4","links":[{"icon":"github","link":"https://github.com/skh-"}],"lastFetch":1723702321408},{"username":"BlooJeans","name":"Matt Jeanes","avatar":"https://avatars.githubusercontent.com/u/1751182?v=4","links":[{"icon":"github","link":"https://github.com/BlooJeans"}],"lastFetch":1723702321708},{"username":"selbekk","name":"Kristofer Giltvedt Selbekk","avatar":"https://avatars.githubusercontent.com/u/1307267?v=4","links":[{"icon":"github","link":"https://github.com/selbekk"}],"lastFetch":1723702321922},{"username":"Mause","name":"Elliana May","avatar":"https://avatars.githubusercontent.com/u/1405026?v=4","links":[{"icon":"github","link":"https://github.com/Mause"}],"lastFetch":1723702322222},{"username":"henhal","name":"Henrik Hall","avatar":"https://avatars.githubusercontent.com/u/9608258?v=4","links":[{"icon":"github","link":"https://github.com/henhal"}],"lastFetch":1723702322532},{"username":"gr2m","name":"Gregor Martynus","avatar":"https://avatars.githubusercontent.com/u/39992?v=4","links":[{"icon":"github","link":"https://github.com/gr2m"}],"lastFetch":1723702322836},{"username":"samdbmg","name":"Sam Mesterton-Gibbons","avatar":"https://avatars.githubusercontent.com/u/408983?v=4","links":[{"icon":"github","link":"https://github.com/samdbmg"}],"lastFetch":1723702323177},{"username":"rendall","name":"Rendall","avatar":"https://avatars.githubusercontent.com/u/293263?v=4","links":[{"icon":"github","link":"https://github.com/rendall"}],"lastFetch":1723702323406},{"username":"robertmassaioli","name":"Robert Massaioli","avatar":"https://avatars.githubusercontent.com/u/149178?v=4","links":[{"icon":"github","link":"https://github.com/robertmassaioli"}],"lastFetch":1723702323622},{"username":"jankuca","name":"Jan Kuča","avatar":"https://avatars.githubusercontent.com/u/367262?v=4","links":[{"icon":"github","link":"https://github.com/jankuca"}],"lastFetch":1723702323953},{"username":"th-m","name":"Thomas Valadez","avatar":"https://avatars.githubusercontent.com/u/13792029?v=4","links":[{"icon":"github","link":"https://github.com/th-m"}],"lastFetch":1723702324162},{"username":"asithade","name":"Asitha de Silva","avatar":"https://avatars.githubusercontent.com/u/3814354?v=4","links":[{"icon":"github","link":"https://github.com/asithade"}],"lastFetch":1723702324375},{"username":"misha-erm","name":"Misha","avatar":"https://avatars.githubusercontent.com/u/8783498?v=4","links":[{"icon":"github","link":"https://github.com/misha-erm"}],"lastFetch":1723702324593},{"username":"radist2s","name":"Alex Batalov","avatar":"https://avatars.githubusercontent.com/u/725645?v=4","links":[{"icon":"github","link":"https://github.com/radist2s"}],"lastFetch":1723702324809},{"username":"FedeBev","name":"Federico Bevione","avatar":"https://avatars.githubusercontent.com/u/22151395?v=4","links":[{"icon":"github","link":"https://github.com/FedeBev"}],"lastFetch":1723702325111},{"username":"yamacent","name":"Daisuke Yamamoto","avatar":"https://avatars.githubusercontent.com/u/8544439?v=4","links":[{"icon":"github","link":"https://github.com/yamacent"}],"lastFetch":1723702325327},{"username":"dnalborczyk","name":null,"avatar":"https://avatars.githubusercontent.com/u/2903325?v=4","links":[{"icon":"github","link":"https://github.com/dnalborczyk"}],"lastFetch":1723702325600},{"username":"FabioWanner","name":null,"avatar":"https://avatars.githubusercontent.com/u/46821078?v=4","links":[{"icon":"github","link":"https://github.com/FabioWanner"}],"lastFetch":1723702325914},{"username":"ashsmith","name":"Ash Smith","avatar":"https://avatars.githubusercontent.com/u/1086841?v=4","links":[{"icon":"github","link":"https://github.com/ashsmith"}],"lastFetch":1723702326314},{"username":"mehalter","name":"Micah Halter","avatar":"https://avatars.githubusercontent.com/u/1591837?v=4","links":[{"icon":"github","link":"https://github.com/mehalter"}],"lastFetch":1723702326537},{"username":"Chrg1001","name":"chrg1001","avatar":"https://avatars.githubusercontent.com/u/40189653?v=4","links":[{"icon":"github","link":"https://github.com/Chrg1001"}],"lastFetch":1723702326933},{"username":"sharmarajdaksh","name":"Dakshraj Sharma","avatar":"https://avatars.githubusercontent.com/u/33689528?v=4","links":[{"icon":"github","link":"https://github.com/sharmarajdaksh"}],"lastFetch":1723702327137},{"username":"shuluster","name":"Shaosu Liu","avatar":"https://avatars.githubusercontent.com/u/1707910?v=4","links":[{"icon":"github","link":"https://github.com/shuluster"}],"lastFetch":1723702327464},{"username":"FDiskas","name":"Vytenis","avatar":"https://avatars.githubusercontent.com/u/468006?v=4","links":[{"icon":"github","link":"https://github.com/FDiskas"}],"lastFetch":1723702327699},{"username":"ericzorn93","name":"Eric Zorn","avatar":"https://avatars.githubusercontent.com/u/22532542?v=4","links":[{"icon":"github","link":"https://github.com/ericzorn93"}],"lastFetch":1723702327943},{"username":"mbelsky","name":"Max Belsky","avatar":"https://avatars.githubusercontent.com/u/3923527?v=4","links":[{"icon":"github","link":"https://github.com/mbelsky"}],"lastFetch":1723702328234},{"username":"techbech","name":"Peter Bech","avatar":"https://avatars.githubusercontent.com/u/1520592?v=4","links":[{"icon":"github","link":"https://github.com/techbech"}],"lastFetch":1723702328459},{"username":"rustyconover","name":"Rusty Conover","avatar":"https://avatars.githubusercontent.com/u/731941?v=4","links":[{"icon":"github","link":"https://github.com/rustyconover"}],"lastFetch":1723702328679},{"username":"bunkscene","name":"Dave Carlson","avatar":"https://avatars.githubusercontent.com/u/2693678?v=4","links":[{"icon":"github","link":"https://github.com/bunkscene"}],"lastFetch":1723702328903},{"username":"ottomated","name":null,"avatar":"https://avatars.githubusercontent.com/u/31470743?v=4","links":[{"icon":"github","link":"https://github.com/ottomated"}],"lastFetch":1723702329170},{"username":"sadfsdfdsa","name":"Artem Shuvaev","avatar":"https://avatars.githubusercontent.com/u/28733669?v=4","links":[{"icon":"github","link":"https://github.com/sadfsdfdsa"}],"lastFetch":1723702329455},{"username":"ajaishankar","name":null,"avatar":"https://avatars.githubusercontent.com/u/328008?v=4","links":[{"icon":"github","link":"https://github.com/ajaishankar"}],"lastFetch":1723702329798},{"username":"dominikdosoudil","name":"Dominik Dosoudil","avatar":"https://avatars.githubusercontent.com/u/15929942?v=4","links":[{"icon":"github","link":"https://github.com/dominikdosoudil"}],"lastFetch":1723702330207},{"username":"kgtkr","name":"kgtkr","avatar":"https://avatars.githubusercontent.com/u/17868838?v=4","links":[{"icon":"github","link":"https://github.com/kgtkr"}],"lastFetch":1723702330515},{"username":"berzi","name":null,"avatar":"https://avatars.githubusercontent.com/u/32619123?v=4","links":[{"icon":"github","link":"https://github.com/berzi"}],"lastFetch":1723702330924},{"username":"PhilipTrauner","name":"Philip Trauner","avatar":"https://avatars.githubusercontent.com/u/9287847?v=4","links":[{"icon":"github","link":"https://github.com/PhilipTrauner"}],"lastFetch":1723702331230},{"username":"Powell-v2","name":"Pavel Yermolin","avatar":"https://avatars.githubusercontent.com/u/25308326?v=4","links":[{"icon":"github","link":"https://github.com/Powell-v2"}],"lastFetch":1723702331539},{"username":"duncanbeevers","name":"Duncan Beevers","avatar":"https://avatars.githubusercontent.com/u/7367?v=4","links":[{"icon":"github","link":"https://github.com/duncanbeevers"}],"lastFetch":1723702331757},{"username":"tkukushkin","name":"Timofei Kukushkin","avatar":"https://avatars.githubusercontent.com/u/1482516?v=4","links":[{"icon":"github","link":"https://github.com/tkukushkin"}],"lastFetch":1723702332153},{"username":"Semigradsky","name":"Dmitry Semigradsky","avatar":"https://avatars.githubusercontent.com/u/1198848?v=4","links":[{"icon":"github","link":"https://github.com/Semigradsky"}],"lastFetch":1723702332564},{"username":"MrLeebo","name":"Jeremy Liberman","avatar":"https://avatars.githubusercontent.com/u/2754163?v=4","links":[{"icon":"github","link":"https://github.com/MrLeebo"}],"lastFetch":1723702332870},{"username":"axelhzf","name":"Axel Hernández Ferrera","avatar":"https://avatars.githubusercontent.com/u/175627?v=4","links":[{"icon":"github","link":"https://github.com/axelhzf"}],"lastFetch":1723702333082},{"username":"imagoiq","name":"Loïc Fürhoff","avatar":"https://avatars.githubusercontent.com/u/12294151?v=4","links":[{"icon":"github","link":"https://github.com/imagoiq"}],"lastFetch":1723702333374},{"username":"BTMPL","name":"Bartosz Szczeciński","avatar":"https://avatars.githubusercontent.com/u/247153?v=4","links":[{"icon":"github","link":"https://github.com/BTMPL"}],"lastFetch":1723702333668},{"username":"HiiiiD","name":"Marco Salomone","avatar":"https://avatars.githubusercontent.com/u/61231210?v=4","links":[{"icon":"github","link":"https://github.com/HiiiiD"}],"lastFetch":1723702333997},{"username":"yacinehmito","name":"Yacine Hmito","avatar":"https://avatars.githubusercontent.com/u/6893840?v=4","links":[{"icon":"github","link":"https://github.com/yacinehmito"}],"lastFetch":1723702334409},{"username":"sajadtorkamani","name":"Sajad Torkamani","avatar":"https://avatars.githubusercontent.com/u/9380313?v=4","links":[{"icon":"github","link":"https://github.com/sajadtorkamani"}],"lastFetch":1723702334714},{"username":"mvdbeek","name":"Marius van den Beek","avatar":"https://avatars.githubusercontent.com/u/6804901?v=4","links":[{"icon":"github","link":"https://github.com/mvdbeek"}],"lastFetch":1723702335043},{"username":"sgrimm","name":"Steven Grimm","avatar":"https://avatars.githubusercontent.com/u/1248649?v=4","links":[{"icon":"github","link":"https://github.com/sgrimm"}],"lastFetch":1723702335327},{"username":"Swiftwork","name":"Erik Hughes","avatar":"https://avatars.githubusercontent.com/u/455178?v=4","links":[{"icon":"github","link":"https://github.com/Swiftwork"}],"lastFetch":1723702335660},{"username":"mtth","name":"Matthieu Monsch","avatar":"https://avatars.githubusercontent.com/u/1216372?v=4","links":[{"icon":"github","link":"https://github.com/mtth"}],"lastFetch":1723702335942},{"username":"mitchell-merry","name":"Mitchell Merry","avatar":"https://avatars.githubusercontent.com/u/8567231?v=4","links":[{"icon":"github","link":"https://github.com/mitchell-merry"}],"lastFetch":1723702336348},{"username":"qnp","name":"François Risoud","avatar":"https://avatars.githubusercontent.com/u/6012554?v=4","links":[{"icon":"github","link":"https://github.com/qnp"}],"lastFetch":1723702336558},{"username":"shoffmeister","name":null,"avatar":"https://avatars.githubusercontent.com/u/3868036?v=4","links":[{"icon":"github","link":"https://github.com/shoffmeister"}],"lastFetch":1723702336771},{"username":"liangskyli","name":"liangsky","avatar":"https://avatars.githubusercontent.com/u/31531283?v=4","links":[{"icon":"github","link":"https://github.com/liangskyli"}],"lastFetch":1723702337067},{"username":"happycollision","name":"Don Denton","avatar":"https://avatars.githubusercontent.com/u/3663628?v=4","links":[{"icon":"github","link":"https://github.com/happycollision"}],"lastFetch":1723702337283},{"username":"ysmood","name":"Yad Smood","avatar":"https://avatars.githubusercontent.com/u/1415488?v=4","links":[{"icon":"github","link":"https://github.com/ysmood"}],"lastFetch":1723702337581},{"username":"barakalon","name":"barak","avatar":"https://avatars.githubusercontent.com/u/12398927?v=4","links":[{"icon":"github","link":"https://github.com/barakalon"}],"lastFetch":1723702337800},{"username":"horaklukas","name":"Lukáš Horák","avatar":"https://avatars.githubusercontent.com/u/996088?v=4","links":[{"icon":"github","link":"https://github.com/horaklukas"}],"lastFetch":1723702338090},{"username":"pvanagtmaal","name":null,"avatar":"https://avatars.githubusercontent.com/u/5946464?v=4","links":[{"icon":"github","link":"https://github.com/pvanagtmaal"}],"lastFetch":1723702338311},{"username":"toomuchdesign","name":"Andrea Carraro","avatar":"https://avatars.githubusercontent.com/u/4573549?v=4","links":[{"icon":"github","link":"https://github.com/toomuchdesign"}],"lastFetch":1723702338605},{"username":"psychedelicious","name":"psychedelicious","avatar":"https://avatars.githubusercontent.com/u/4822129?v=4","links":[{"icon":"github","link":"https://github.com/psychedelicious"}],"lastFetch":1723702338854},{"username":"tkrotoff","name":"Tanguy Krotoff","avatar":"https://avatars.githubusercontent.com/u/643434?v=4","links":[{"icon":"github","link":"https://github.com/tkrotoff"}],"lastFetch":1723702339067},{"username":"pimveldhuisen","name":"Pim Veldhuisen","avatar":"https://avatars.githubusercontent.com/u/3043834?v=4","links":[{"icon":"github","link":"https://github.com/pimveldhuisen"}],"lastFetch":1723702339321},{"username":"asvishnyakov","name":"Aleksandr Vishniakov","avatar":"https://avatars.githubusercontent.com/u/6369252?v=4","links":[{"icon":"github","link":"https://github.com/asvishnyakov"}],"lastFetch":1723702339731},{"username":"SchabaJo","name":null,"avatar":"https://avatars.githubusercontent.com/u/138689813?v=4","links":[{"icon":"github","link":"https://github.com/SchabaJo"}],"lastFetch":1723702340034},{"username":"AhsanFazal","name":"Ahsan Fazal","avatar":"https://avatars.githubusercontent.com/u/7458046?v=4","links":[{"icon":"github","link":"https://github.com/AhsanFazal"}],"lastFetch":1723702340447},{"username":"ElForastero","name":"Eugene Dzhumak","avatar":"https://avatars.githubusercontent.com/u/5102818?v=4","links":[{"icon":"github","link":"https://github.com/ElForastero"}],"lastFetch":1723702340857},{"username":"msgadi","name":"Mohammed Gadi","avatar":"https://avatars.githubusercontent.com/u/9037086?v=4","links":[{"icon":"github","link":"https://github.com/msgadi"}],"lastFetch":1723702341267},{"username":"muttonchop","name":"Adam K","avatar":"https://avatars.githubusercontent.com/u/1037657?v=4","links":[{"icon":"github","link":"https://github.com/muttonchop"}],"lastFetch":1723702341509},{"username":"christoph-fricke","name":"Christoph Fricke","avatar":"https://avatars.githubusercontent.com/u/23103835?v=4","links":[{"icon":"github","link":"https://github.com/christoph-fricke"}],"lastFetch":1723702341880},{"username":"JorrinKievit","name":"Jorrin","avatar":"https://avatars.githubusercontent.com/u/43169049?v=4","links":[{"icon":"github","link":"https://github.com/JorrinKievit"}],"lastFetch":1723702342291},{"username":"WickyNilliams","name":"Nick Williams","avatar":"https://avatars.githubusercontent.com/u/1091390?v=4","links":[{"icon":"github","link":"https://github.com/WickyNilliams"}],"lastFetch":1723702342662},{"username":"hrsh7th","name":"hrsh7th","avatar":"https://avatars.githubusercontent.com/u/629908?v=4","links":[{"icon":"github","link":"https://github.com/hrsh7th"}],"lastFetch":1723702342901},{"username":"davidleger95","name":"David Leger","avatar":"https://avatars.githubusercontent.com/u/10498708?v=4","links":[{"icon":"github","link":"https://github.com/davidleger95"}],"lastFetch":1723702343122},{"username":"phk422","name":"Hongkun Peng","avatar":"https://avatars.githubusercontent.com/u/59734322?v=4","links":[{"icon":"github","link":"https://github.com/phk422"}],"lastFetch":1723702343337},{"username":"mzronek","name":"Matthias Zronek","avatar":"https://avatars.githubusercontent.com/u/3847700?v=4","links":[{"icon":"github","link":"https://github.com/mzronek"}],"lastFetch":1723702343551},{"username":"raurfang","name":"Łukasz Wiśniewski","avatar":"https://avatars.githubusercontent.com/u/867241?v=4","links":[{"icon":"github","link":"https://github.com/raurfang"}],"lastFetch":1723702343761},{"username":"JeanRemiDelteil","name":"Jean-Rémi Delteil","avatar":"https://avatars.githubusercontent.com/u/9743907?v=4","links":[{"icon":"github","link":"https://github.com/JeanRemiDelteil"}],"lastFetch":1723702344053},{"username":"TzviPM","name":"Tzvi Melamed","avatar":"https://avatars.githubusercontent.com/u/1950680?v=4","links":[{"icon":"github","link":"https://github.com/TzviPM"}],"lastFetch":1723702344340},{"username":"LucaSchwan","name":"ehrenschwan","avatar":"https://avatars.githubusercontent.com/u/25820532?v=4","links":[{"icon":"github","link":"https://github.com/LucaSchwan"}],"lastFetch":1723702344647},{"username":"nzapponi","name":"Niccolo Zapponi","avatar":"https://avatars.githubusercontent.com/u/20582065?v=4","links":[{"icon":"github","link":"https://github.com/nzapponi"}],"lastFetch":1723702344887},{"username":"luchsamapparat","name":"Marvin Luchs","avatar":"https://avatars.githubusercontent.com/u/875017?v=4","links":[{"icon":"github","link":"https://github.com/luchsamapparat"}],"lastFetch":1723702345116},{"username":"nmacmunn","name":"Neil MacMunn","avatar":"https://avatars.githubusercontent.com/u/849964?v=4","links":[{"icon":"github","link":"https://github.com/nmacmunn"}],"lastFetch":1723702345464}],"openapi-fetch":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723702317423},{"username":"fergusean","name":null,"avatar":"https://avatars.githubusercontent.com/u/1029297?v=4","links":[{"icon":"github","link":"https://github.com/fergusean"}],"lastFetch":1723702317672},{"username":"shinzui","name":"Nadeem Bitar","avatar":"https://avatars.githubusercontent.com/u/519?v=4","links":[{"icon":"github","link":"https://github.com/shinzui"}],"lastFetch":1723702318032},{"username":"ezpuzz","name":"Emory Petermann","avatar":"https://avatars.githubusercontent.com/u/672182?v=4","links":[{"icon":"github","link":"https://github.com/ezpuzz"}],"lastFetch":1723702318271},{"username":"KotoriK","name":null,"avatar":"https://avatars.githubusercontent.com/u/52659125?v=4","links":[{"icon":"github","link":"https://github.com/KotoriK"}],"lastFetch":1723702318483},{"username":"fletchertyler914","name":"Tyler Fletcher","avatar":"https://avatars.githubusercontent.com/u/3344498?v=4","links":[{"icon":"github","link":"https://github.com/fletchertyler914"}],"lastFetch":1723702318787},{"username":"nholik","name":"Nicklos Holik","avatar":"https://avatars.githubusercontent.com/u/2022214?v=4","links":[{"icon":"github","link":"https://github.com/nholik"}],"lastFetch":1723702319025},{"username":"roj1512","name":null,"avatar":"https://avatars.githubusercontent.com/u/175297870?v=4","links":[{"icon":"github","link":"https://github.com/roj1512"}],"lastFetch":1723702319230},{"username":"nickcaballero","name":"Nick Caballero","avatar":"https://avatars.githubusercontent.com/u/355976?v=4","links":[{"icon":"github","link":"https://github.com/nickcaballero"}],"lastFetch":1723702319560},{"username":"hd-o","name":"Hadrian de Oliveira","avatar":"https://avatars.githubusercontent.com/u/58871222?v=4","links":[{"icon":"github","link":"https://github.com/hd-o"}],"lastFetch":1723702319854},{"username":"kecrily","name":"Percy Ma","avatar":"https://avatars.githubusercontent.com/u/45708948?v=4","links":[{"icon":"github","link":"https://github.com/kecrily"}],"lastFetch":1723702320123},{"username":"psychedelicious","name":"psychedelicious","avatar":"https://avatars.githubusercontent.com/u/4822129?v=4","links":[{"icon":"github","link":"https://github.com/psychedelicious"}],"lastFetch":1723702320432},{"username":"muttonchop","name":"Adam K","avatar":"https://avatars.githubusercontent.com/u/1037657?v=4","links":[{"icon":"github","link":"https://github.com/muttonchop"}],"lastFetch":1723702320746},{"username":"marcomuser","name":"Marco Muser","avatar":"https://avatars.githubusercontent.com/u/64737396?v=4","links":[{"icon":"github","link":"https://github.com/marcomuser"}],"lastFetch":1723702321093},{"username":"HugeLetters","name":"Evgenii Perminov","avatar":"https://avatars.githubusercontent.com/u/119697239?v=4","links":[{"icon":"github","link":"https://github.com/HugeLetters"}],"lastFetch":1723702321404},{"username":"Fumaz","name":"alex","avatar":"https://avatars.githubusercontent.com/u/45318608?v=4","links":[{"icon":"github","link":"https://github.com/Fumaz"}],"lastFetch":1723702321716},{"username":"darwish","name":"Mike Darwish","avatar":"https://avatars.githubusercontent.com/u/292570?v=4","links":[{"icon":"github","link":"https://github.com/darwish"}],"lastFetch":1723702322033},{"username":"kaechele","name":"Felix Kaechele","avatar":"https://avatars.githubusercontent.com/u/454490?v=4","links":[{"icon":"github","link":"https://github.com/kaechele"}],"lastFetch":1723702322332},{"username":"phk422","name":"Hongkun Peng","avatar":"https://avatars.githubusercontent.com/u/59734322?v=4","links":[{"icon":"github","link":"https://github.com/phk422"}],"lastFetch":1723702322616},{"username":"mikestopcontinues","name":"Mike Stop Continues","avatar":"https://avatars.githubusercontent.com/u/150434?v=4","links":[{"icon":"github","link":"https://github.com/mikestopcontinues"}],"lastFetch":1723702322919},{"username":"JE-Lee","name":"maurice","avatar":"https://avatars.githubusercontent.com/u/19794813?v=4","links":[{"icon":"github","link":"https://github.com/JE-Lee"}],"lastFetch":1723702323179},{"username":"vipentti","name":"Ville Penttinen","avatar":"https://avatars.githubusercontent.com/u/4726680?v=4","links":[{"icon":"github","link":"https://github.com/vipentti"}],"lastFetch":1723702323388},{"username":"armandabric","name":"Armand Abric","avatar":"https://avatars.githubusercontent.com/u/95120?v=4","links":[{"icon":"github","link":"https://github.com/armandabric"}],"lastFetch":1723702323685},{"username":"illright","name":"Lev Chelyadinov","avatar":"https://avatars.githubusercontent.com/u/15035286?v=4","links":[{"icon":"github","link":"https://github.com/illright"}],"lastFetch":1723702323896}],"openapi-react-query":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723702317353},{"username":"kerwanp","name":"Martin Paucot","avatar":"https://avatars.githubusercontent.com/u/36955373?v=4","links":[{"icon":"github","link":"https://github.com/kerwanp"}],"lastFetch":1723702317570},{"username":"yoshi2no","name":"yoshi2no","avatar":"https://avatars.githubusercontent.com/u/57059705?v=4","links":[{"icon":"github","link":"https://github.com/yoshi2no"}],"lastFetch":1723702318027}]} \ No newline at end of file +{"openapi-typescript":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723808362280},{"username":"psmyrdek","name":"Przemek Smyrdek","avatar":"https://avatars.githubusercontent.com/u/6187417?v=4","links":[{"icon":"github","link":"https://github.com/psmyrdek"}],"lastFetch":1723808362561},{"username":"enmand","name":"Dan Enman","avatar":"https://avatars.githubusercontent.com/u/432487?v=4","links":[{"icon":"github","link":"https://github.com/enmand"}],"lastFetch":1723808362780},{"username":"atlefren","name":"Atle Frenvik Sveen","avatar":"https://avatars.githubusercontent.com/u/1829927?v=4","links":[{"icon":"github","link":"https://github.com/atlefren"}],"lastFetch":1723808363086},{"username":"tpdewolf","name":"Tim de Wolf","avatar":"https://avatars.githubusercontent.com/u/4455209?v=4","links":[{"icon":"github","link":"https://github.com/tpdewolf"}],"lastFetch":1723808363328},{"username":"tombarton","name":"Tom Barton","avatar":"https://avatars.githubusercontent.com/u/6222711?v=4","links":[{"icon":"github","link":"https://github.com/tombarton"}],"lastFetch":1723808363565},{"username":"svnv","name":"Sven Nicolai Viig","avatar":"https://avatars.githubusercontent.com/u/1080888?v=4","links":[{"icon":"github","link":"https://github.com/svnv"}],"lastFetch":1723808363793},{"username":"sorin-davidoi","name":"Sorin Davidoi","avatar":"https://avatars.githubusercontent.com/u/2109702?v=4","links":[{"icon":"github","link":"https://github.com/sorin-davidoi"}],"lastFetch":1723808364053},{"username":"scvnathan","name":"Nathan Schneirov","avatar":"https://avatars.githubusercontent.com/u/73474?v=4","links":[{"icon":"github","link":"https://github.com/scvnathan"}],"lastFetch":1723808364295},{"username":"lbenie","name":"Lucien Bénié","avatar":"https://avatars.githubusercontent.com/u/7316046?v=4","links":[{"icon":"github","link":"https://github.com/lbenie"}],"lastFetch":1723808364521},{"username":"bokub","name":"Boris K","avatar":"https://avatars.githubusercontent.com/u/17952318?v=4","links":[{"icon":"github","link":"https://github.com/bokub"}],"lastFetch":1723808364735},{"username":"antonk52","name":"Anton Kastritskii","avatar":"https://avatars.githubusercontent.com/u/5817809?v=4","links":[{"icon":"github","link":"https://github.com/antonk52"}],"lastFetch":1723808364955},{"username":"tshelburne","name":"Tim Shelburne","avatar":"https://avatars.githubusercontent.com/u/1202267?v=4","links":[{"icon":"github","link":"https://github.com/tshelburne"}],"lastFetch":1723808365180},{"username":"typeofweb","name":"Michał Miszczyszyn","avatar":"https://avatars.githubusercontent.com/u/1338731?v=4","links":[{"icon":"github","link":"https://github.com/typeofweb"}],"lastFetch":1723808365522},{"username":"skh-","name":"Sam K Hall","avatar":"https://avatars.githubusercontent.com/u/1292598?v=4","links":[{"icon":"github","link":"https://github.com/skh-"}],"lastFetch":1723808365828},{"username":"BlooJeans","name":"Matt Jeanes","avatar":"https://avatars.githubusercontent.com/u/1751182?v=4","links":[{"icon":"github","link":"https://github.com/BlooJeans"}],"lastFetch":1723808366132},{"username":"selbekk","name":"Kristofer Giltvedt Selbekk","avatar":"https://avatars.githubusercontent.com/u/1307267?v=4","links":[{"icon":"github","link":"https://github.com/selbekk"}],"lastFetch":1723808366365},{"username":"Mause","name":"Elliana May","avatar":"https://avatars.githubusercontent.com/u/1405026?v=4","links":[{"icon":"github","link":"https://github.com/Mause"}],"lastFetch":1723808366687},{"username":"henhal","name":"Henrik Hall","avatar":"https://avatars.githubusercontent.com/u/9608258?v=4","links":[{"icon":"github","link":"https://github.com/henhal"}],"lastFetch":1723808366980},{"username":"gr2m","name":"Gregor Martynus","avatar":"https://avatars.githubusercontent.com/u/39992?v=4","links":[{"icon":"github","link":"https://github.com/gr2m"}],"lastFetch":1723808367210},{"username":"samdbmg","name":"Sam Mesterton-Gibbons","avatar":"https://avatars.githubusercontent.com/u/408983?v=4","links":[{"icon":"github","link":"https://github.com/samdbmg"}],"lastFetch":1723808367428},{"username":"rendall","name":"Rendall","avatar":"https://avatars.githubusercontent.com/u/293263?v=4","links":[{"icon":"github","link":"https://github.com/rendall"}],"lastFetch":1723808367636},{"username":"robertmassaioli","name":"Robert Massaioli","avatar":"https://avatars.githubusercontent.com/u/149178?v=4","links":[{"icon":"github","link":"https://github.com/robertmassaioli"}],"lastFetch":1723808367925},{"username":"jankuca","name":"Jan Kuča","avatar":"https://avatars.githubusercontent.com/u/367262?v=4","links":[{"icon":"github","link":"https://github.com/jankuca"}],"lastFetch":1723808368207},{"username":"th-m","name":"Thomas Valadez","avatar":"https://avatars.githubusercontent.com/u/13792029?v=4","links":[{"icon":"github","link":"https://github.com/th-m"}],"lastFetch":1723808368515},{"username":"asithade","name":"Asitha de Silva","avatar":"https://avatars.githubusercontent.com/u/3814354?v=4","links":[{"icon":"github","link":"https://github.com/asithade"}],"lastFetch":1723808368811},{"username":"misha-erm","name":"Misha","avatar":"https://avatars.githubusercontent.com/u/8783498?v=4","links":[{"icon":"github","link":"https://github.com/misha-erm"}],"lastFetch":1723808369027},{"username":"radist2s","name":"Alex Batalov","avatar":"https://avatars.githubusercontent.com/u/725645?v=4","links":[{"icon":"github","link":"https://github.com/radist2s"}],"lastFetch":1723808369252},{"username":"FedeBev","name":"Federico Bevione","avatar":"https://avatars.githubusercontent.com/u/22151395?v=4","links":[{"icon":"github","link":"https://github.com/FedeBev"}],"lastFetch":1723808369486},{"username":"yamacent","name":"Daisuke Yamamoto","avatar":"https://avatars.githubusercontent.com/u/8544439?v=4","links":[{"icon":"github","link":"https://github.com/yamacent"}],"lastFetch":1723808369694},{"username":"dnalborczyk","name":null,"avatar":"https://avatars.githubusercontent.com/u/2903325?v=4","links":[{"icon":"github","link":"https://github.com/dnalborczyk"}],"lastFetch":1723808369907},{"username":"FabioWanner","name":null,"avatar":"https://avatars.githubusercontent.com/u/46821078?v=4","links":[{"icon":"github","link":"https://github.com/FabioWanner"}],"lastFetch":1723808370122},{"username":"ashsmith","name":"Ash Smith","avatar":"https://avatars.githubusercontent.com/u/1086841?v=4","links":[{"icon":"github","link":"https://github.com/ashsmith"}],"lastFetch":1723808370449},{"username":"mehalter","name":"Micah Halter","avatar":"https://avatars.githubusercontent.com/u/1591837?v=4","links":[{"icon":"github","link":"https://github.com/mehalter"}],"lastFetch":1723808370687},{"username":"Chrg1001","name":"chrg1001","avatar":"https://avatars.githubusercontent.com/u/40189653?v=4","links":[{"icon":"github","link":"https://github.com/Chrg1001"}],"lastFetch":1723808370979},{"username":"sharmarajdaksh","name":"Dakshraj Sharma","avatar":"https://avatars.githubusercontent.com/u/33689528?v=4","links":[{"icon":"github","link":"https://github.com/sharmarajdaksh"}],"lastFetch":1723808371207},{"username":"shuluster","name":"Shaosu Liu","avatar":"https://avatars.githubusercontent.com/u/1707910?v=4","links":[{"icon":"github","link":"https://github.com/shuluster"}],"lastFetch":1723808371559},{"username":"FDiskas","name":"Vytenis","avatar":"https://avatars.githubusercontent.com/u/468006?v=4","links":[{"icon":"github","link":"https://github.com/FDiskas"}],"lastFetch":1723808371791},{"username":"ericzorn93","name":"Eric Zorn","avatar":"https://avatars.githubusercontent.com/u/22532542?v=4","links":[{"icon":"github","link":"https://github.com/ericzorn93"}],"lastFetch":1723808372098},{"username":"mbelsky","name":"Max Belsky","avatar":"https://avatars.githubusercontent.com/u/3923527?v=4","links":[{"icon":"github","link":"https://github.com/mbelsky"}],"lastFetch":1723808372406},{"username":"techbech","name":"Peter Bech","avatar":"https://avatars.githubusercontent.com/u/1520592?v=4","links":[{"icon":"github","link":"https://github.com/techbech"}],"lastFetch":1723808372627},{"username":"rustyconover","name":"Rusty Conover","avatar":"https://avatars.githubusercontent.com/u/731941?v=4","links":[{"icon":"github","link":"https://github.com/rustyconover"}],"lastFetch":1723808372848},{"username":"bunkscene","name":"Dave Carlson","avatar":"https://avatars.githubusercontent.com/u/2693678?v=4","links":[{"icon":"github","link":"https://github.com/bunkscene"}],"lastFetch":1723808373077},{"username":"ottomated","name":null,"avatar":"https://avatars.githubusercontent.com/u/31470743?v=4","links":[{"icon":"github","link":"https://github.com/ottomated"}],"lastFetch":1723808373298},{"username":"sadfsdfdsa","name":"Artem Shuvaev","avatar":"https://avatars.githubusercontent.com/u/28733669?v=4","links":[{"icon":"github","link":"https://github.com/sadfsdfdsa"}],"lastFetch":1723808373512},{"username":"ajaishankar","name":null,"avatar":"https://avatars.githubusercontent.com/u/328008?v=4","links":[{"icon":"github","link":"https://github.com/ajaishankar"}],"lastFetch":1723808373737},{"username":"dominikdosoudil","name":"Dominik Dosoudil","avatar":"https://avatars.githubusercontent.com/u/15929942?v=4","links":[{"icon":"github","link":"https://github.com/dominikdosoudil"}],"lastFetch":1723808373955},{"username":"kgtkr","name":"kgtkr","avatar":"https://avatars.githubusercontent.com/u/17868838?v=4","links":[{"icon":"github","link":"https://github.com/kgtkr"}],"lastFetch":1723808374281},{"username":"berzi","name":null,"avatar":"https://avatars.githubusercontent.com/u/32619123?v=4","links":[{"icon":"github","link":"https://github.com/berzi"}],"lastFetch":1723808374532},{"username":"PhilipTrauner","name":"Philip Trauner","avatar":"https://avatars.githubusercontent.com/u/9287847?v=4","links":[{"icon":"github","link":"https://github.com/PhilipTrauner"}],"lastFetch":1723808374754},{"username":"Powell-v2","name":"Pavel Yermolin","avatar":"https://avatars.githubusercontent.com/u/25308326?v=4","links":[{"icon":"github","link":"https://github.com/Powell-v2"}],"lastFetch":1723808374966},{"username":"duncanbeevers","name":"Duncan Beevers","avatar":"https://avatars.githubusercontent.com/u/7367?v=4","links":[{"icon":"github","link":"https://github.com/duncanbeevers"}],"lastFetch":1723808375228},{"username":"tkukushkin","name":"Timofei Kukushkin","avatar":"https://avatars.githubusercontent.com/u/1482516?v=4","links":[{"icon":"github","link":"https://github.com/tkukushkin"}],"lastFetch":1723808375535},{"username":"Semigradsky","name":"Dmitry Semigradsky","avatar":"https://avatars.githubusercontent.com/u/1198848?v=4","links":[{"icon":"github","link":"https://github.com/Semigradsky"}],"lastFetch":1723808375742},{"username":"MrLeebo","name":"Jeremy Liberman","avatar":"https://avatars.githubusercontent.com/u/2754163?v=4","links":[{"icon":"github","link":"https://github.com/MrLeebo"}],"lastFetch":1723808376036},{"username":"axelhzf","name":"Axel Hernández Ferrera","avatar":"https://avatars.githubusercontent.com/u/175627?v=4","links":[{"icon":"github","link":"https://github.com/axelhzf"}],"lastFetch":1723808376331},{"username":"imagoiq","name":"Loïc Fürhoff","avatar":"https://avatars.githubusercontent.com/u/12294151?v=4","links":[{"icon":"github","link":"https://github.com/imagoiq"}],"lastFetch":1723808376552},{"username":"BTMPL","name":"Bartosz Szczeciński","avatar":"https://avatars.githubusercontent.com/u/247153?v=4","links":[{"icon":"github","link":"https://github.com/BTMPL"}],"lastFetch":1723808376882},{"username":"HiiiiD","name":"Marco Salomone","avatar":"https://avatars.githubusercontent.com/u/61231210?v=4","links":[{"icon":"github","link":"https://github.com/HiiiiD"}],"lastFetch":1723808377118},{"username":"yacinehmito","name":"Yacine Hmito","avatar":"https://avatars.githubusercontent.com/u/6893840?v=4","links":[{"icon":"github","link":"https://github.com/yacinehmito"}],"lastFetch":1723808377419},{"username":"sajadtorkamani","name":"Sajad Torkamani","avatar":"https://avatars.githubusercontent.com/u/9380313?v=4","links":[{"icon":"github","link":"https://github.com/sajadtorkamani"}],"lastFetch":1723808377642},{"username":"mvdbeek","name":"Marius van den Beek","avatar":"https://avatars.githubusercontent.com/u/6804901?v=4","links":[{"icon":"github","link":"https://github.com/mvdbeek"}],"lastFetch":1723808377864},{"username":"sgrimm","name":"Steven Grimm","avatar":"https://avatars.githubusercontent.com/u/1248649?v=4","links":[{"icon":"github","link":"https://github.com/sgrimm"}],"lastFetch":1723808378080},{"username":"Swiftwork","name":"Erik Hughes","avatar":"https://avatars.githubusercontent.com/u/455178?v=4","links":[{"icon":"github","link":"https://github.com/Swiftwork"}],"lastFetch":1723808378296},{"username":"mtth","name":"Matthieu Monsch","avatar":"https://avatars.githubusercontent.com/u/1216372?v=4","links":[{"icon":"github","link":"https://github.com/mtth"}],"lastFetch":1723808378607},{"username":"mitchell-merry","name":"Mitchell Merry","avatar":"https://avatars.githubusercontent.com/u/8567231?v=4","links":[{"icon":"github","link":"https://github.com/mitchell-merry"}],"lastFetch":1723808378852},{"username":"qnp","name":"François Risoud","avatar":"https://avatars.githubusercontent.com/u/6012554?v=4","links":[{"icon":"github","link":"https://github.com/qnp"}],"lastFetch":1723808379074},{"username":"shoffmeister","name":null,"avatar":"https://avatars.githubusercontent.com/u/3868036?v=4","links":[{"icon":"github","link":"https://github.com/shoffmeister"}],"lastFetch":1723808379419},{"username":"liangskyli","name":"liangsky","avatar":"https://avatars.githubusercontent.com/u/31531283?v=4","links":[{"icon":"github","link":"https://github.com/liangskyli"}],"lastFetch":1723808379645},{"username":"happycollision","name":"Don Denton","avatar":"https://avatars.githubusercontent.com/u/3663628?v=4","links":[{"icon":"github","link":"https://github.com/happycollision"}],"lastFetch":1723808379888},{"username":"ysmood","name":"Yad Smood","avatar":"https://avatars.githubusercontent.com/u/1415488?v=4","links":[{"icon":"github","link":"https://github.com/ysmood"}],"lastFetch":1723808380145},{"username":"barakalon","name":"barak","avatar":"https://avatars.githubusercontent.com/u/12398927?v=4","links":[{"icon":"github","link":"https://github.com/barakalon"}],"lastFetch":1723808380442},{"username":"horaklukas","name":"Lukáš Horák","avatar":"https://avatars.githubusercontent.com/u/996088?v=4","links":[{"icon":"github","link":"https://github.com/horaklukas"}],"lastFetch":1723808380807},{"username":"pvanagtmaal","name":null,"avatar":"https://avatars.githubusercontent.com/u/5946464?v=4","links":[{"icon":"github","link":"https://github.com/pvanagtmaal"}],"lastFetch":1723808381048},{"username":"toomuchdesign","name":"Andrea Carraro","avatar":"https://avatars.githubusercontent.com/u/4573549?v=4","links":[{"icon":"github","link":"https://github.com/toomuchdesign"}],"lastFetch":1723808381268},{"username":"psychedelicious","name":"psychedelicious","avatar":"https://avatars.githubusercontent.com/u/4822129?v=4","links":[{"icon":"github","link":"https://github.com/psychedelicious"}],"lastFetch":1723808381483},{"username":"tkrotoff","name":"Tanguy Krotoff","avatar":"https://avatars.githubusercontent.com/u/643434?v=4","links":[{"icon":"github","link":"https://github.com/tkrotoff"}],"lastFetch":1723808381751},{"username":"pimveldhuisen","name":"Pim Veldhuisen","avatar":"https://avatars.githubusercontent.com/u/3043834?v=4","links":[{"icon":"github","link":"https://github.com/pimveldhuisen"}],"lastFetch":1723808382047},{"username":"asvishnyakov","name":"Aleksandr Vishniakov","avatar":"https://avatars.githubusercontent.com/u/6369252?v=4","links":[{"icon":"github","link":"https://github.com/asvishnyakov"}],"lastFetch":1723808382340},{"username":"SchabaJo","name":null,"avatar":"https://avatars.githubusercontent.com/u/138689813?v=4","links":[{"icon":"github","link":"https://github.com/SchabaJo"}],"lastFetch":1723808382571},{"username":"AhsanFazal","name":"Ahsan Fazal","avatar":"https://avatars.githubusercontent.com/u/7458046?v=4","links":[{"icon":"github","link":"https://github.com/AhsanFazal"}],"lastFetch":1723808382875},{"username":"ElForastero","name":"Eugene Dzhumak","avatar":"https://avatars.githubusercontent.com/u/5102818?v=4","links":[{"icon":"github","link":"https://github.com/ElForastero"}],"lastFetch":1723808383102},{"username":"msgadi","name":"Mohammed Gadi","avatar":"https://avatars.githubusercontent.com/u/9037086?v=4","links":[{"icon":"github","link":"https://github.com/msgadi"}],"lastFetch":1723808383368},{"username":"muttonchop","name":"Adam K","avatar":"https://avatars.githubusercontent.com/u/1037657?v=4","links":[{"icon":"github","link":"https://github.com/muttonchop"}],"lastFetch":1723808383582},{"username":"christoph-fricke","name":"Christoph Fricke","avatar":"https://avatars.githubusercontent.com/u/23103835?v=4","links":[{"icon":"github","link":"https://github.com/christoph-fricke"}],"lastFetch":1723808383790},{"username":"JorrinKievit","name":"Jorrin","avatar":"https://avatars.githubusercontent.com/u/43169049?v=4","links":[{"icon":"github","link":"https://github.com/JorrinKievit"}],"lastFetch":1723808384011},{"username":"WickyNilliams","name":"Nick Williams","avatar":"https://avatars.githubusercontent.com/u/1091390?v=4","links":[{"icon":"github","link":"https://github.com/WickyNilliams"}],"lastFetch":1723808384316},{"username":"hrsh7th","name":"hrsh7th","avatar":"https://avatars.githubusercontent.com/u/629908?v=4","links":[{"icon":"github","link":"https://github.com/hrsh7th"}],"lastFetch":1723808384622},{"username":"davidleger95","name":"David Leger","avatar":"https://avatars.githubusercontent.com/u/10498708?v=4","links":[{"icon":"github","link":"https://github.com/davidleger95"}],"lastFetch":1723808384929},{"username":"phk422","name":"Hongkun Peng","avatar":"https://avatars.githubusercontent.com/u/59734322?v=4","links":[{"icon":"github","link":"https://github.com/phk422"}],"lastFetch":1723808385140},{"username":"mzronek","name":"Matthias Zronek","avatar":"https://avatars.githubusercontent.com/u/3847700?v=4","links":[{"icon":"github","link":"https://github.com/mzronek"}],"lastFetch":1723808385356},{"username":"raurfang","name":"Łukasz Wiśniewski","avatar":"https://avatars.githubusercontent.com/u/867241?v=4","links":[{"icon":"github","link":"https://github.com/raurfang"}],"lastFetch":1723808385581},{"username":"JeanRemiDelteil","name":"Jean-Rémi Delteil","avatar":"https://avatars.githubusercontent.com/u/9743907?v=4","links":[{"icon":"github","link":"https://github.com/JeanRemiDelteil"}],"lastFetch":1723808385844},{"username":"TzviPM","name":"Tzvi Melamed","avatar":"https://avatars.githubusercontent.com/u/1950680?v=4","links":[{"icon":"github","link":"https://github.com/TzviPM"}],"lastFetch":1723808386146},{"username":"LucaSchwan","name":"ehrenschwan","avatar":"https://avatars.githubusercontent.com/u/25820532?v=4","links":[{"icon":"github","link":"https://github.com/LucaSchwan"}],"lastFetch":1723808386444},{"username":"nzapponi","name":"Niccolo Zapponi","avatar":"https://avatars.githubusercontent.com/u/20582065?v=4","links":[{"icon":"github","link":"https://github.com/nzapponi"}],"lastFetch":1723808386770},{"username":"luchsamapparat","name":"Marvin Luchs","avatar":"https://avatars.githubusercontent.com/u/875017?v=4","links":[{"icon":"github","link":"https://github.com/luchsamapparat"}],"lastFetch":1723808386995},{"username":"nmacmunn","name":"Neil MacMunn","avatar":"https://avatars.githubusercontent.com/u/849964?v=4","links":[{"icon":"github","link":"https://github.com/nmacmunn"}],"lastFetch":1723808387322}],"openapi-fetch":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723808362783},{"username":"fergusean","name":null,"avatar":"https://avatars.githubusercontent.com/u/1029297?v=4","links":[{"icon":"github","link":"https://github.com/fergusean"}],"lastFetch":1723808363003},{"username":"shinzui","name":"Nadeem Bitar","avatar":"https://avatars.githubusercontent.com/u/519?v=4","links":[{"icon":"github","link":"https://github.com/shinzui"}],"lastFetch":1723808363227},{"username":"ezpuzz","name":"Emory Petermann","avatar":"https://avatars.githubusercontent.com/u/672182?v=4","links":[{"icon":"github","link":"https://github.com/ezpuzz"}],"lastFetch":1723808363446},{"username":"KotoriK","name":null,"avatar":"https://avatars.githubusercontent.com/u/52659125?v=4","links":[{"icon":"github","link":"https://github.com/KotoriK"}],"lastFetch":1723808363675},{"username":"fletchertyler914","name":"Tyler Fletcher","avatar":"https://avatars.githubusercontent.com/u/3344498?v=4","links":[{"icon":"github","link":"https://github.com/fletchertyler914"}],"lastFetch":1723808363989},{"username":"nholik","name":"Nicklos Holik","avatar":"https://avatars.githubusercontent.com/u/2022214?v=4","links":[{"icon":"github","link":"https://github.com/nholik"}],"lastFetch":1723808364218},{"username":"roj1512","name":null,"avatar":"https://avatars.githubusercontent.com/u/175297870?v=4","links":[{"icon":"github","link":"https://github.com/roj1512"}],"lastFetch":1723808364486},{"username":"nickcaballero","name":"Nick Caballero","avatar":"https://avatars.githubusercontent.com/u/355976?v=4","links":[{"icon":"github","link":"https://github.com/nickcaballero"}],"lastFetch":1723808364792},{"username":"hd-o","name":"Hadrian de Oliveira","avatar":"https://avatars.githubusercontent.com/u/58871222?v=4","links":[{"icon":"github","link":"https://github.com/hd-o"}],"lastFetch":1723808364997},{"username":"kecrily","name":"Percy Ma","avatar":"https://avatars.githubusercontent.com/u/45708948?v=4","links":[{"icon":"github","link":"https://github.com/kecrily"}],"lastFetch":1723808365262},{"username":"psychedelicious","name":"psychedelicious","avatar":"https://avatars.githubusercontent.com/u/4822129?v=4","links":[{"icon":"github","link":"https://github.com/psychedelicious"}],"lastFetch":1723808365482},{"username":"muttonchop","name":"Adam K","avatar":"https://avatars.githubusercontent.com/u/1037657?v=4","links":[{"icon":"github","link":"https://github.com/muttonchop"}],"lastFetch":1723808365702},{"username":"marcomuser","name":"Marco Muser","avatar":"https://avatars.githubusercontent.com/u/64737396?v=4","links":[{"icon":"github","link":"https://github.com/marcomuser"}],"lastFetch":1723808365931},{"username":"HugeLetters","name":"Evgenii Perminov","avatar":"https://avatars.githubusercontent.com/u/119697239?v=4","links":[{"icon":"github","link":"https://github.com/HugeLetters"}],"lastFetch":1723808366147},{"username":"Fumaz","name":"alex","avatar":"https://avatars.githubusercontent.com/u/45318608?v=4","links":[{"icon":"github","link":"https://github.com/Fumaz"}],"lastFetch":1723808366370},{"username":"darwish","name":"Mike Darwish","avatar":"https://avatars.githubusercontent.com/u/292570?v=4","links":[{"icon":"github","link":"https://github.com/darwish"}],"lastFetch":1723808366690},{"username":"kaechele","name":"Felix Kaechele","avatar":"https://avatars.githubusercontent.com/u/454490?v=4","links":[{"icon":"github","link":"https://github.com/kaechele"}],"lastFetch":1723808366905},{"username":"phk422","name":"Hongkun Peng","avatar":"https://avatars.githubusercontent.com/u/59734322?v=4","links":[{"icon":"github","link":"https://github.com/phk422"}],"lastFetch":1723808367119},{"username":"mikestopcontinues","name":"Mike Stop Continues","avatar":"https://avatars.githubusercontent.com/u/150434?v=4","links":[{"icon":"github","link":"https://github.com/mikestopcontinues"}],"lastFetch":1723808367352},{"username":"JE-Lee","name":"maurice","avatar":"https://avatars.githubusercontent.com/u/19794813?v=4","links":[{"icon":"github","link":"https://github.com/JE-Lee"}],"lastFetch":1723808367593},{"username":"vipentti","name":"Ville Penttinen","avatar":"https://avatars.githubusercontent.com/u/4726680?v=4","links":[{"icon":"github","link":"https://github.com/vipentti"}],"lastFetch":1723808367900},{"username":"armandabric","name":"Armand Abric","avatar":"https://avatars.githubusercontent.com/u/95120?v=4","links":[{"icon":"github","link":"https://github.com/armandabric"}],"lastFetch":1723808368123},{"username":"illright","name":"Lev Chelyadinov","avatar":"https://avatars.githubusercontent.com/u/15035286?v=4","links":[{"icon":"github","link":"https://github.com/illright"}],"lastFetch":1723808368420}],"openapi-react-query":[{"username":"drwpow","name":"Drew Powers","avatar":"https://avatars.githubusercontent.com/u/1369770?v=4","links":[{"icon":"github","link":"https://github.com/drwpow"}],"lastFetch":1723808362210},{"username":"kerwanp","name":"Martin Paucot","avatar":"https://avatars.githubusercontent.com/u/36955373?v=4","links":[{"icon":"github","link":"https://github.com/kerwanp"}],"lastFetch":1723808362518},{"username":"yoshi2no","name":"yoshi2no","avatar":"https://avatars.githubusercontent.com/u/57059705?v=4","links":[{"icon":"github","link":"https://github.com/yoshi2no"}],"lastFetch":1723808362821}]} \ No newline at end of file diff --git a/docs/ja/about.md b/docs/ja/about.md index aa963be1c..04d7a62ac 100644 --- a/docs/ja/about.md +++ b/docs/ja/about.md @@ -32,7 +32,7 @@ description: このプロジェクトに関する追加情報 ## プロジェクトの目標 1. 任意の有効な OpenAPI スキーマを TypeScript 型に変換できるようにすること。どんなに複雑なスキーマでも対応可能です。 -2. 生成される型は静的に解析可能で、実行時の依存関係がない(ただし、[enum](https://www.typescriptlang.org/docs/handbook/enums.html) のような例外はあります)。 +2. 生成される型は静的に解析可能で、実行時の依存関係がない(ただし、[enums](https://www.typescriptlang.org/docs/handbook/enums.html) のような例外はあります)。 3. 生成された型は、元のスキーマにできるだけ一致し、元の大文字形式などを保持します。 4. 型の生成 は Node.js だけで実行可能であり、(Java、Python などは不要)どんな環境でも実行できます。 5. ファイルからの OpenAPI スキーマのフェッチや、ローカルおよびリモートサーバーからのフェッチをサポートします。 diff --git a/docs/ja/advanced.md b/docs/ja/advanced.md index 42c69dd99..9eb8abb01 100644 --- a/docs/ja/advanced.md +++ b/docs/ja/advanced.md @@ -19,13 +19,13 @@ $ DEBUG=openapi-ts:* npx openapi-typescript schema.yaml -o my-types.ts 出力が `stdout` の場合、デバッグメッセージは抑制されることに注意してください。 -## 列挙型の拡張 +## Enum の拡張 -`x-enum-varnames` は、対応する値に別の列挙型名を定義するために使用されます。これは列挙項目の名前を定義するために使用されます。 +`x-enum-varnames` は、対応する値に別の列挙型名を定義するために使用されます。これは enum の項目名を定義するために使用されます。 `x-enum-descriptions` は、各値に対して個別の説明を提供するために使用できます。これは、コード内のコメント(Javaの場合はjavadocのようなもの)として使用されます。 -`x-enum-descriptions`および`x-enum-varnames`は、それぞれ列挙型と同じ数の項目を含むリストであることが期待されます。リスト内の項目の順序は重要です:位置を使用してこれらを結びつけます。 +`x-enum-descriptions`および`x-enum-varnames`は、それぞれ Enum と同じ数の項目を含むリストであることが期待されます。リスト内の項目の順序は重要です:位置を参考にしてこれらを結びつけます。 例: @@ -68,7 +68,7 @@ enum ErrorCode { ::: -この方法で生成するには、[コマンドライン](cli.md#flags)で `--enum` を指定する必要があります。 +この方法で生成するには、[コマンドライン](cli#%E3%83%95%E3%83%A9%E3%82%AF%E3%82%99)で `--enum` を指定する必要があります。 または、`x-enumNames`および`x-enumDescriptions`([NSwag/NJsonSchema](https://github.com/RicoSuter/NJsonSchema/wiki/Enums#enum-names-and-descriptions))も使用できます。 @@ -78,7 +78,7 @@ enum ErrorCode { ### Redocly ルール -TypeScript生成におけるエラーを減らすために、[Redocly config](https://redocly.com/docs/cli/rules/built-in-rules/)で次の組み込みルールを適用することをお勧めします: +TypeScript生成におけるエラーを減らすために、[Redocly config](https://redocly.com/docs/cli/rules/built-in-rules/) で次の組み込みルールを適用することをお勧めします: | ルール | 設定 | 理由 | | :-------------------------------------------------------------------------------------------- | :----------------: | :------------------------------- | @@ -100,9 +100,9 @@ TypeScript生成におけるエラーを減らすために、[Redocly config](ht JSのスタイルガイドが推奨するように、APIレスポンスを`camelCase`にリネームしたくなるかもしれません。しかし、リネームは時間の無駄になるだけでなく、次のような保守上の問題を引き起こすため、**リネームを避ける**ことをお勧めします: - ❌ 生成された型(たとえばopenapi-typescriptが生成した型)は、手動で入力する必要がある -- ❌ リネームは実行時に発生するため、アプリケーションが隠れた変更を行う際に遅延を引き起こす +- ❌ リネームは実行時に発生するため、アプリケーションが見えない変更を行う際に遅延を引き起こす - ❌ 名前変更ツールを構築し、維持(およびテスト)する必要がある -- ❌ APIが `requestBodies `に `snake_case` を必要とする場合、すべての作業を各APIリクエストで元に戻さなければならない +- ❌ APIが `requestBodies`に `snake_case` を必要とする場合、すべての作業を各APIリクエストで元に戻さなければならない 代わりに、「一貫性」をより包括的な概念と見なし、JSスタイルの規約に従うよりもAPIスキーマをそのまま保持することが優れていると認識してください。 @@ -195,8 +195,8 @@ Record;   - Schema - Generated Type + スキーマ + 生成される型 @@ -280,7 +280,7 @@ prefixItems: ### `oneOf`を単独で使用する -OpenAPIのコンポジションツール(`oneOf` / `anyOf` / `allOf`)は、スキーマ内のコード量を減らしながら柔軟性を最大化する強力なツールです。しかし、TypeScriptの共用体型は[XOR](https://en.wikipedia.org/wiki/Exclusive_or)を提供しないため、`oneOf` に直接マッピングすることはできません。そのため、oneOfは単独で使用し、他のコンポジションメソッドやプロパティと組み合わせないことが推奨されます。例えば: +OpenAPIのコンポジションツール(`oneOf` / `anyOf` / `allOf`)は、スキーマ内のコード量を減らしながら柔軟性を最大化する強力なツールです。しかし、TypeScriptのユニオン型は[XOR](https://en.wikipedia.org/wiki/Exclusive_or)を提供しないため、`oneOf` に直接マッピングすることはできません。そのため、oneOfは単独で使用し、他のコンポジションメソッドやプロパティと組み合わせないことが推奨されます。例えば: #### ❌ 悪い @@ -310,7 +310,7 @@ Pet: ::: -これは、TypeScriptのユニオンとインターセクションの両方を組み合わせた次のような型が生成されます。これは有効なTypeScriptですが、複雑であり、推論が意図した通りに機能しない可能性があります。しかし、最も問題となるのは、TypeScriptがtypeプロパティを通じて区別できないことです。 +これは、TypeScript のユニオン型とインターセクション型の両方を組み合わせた次のような型が生成されます。これは有効な TypeScript ですが、複雑であり、推論が意図した通りに機能しない可能性があります。しかし、最も問題となるのは、TypeScript が type プロパティを通じて区別できないことです。 ::: code-group @@ -365,7 +365,7 @@ Cat: { type?: "cat"; } & components["schemas"]["PetCommonProperties"]; _注: 任意で、`Pet` に `discriminator.propertyName: "type"` を指定することもできます([ドキュメント](https://spec.openapis.org/oas/v3.1.0#discriminator-object))。これにより、自動的に `type` キーが生成されますが、明示性が低くなります。_ -スキーマでは任意の方法でコンポジションを使用することが許可されていますが、生成された型を確認し、ユニオンやインターセクションをより簡潔に表現できる方法がないか検討することは重要です。 `oneOf` の使用を制限することが唯一の方法ではありませんが、しばしば最大の効果をもたらします。 +スキーマでは任意の方法でコンポジションを使用することが許可されていますが、生成された型を確認し、ユニオン型やインターセクション型をより簡潔に表現できる方法がないか検討することは重要です。 `oneOf` の使用を制限することが唯一の方法ではありませんが、しばしば最大の効果をもたらします。 ## JSONSchema $defs の注意点 @@ -448,10 +448,10 @@ export interface components { ::: -そのため、$defs を定義する場所には注意が必要です。最終的に生成される型から $defs が消えてしまう可能性があります。 +そのため、`$defs` を定義する場所には注意が必要です。最終的に生成される型から $defs が消えてしまう可能性があります。 ::: tip -不安な場合は、$defs をルートスキーマレベルで定義するのが安全です。 +不安な場合は、`$defs` をルートスキーマレベルで定義するのが安全です。 ::: diff --git a/docs/ja/cli.md b/docs/ja/cli.md index f663a0c68..94666e5c2 100644 --- a/docs/ja/cli.md +++ b/docs/ja/cli.md @@ -27,11 +27,11 @@ npx openapi-typescript https://petstore3.swagger.io/api/v3/openapi.yaml -o petst ### 複数のスキーマ -複数のスキーマを変換するには、プロジェクトのルートディレクトリに `redocly.yaml` ファイルを作成し、[APIs を定義します](https://redocly.com/docs/cli/configuration/)。`apis` の下に、それぞれのスキーマに一意の名前とオプションのバージョンを指定します(名前は一意であれば問題ありません)。`root` 値をスキーマのエントリーポイントとして設定し、これが主な入力として機能します。出力には、`x-openapi-ts.output` を設定します: +複数のスキーマを変換するには、プロジェクトのルートディレクトリに `redocly.yaml` ファイルを作成し、[APIs を定義します](https://redocly.com/docs/cli/configuration/)。`apis` の下に、それぞれのスキーマに一意の名前と、必要に応じてオプションのバージョンを指定します(名前は一意であれば問題ありません)。`root` の値をスキーマのエントリーポイントに設定します。これが主な入力として機能します。出力については、`x-openapi-ts.output` で設定します: ::: code-group -```yaml [my-openapi-3-schema.yaml] +```yaml [redocly.yaml] apis: core@v2: root: ./openapi/openapi.yaml @@ -59,7 +59,7 @@ npx openapi-typescript ::: warning -以前のバージョンではワイルドカードがサポートされていましたが、v7 では廃止され、代わりに `redocly.yaml` が使用されるようになりました。これにより、各スキーマの出力先をより詳細に制御でき、各スキーマに固有の設定を適用することができます。 +以前のバージョンでは globbing がサポートされていましたが、v7 では廃止され、代わりに `redocly.yaml` が推奨されるようになりました。これにより、各スキーマの出力先をより詳細に制御でき、各スキーマに固有の設定を適用することができます。 ::: @@ -79,7 +79,7 @@ Redoclyの設定オプションについての詳細は [Redoclyのドキュメ ::: code-group -```yaml [my-openap-3-schema.yaml] +```yaml [redocly.yaml] resolve: http: headers: @@ -108,10 +108,10 @@ CLI は以下のフラグをサポートしています: | `--additional-properties` | | `false` | `additionalProperties: false` がないすべてのスキーマオブジェクトに任意のプロパティを許可します | | `--alphabetize` | | `false` | 型をアルファベット順にソートします | | `--array-length` | | `false` | 配列の `minItems` / `maxItems` を使用してタプルを生成します | -| `--default-non-nullable` | | `true` | デフォルト値を持つスキーマオブジェクトを、パラメータを除き、非null型として扱います | -| `--properties-required-by-default` | | `false` | `required` がないスキーマオブジェクトを、すべてのプロパティが必須であるかのように扱います | +| `--default-non-nullable` | | `true` | デフォルト値を持つスキーマオブジェクトを、非nullableとして扱います(parametersを除きます) | +| `--properties-required-by-default` | | `false` | `required` がないスキーマオブジェクトについて、すべてのプロパティを必須として扱います | | `--empty-objects-unknown` | | `false` | 指定されたプロパティも `additionalProperties` もないスキーマオブジェクトに任意のプロパティを許可します | -| `--enum` | | `false` | 文字列の共用体ではなく、[TS enums](https://www.typescriptlang.org/docs/handbook/enums.html) を生成します | +| `--enum` | | `false` | 文字列のユニオン型ではなく、[TS enums](https://www.typescriptlang.org/docs/handbook/enums.html) を生成します | | `--enum-values` | | `false` | enumの値を配列としてエクスポートします | | `--dedupe-enums` | | `false` | `--enum=true` が設定されている場合、enumの重複を排除します | | `--check` | | `false` | 生成された型が最新であることを確認します | @@ -160,7 +160,7 @@ type UserResponses = paths[url]["responses"]; // 自動的に `paths['/user/{use ::: -これは人為的な例ですが、この機能を使用して、フェッチクライアントやアプリケーション内の他の便利な場所で、URLに基づいて型を自動的に推論することができます。 +これは人為的な例ですが、この機能を使用して、フェッチクライアントやアプリケーション内の他に有用的な場面で、URLに基づいて型を自動的に推論することができます。 _ありがとう, [@Powell-v2](https://github.com/Powell-v2)!_ @@ -202,6 +202,6 @@ export interface components { これにより、配列の長さに対するより明示的な型チェックが可能になります。 -_注: この機能には適切な制限があります。例えば `maxItems: 100` の場合は、単純に `string[];` に戻ります。_ +_注: この機能には合理的な制限があります。例えば `maxItems: 100` の場合は、単純に `string[];` に戻ります。_ _ありがとう, [@kgtkr](https://github.com/kgtkr)!_ diff --git a/docs/ja/examples.md b/docs/ja/examples.md index ebf6e51a3..bd1136b92 100644 --- a/docs/ja/examples.md +++ b/docs/ja/examples.md @@ -5,18 +5,146 @@ description: openapi-typescriptを実際のアプリケーションで使用す # 使用例 -openapi-typescriptで生成された型は汎用性が高く、さまざまな方法で利用できます。これらの例は包括的なものではありませんが、アプリケーションでの使用方法についてのアイデアを刺激することを期待しています。 +openapi-typescript で生成された型は汎用性が高く、さまざまな方法で利用できます。これらの例は包括的なものではありませんが、アプリケーションでの使用方法についてのアイデアを刺激することを期待しています。 ## データフェッチ データを取得する際には、**自動的に型付けされたfetchラッパー**を使用すると、簡単かつ安全に行えます: -- [openapi-fetch](/ja/openapi-fetch/) (推奨) -- [openapi-typescript-fetch](https://www.npmjs.com/package/openapi-typescript-fetch) by [@ajaishankar](https://github.com/ajaishankar) +
+openapi-fetch (推奨) + +::: code-group + +```ts [test/my-project.ts] +import createClient from "openapi-fetch"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const client = createClient({ baseUrl: "https://myapi.dev/v1/" }); + +const { + data, // 2XX レスポンスの場合のみ存在 + error, // 4XX または 5XX レスポンスの場合のみ存在 +} = await client.GET("/blogposts/{post_id}", { + params: { + path: { post_id: "123" }, + }, +}); + +await client.PUT("/blogposts", { + body: { + title: "My New Post", + }, +}); +``` + +::: + +
+ +
+openapi-typescript-fetch by @ajaishankar + +::: code-group + +```ts [test/my-project.ts] +import { Fetcher } from "openapi-typescript-fetch"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +const fetcher = Fetcher.for(); + +// GET リクエストを送信 +const getBlogPost = fetcher.path("/blogposts/{post_id}").method("get").create(); + +try { + const { status, data } = await getBlogPost({ + pathParams: { post_id: "123" }, + }); + console.log(data); +} catch (error) { + console.error("Error:", error); +} + +// PUT リクエストを送信 +const updateBlogPost = fetcher.path("/blogposts").method("put").create(); + +try { + await updateBlogPost({ body: { title: "My New Post" } }); +} catch (error) { + console.error("Error:", error); +} +``` + +::: + +
+ +
+feature-fetch by builder.group + +::: code-group + +```ts [test/my-project.ts] +import { createOpenApiFetchClient } from "feature-fetch"; +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 + +// OpenAPI fetch クライアントを作成 +const fetchClient = createOpenApiFetchClient({ + prefixUrl: "https://myapi.dev/v1", +}); + +// GET リクエストを送信 +const response = await fetchClient.get("/blogposts/{post_id}", { + pathParams: { + post_id: "123", + }, +}); + +// レスポンスを処理する(アプローチ1:標準のif-else) +if (response.isOk()) { + const data = response.value.data; + console.log(data); // 成功したレスポンスを処理 +} else { + const error = response.error; + if (error instanceof NetworkError) { + console.error("Network error:", error.message); + } else if (error instanceof RequestError) { + console.error("Request error:", error.message, "Status:", error.status); + } else { + console.error("Service error:", error.message); + } +} + +// PUT リクエストを送信 +const putResponse = await fetchClient.put("/blogposts", { + body: { + title: "My New Post", + }, +}); + +// レスポンスを処理する(アプローチ2:try-catch) +try { + const putData = putResponse.unwrap().data; + console.log(putData); // 成功したレスポンスを処理 +} catch (error) { + // エラーを処理 + if (error instanceof NetworkError) { + console.error("Network error:", error.message); + } else if (error instanceof RequestError) { + console.error("Request error:", error.message, "Status:", error.status); + } else { + console.error("Service error:", error.message); + } +} +``` + +::: + +
::: tip -良いfetchラッパーは**ジェネリクスの使用は避ける**べきです。ジェネリクスは多くのタイプ指定が必要で、エラーを隠してしまう可能性があります! +良い fetch ラッパーは**ジェネリクスの使用は避ける**べきです。ジェネリクスは多くのタイプ指定が必要で、エラーを隠してしまう可能性があります! ::: @@ -30,7 +158,7 @@ openapi-typescriptで生成された型は汎用性が高く、さまざまな ```ts [src/my-project.ts] import { Hono } from "hono"; -import { components, paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成 +import { components, paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 const app = new Hono(); @@ -58,6 +186,108 @@ export default app; ::: +## Hono と [`@blgc/openapi-router`](https://github.com/builder-group/community/tree/develop/packages/openapi-router) + +[Honoの例](#hono) のように、各ルートをジェネリックで手動で型付けする代わりに、[`@blgc/openapi-router`](https://github.com/builder-group/community/tree/develop/packages/openapi-router) は、[Hono router](https://hono.dev/docs/api/routing) をラップして完全な型安全性を提供し、バリデーターを使用してOpenAPIスキーマを強制します。 + +::: tip 知っておくと良いこと + +TypeScriptの型はコンパイル時の安全性を保証しますが、実行時のスキーマ検証を強制するものではありません。実行時の検証を確保するためには、ZodやValibotなどのバリデーションライブラリと統合する必要があります。バリデーションルールを手動で定義する必要がありますが、それらは型安全であり、ルールが正しく定義されていることを保証します。 + +::: + +::: code-group + +```ts [src/router.ts] +import { createHonoOpenApiRouter } from "@blgc/openapi-router"; +import { Hono } from "hono"; +import { zValidator } from "validation-adapters/zod"; +import * as z from "zod"; + +import { paths } from "./gen/v1"; // openapi-typescriptで生成された型 +import { PetSchema } from "./schemas"; // 検証用の再利用可能なカスタムZodスキーマ + +export const router = new Hono(); +export const openApiRouter = createHonoOpenApiRouter(router); + +// GET /pet/{petId} +openApiRouter.get("/pet/{petId}", { + pathValidator: zValidator( + z.object({ + petId: z.number(), // petIdが数値であることを検証 + }) + ), + handler: (c) => { + const { petId } = c.req.valid("param"); // 検証済みのパラメータにアクセス + return c.json({ name: "Falko", photoUrls: [] }); + }, +}); + +// POST /pet +openApiRouter.post("/pet", { + bodyValidator: zValidator(PetSchema), // PetSchemaを使用してリクエストボディを検証 + handler: (c) => { + const { name, photoUrls } = c.req.valid("json"); // 検証済みのボディデータにアクセス + return c.json({ name, photoUrls }); + }, +}); +``` + +::: + +[完全な例](https://github.com/builder-group/community/tree/develop/examples/openapi-router/hono/petstore) + +## Express と [`@blgc/openapi-router`](https://github.com/builder-group/community/tree/develop/packages/openapi-router) + +[`@blgc/openapi-router`](https://github.com/builder-group/community/tree/develop/packages/openapi-router) は、[Express ルーター](https://expressjs.com/en/5x/api.html#router) をラップして、完全な型安全性を提供し、バリデーターを使用して OpenAPI スキーマを強制します。 + +::: tip 知っておくと良いこと + +TypeScriptの型はコンパイル時の安全性を保証しますが、実行時のスキーマ検証を強制するものではありません。実行時の検証を確保するためには、ZodやValibotなどのバリデーションライブラリと統合する必要があります。バリデーションルールを手動で定義する必要がありますが、それらは型安全であり、ルールが正しく定義されていることを保証します。 + +::: + +::: code-group + +```ts [src/router.ts] +import { createExpressOpenApiRouter } from "@blgc/openapi-router"; +import { Router } from "express"; +import * as v from "valibot"; +import { vValidator } from "validation-adapters/valibot"; + +import { paths } from "./gen/v1"; // openapi-typescriptで生成された型 +import { PetSchema } from "./schemas"; // 検証用の再利用可能なカスタムZodスキーマ + +export const router: Router = Router(); +export const openApiRouter = createExpressOpenApiRouter(router); + +// GET /pet/{petId} +openApiRouter.get("/pet/{petId}", { + pathValidator: vValidator( + v.object({ + petId: v.number(), // petIdが数値であることを検証 + }) + ), + handler: (req, res) => { + const { petId } = req.params; // 検証済みのパラメータにアクセス + res.send({ name: "Falko", photoUrls: [] }); + }, +}); + +// POST /pet +openApiRouter.post("/pet", { + bodyValidator: vValidator(PetSchema), // PetSchemaを使用してリクエストボディを検証 + handler: (req, res) => { + const { name, photoUrls } = req.body; // 検証済みのボディデータにアクセス + res.send({ name, photoUrls }); + }, +}); +``` + +::: + +[完全な例](https://github.com/builder-group/community/tree/develop/examples/openapi-router/express/petstore) + ## Mock-Service-Worker (MSW) [Mock Service Worker (MSW)](https://mswjs.io) を使用してAPIモックを定義している場合、**小さくて自動的に型付けされたラッパー**をMSWと合わせて使用することで、OpenAPI仕様が変更された際にAPIモックのコンフリクトを簡単に解決できます。最終的には、アプリケーションのAPIクライアントとAPIモックの**両方**に同じレベルの信頼を持つことができます。 @@ -74,7 +304,7 @@ export default app; 最も一般的なテストの誤検知の原因の一つは、モックが実際のAPIレスポンスと一致していない場合です。 -`openapi-typescript` は、最小限の労力でこれを防ぐための素晴らしい方法を提供します。以下に、OpenAPIスキーマに一致するようにすべてのモックを型チェックするためのヘルパー関数を書く一例を示します(ここでは[vitest](https://vitest.dev/)や[vitest-fetch-mock](https://www.npmjs.com/package/vitest-fetch-mock)を使用しますが、同じ原則が他の設定にも適用できます): +`openapi-typescript` は、最小限の労力でこれを防ぐための素晴らしい方法を提供します。以下に、OpenAPIスキーマに一致するようにすべてのモックを型チェックするためのヘルパー関数を書く一例を示します(ここでは [vitest](https://vitest.dev/) や [vitest-fetch-mock](https://www.npmjs.com/package/vitest-fetch-mock) を使用しますが、同じ原則が他の設定にも適用できます): 次のようなオブジェクト構造でモックを定義し、一度に複数のエンドポイントをモックすることを考えてみましょう: @@ -130,7 +360,7 @@ describe("My API test", () => { _注: この例では、標準の `fetch()` 関数を使用していますが、[openapi-fetch](/ja/openapi-fetch/) を含む他の fetch ラッパーも、何の変更も加えずに代わりに使用できます。_ -以下のコードは、`test/utils.ts` ファイルに記述し、必要に応じてプロジェクトにコピー&ペーストして使用することができます(シンプルさを保つために隠しています)。 +コードは、`test/utils.ts` ファイルにあり、必要に応じてプロジェクトにコピー&ペーストして使用することができます(シンプルさを保つために隠しています)。
📄 test/utils.ts @@ -138,7 +368,7 @@ _注: この例では、標準の `fetch()` 関数を使用していますが、 ::: code-group ```ts [test/utils.ts] -import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typescript +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 // 設定 // ⚠️ 重要: ここを変更してください!これはすべてのURLにプレフィックスを追加します @@ -219,7 +449,7 @@ export function findPath( ::: info 追加の説明 -このコードはかなり複雑です! 大部分は詳細な実装なので無視しても構いません。重要な仕掛けが行われているのは、`mockResponses(…)` 関数のシグネチャです。ここには、この構造と私たちの設計との直接的なリンクがあることに気づくでしょう。その後、残りのコードは、ランタイムが期待通りに動作するように調整するためのものです。 +このコードはかなり複雑です! 大部分は詳細な実装なので無視しても構いません。重要な仕掛けが行われているのは、`mockResponses(…)` 関数のシグネチャです。ここにすべての重要な処理が行われています—この構造と私たちの設計との直接的な関係が見えるでしょう。残りのコードはランタイムが期待通りに動作するように整えるだけです。 ::: diff --git a/docs/ja/index.md b/docs/ja/index.md index d71afd47a..13a6e7660 100644 --- a/docs/ja/index.md +++ b/docs/ja/index.md @@ -15,7 +15,7 @@ hero: features: - title: "超高速" - details: "静的な TypeScript 型は、実行時に影響を与えず、クライアントの負担もありません。" + details: "静的な TypeScriptの型は、実行時に影響を与えず、クライアントの負担もありません。" - title: "型安全" details: "OpenAPI スキーマを使用して、セットアップやテストなしでコード全体を型チェックします。" - title: "どこでも実行可能" diff --git a/docs/ja/introduction.md b/docs/ja/introduction.md index d14c02d13..f93bd8148 100644 --- a/docs/ja/introduction.md +++ b/docs/ja/introduction.md @@ -18,7 +18,7 @@ OpenAPI初心者ですか?Speakeasyの [Intro to OpenAPI](https://www.speakeas ## 特徴 - ✅ OpenAPI 3.0および3.1をサポート([discriminators](https://spec.openapis.org/oas/v3.1.0#discriminator-object)のような高度な機能を含む) -- ✅ 従来のコード生成より優れている**ランタイムなしの型**を生成 +- ✅ 従来のコード生成より優れている**実行時に依存しない型**を生成 - ✅ YAMLまたはJSONから、ローカルまたはリモートでスキーマを読み込む - ✅ 巨大なスキーマであってもミリ秒単位で型を生成 @@ -30,7 +30,7 @@ _注: OpenAPI 2.xはバージョン `5.x` およびそれ以前でサポート ## セットアップ -このライブラリを使用するには、最新バージョンの [Node.js](https://nodejs.org) がインストールされている必要があります(20.x以上を推奨)。インストールしたら、以下のコマンドをプロジェクトで実行してください: +このライブラリを使用するには、最新バージョンの [Node.js](https://nodejs.org) がインストールされている必要があります(20.x 以上を推奨)。インストールしたら、以下のコマンドをプロジェクトで実行してください: ```bash npm i -D openapi-typescript typescript @@ -103,10 +103,10 @@ type ErrorResponse = ::: -ここから、これらの型を以下の用途(ただし、これに限定されません)で使用できます: +ここから、これらの型を以下の用途で使用できます(ただし、これに限定されません): -- OpenAPI対応のfetchクライアント(例:[openapi-fetch](/ja/openapi-fetch/))を使用 +- OpenAPI対応のfetchクライアントを使用する(例:[openapi-fetch](/ja/openapi-fetch/)) - 他のAPIリクエストボディやレスポンスの型のアサート - API型に基づいたコアビジネスロジックの構築 -- モックテストデータが現在のスキーマと一致していることを確認 +- モックテストデータが現在のスキーマと一致していることを確認する - 任意のnpmパッケージ(クライアントSDKなど)にAPI型をパッケージ化する diff --git a/docs/ja/migration-guide.md b/docs/ja/migration-guide.md index b12cc9e05..2327effa7 100644 --- a/docs/ja/migration-guide.md +++ b/docs/ja/migration-guide.md @@ -13,13 +13,13 @@ description: openapi-typescript のバージョン間の移行 ### TypeScript AST -7.x では、単純な文字列変換の代わりに TypeScript AST が導入されました。これにより、Node.js のコア API が TypeScript AST を返すようになり、`transform()` および `postTransform()` オプションも影響を受けます。[Node.js API のドキュメントが、関連する例と共に更新されています](./node)。 +7.x では、単純な文字列変換の代わりに TypeScript AST が導入されました。これは、TypeScript ASTを返すようになったコアのNode.js API、および `transform()` や `postTransform()` オプションに適用されます。[Node.js API のドキュメントが、関連する例と共に更新されています](./node)。 -### defaultNonNullable: デフォルトで true +### defaultNonNullableがデフォルトで true -CLI および Node.js API では、`--default-non-nullable` の動作がデフォルトで有効になりました。これにより、スキーマオブジェクトに `default` 値がある場合、それは `required` として扱われます(パラメータを除く)。 +CLI および Node.js API では、`--default-non-nullable` の動作がデフォルトで有効になりました。これにより、スキーマオブジェクトに `default` 値がある場合、それは `required` として扱われます(parametersを除く)。 -### Redocly 設定ファイルによるグロビングの置き換え +### Redocly 設定ファイルによる globbing の置き換え 7.x では複数のスキーマを一度に生成することができますが、特定の命名スキーマに従うことを強制するグロビングの代わりに、`redocly.config.yaml` ファイルを宣言して、各入力スキーマとその関連する生成された型の保存場所を指定します。これにより、複数のスキーマの命名と整理に柔軟性が生まれます。 @@ -47,9 +47,9 @@ await openapiTS(input); | Local file | `string \| URL` | `URL` | | Remote file | `string \| URL` | `URL` | -最大の変更点は `string` の扱いです。6.x では、string はローカルまたはリモートのファイルパスを指す可能性がありましたが、これは予測不可能でした。というのも、ローカルファイルパスの場合、Node が呼び出された場所に依存していたからです。7.x では、**すべてのファイルパスは [URL](https://nodejs.org/api/url.html) である必要があります**(ローカルパスの場合、`new URL('./path/to/my/schema', import.meta.url)` または `new URL('file:///absolute/path/to/my/schema')` を使用)。これにより、 `string` タイプがインライン YAML(または JSON)を扱えるようになりました(6.x ではサポートされていませんでした)。 +最大の変更点は `string` の扱いです。6.x では、string はローカルまたはリモートのファイルパスを指す可能性がありましたが、これは予測不可能でした。というのも、ローカルファイルパスの場合、Node が呼び出された場所に依存していたからです。7.x では、**すべてのファイルパスは [URL](https://nodejs.org/api/url.html) である必要があります**(ローカルパスの場合、`new URL('./path/to/my/schema', import.meta.url)` または `new URL('file:///absolute/path/to/my/schema')` を使用)。これにより、 `string` 型がインライン YAML(または JSON)を扱えるようになりました(6.x ではサポートされていませんでした)。 -[詳細は更新されたドキュメントを参照](./node#usage)。 +[詳細は更新されたドキュメントを参照](./node#使用方法)。 --- diff --git a/docs/ja/node.md b/docs/ja/node.md index 19a023a37..2fedf1716 100644 --- a/docs/ja/node.md +++ b/docs/ja/node.md @@ -23,17 +23,17 @@ npm i --save-dev openapi-typescript typescript Node.js APIは、`URL`、`string`、またはJSONオブジェクトを入力として受け付けます: -| Type | Description | Example | +| タイプ | 説明 | 例 | | :------: | :--------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------- | | `URL` | ローカルまたはリモートファイルを読み取る | `await openapiTS(new URL('./schema.yaml', import.meta.url))`
`await openapiTS(new URL('https://myapi.com/v1/openapi.yaml'))` | | `string` | 動的なYAMLまたはJSONを読み取る | `await openapiTS('openapi: "3.1" … ')` | | `JSON` | 動的なJSONを読み取る | `await openapiTS({ openapi: '3.1', … })` | -また、 `Readable` ストリームや`Buffer` 型も受け付け、これらは文字列として解決されます(ドキュメント全体が必要でないと検証、バンドル、型生成ができません)。 +また、 `Readable` ストリームや`Buffer` 型も受け付け、これらは文字列として解決されます(ドキュメント全体がないと検証、バンドル、型生成ができません)。 -Node APIはTypeScript ASTを返す `Promise` を返します。その後、必要に応じてASTをトラバース、操作、または修正できます。 +Node APIはTypeScript の AST を含む `Promise` を返します。その後、必要に応じてASTをトラバース、操作、または修正できます。 -TypeScript ASTを文字列に変換するには、[TypeScriptのプリンターのラッパー](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#re-printing-sections-of-a-typescript-file)である `astToString()` ヘルパーを使用できます: +TypeScript ASTを文字列に変換するには、[TypeScriptのprinterのラッパー](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#re-printing-sections-of-a-typescript-file)である `astToString()` ヘルパーを使用できます: ::: code-group @@ -60,7 +60,7 @@ Redoc configはopenapi-typescriptを使用するために必須ではありま import { createConfig, loadConfig } from "@redocly/openapi-core"; import openapiTS from "openapi-typescript"; -// オプション1:メモリ内で設定を作成 +// オプション1: インメモリ設定を作成 const redocly = await createConfig( { apis: { @@ -71,7 +71,7 @@ const redocly = await createConfig( { extends: ["recommended"] }, ); -// オプション2:redocly.yamlファイルから読み込み +// オプション2: redocly.yamlファイルから読み込み const redocly = await loadConfig({ configPath: "redocly.yaml" }); const ast = await openapiTS(mySchema, { redocly }); @@ -79,17 +79,17 @@ const ast = await openapiTS(mySchema, { redocly }); ::: -## Options +## オプション -Node APIは、 `camelCase` 形式で[CLI フラグ](./cli#options) すべてをサポートしており、以下の追加オプションも利用可能です: +Node APIは、 `camelCase` 形式で[CLI フラグ](./cli#%E3%83%95%E3%83%A9%E3%82%AF%E3%82%99) すべてをサポートしており、以下の追加オプションも利用可能です: -| 名前 | タイプ | デフォルト | Description | -| :-------------- | :-------------: | :-------------: | :--------------------------------------------------------------------------------------- | -| `transform` | `Function` | | Override the default Schema Object ➝ TypeScript transformer in certain scenarios | -| `postTransform` | `Function` | | `transform` と同じだが、TypeScript変換後に実行される | -| `silent` | `boolean` | `false` | 警告メッセージを非表示にする(致命的なエラーは表示されます) | -| `cwd` | `string \| URL` | `process.cwd()` | (オプション)必要に応じてリモート$refの解決を支援するために現在の作業ディレクトリを指定 | -| `inject` | `string` | | ファイルの先頭に任意のTypeScript型を注入 | +| 名前 | タイプ | デフォルト | 説明 | +| :-------------- | :-------------: | :-------------: | :------------------------------------------------------------------------------------------- | +| `transform` | `Function` | | 特定の状況でデフォルトのスキーマオブジェクトをTypeScriptにするトランスフォーマーを上書きする | +| `postTransform` | `Function` | | `transform` と同じだが、TypeScript変換後に実行される | +| `silent` | `boolean` | `false` | 警告メッセージを非表示にする(致命的なエラーは表示されます) | +| `cwd` | `string \| URL` | `process.cwd()` | (オプション)必要に応じてリモート$refの解決を支援するために現在の作業ディレクトリを指定 | +| `inject` | `string` | | ファイルの先頭に任意のTypeScript型を注入 | ### transform / postTransform diff --git a/docs/ja/openapi-fetch/api.md b/docs/ja/openapi-fetch/api.md index 8fdfdc2bf..5979e6d9a 100644 --- a/docs/ja/openapi-fetch/api.md +++ b/docs/ja/openapi-fetch/api.md @@ -13,10 +13,10 @@ description: openapi-fetch API createClient(options); ``` -| Name | Type | Description | +| 名前 | 型 | 説明 | | :---------------- | :-------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `baseUrl` | `string` | すべてのfetch URLにこのオプションで指定されたプレフィックスを付与します (例. `"https://myapi.dev/v1/"`) | -| `fetch` | `fetch` | リクエストに使用するFetchインスタンス (デフォルト: `globalThis.fetch`) | +| `baseUrl` | `string` | すべての fetch URL にこのオプションで指定されたプレフィックスを付与します (例.`"https://myapi.dev/v1/"`) | +| `fetch` | `fetch` | リクエストに使用する Fetch インスタンス (デフォルト: `globalThis.fetch`) | | `querySerializer` | QuerySerializer | (任意) [querySerializer](#queryserializer) を提供します | | `bodySerializer` | BodySerializer | (任意) [bodySerializer](#bodyserializer) を提供します | | (Fetch options) | | 有効なすべてのfetchオプション(`headers`, `mode`, `cache`, `signal` など)を指定可能です。([ドキュメント](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options)) | @@ -29,16 +29,16 @@ createClient(options); client.GET("/my-url", options); ``` -| Name | Type | Description | -| :---------------- | :---------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `params` | ParamsObject | エンドポイントの [path](https://swagger.io/specification/#parameter-locations) と [query](https://swagger.io/specification/#parameter-locations) パラメータ。 | -| `body` | `{ [name]:value }` | エンドポイントの [requestBody](https://spec.openapis.org/oas/latest.html#request-body-object) データ。 | -| `querySerializer` | QuerySerializer | (任意) [querySerializer](#queryserializer) を提供します | -| `bodySerializer` | BodySerializer | (任意) [bodySerializer](#bodyserializer) を提供します | -| `parseAs` | `"json"` \| `"text"` \| `"arrayBuffer"` \| `"blob"` \| `"stream"` | (任意) [組み込みのインスタンスメソッド](https://developer.mozilla.org/en-US/docs/Web/API/Response#instance_methods) を使用してレスポンスを解析します(デフォルト: "json") (デフォルト: `"json"`). `"stream"` は解析をスキップし、未処理のストリームを返します。 | -| `fetch` | `fetch` | リクエストに使用するFetchインスタンス (デフォルト: `createClient` で指定されたfetch) | -| `middleware` | `Middleware[]` | [ドキュメントを参照](/openapi-fetch/middleware-auth) | -| (Fetch options) | | 有効なすべてのfetchオプション(`headers`, `mode`, `cache`, `signal`など) ([ドキュメント](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options)) | +| 名前 | 型 | 説明 | +| :---------------- | :---------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `params` | ParamsObject | エンドポイントの [path](https://swagger.io/specification/#parameter-locations) と [query](https://swagger.io/specification/#parameter-locations) パラメータ。 | +| `body` | `{ [name]:value }` | エンドポイントの [requestBody](https://spec.openapis.org/oas/latest.html#request-body-object) データ。 | +| `querySerializer` | QuerySerializer | (任意) [querySerializer](#queryserializer) を提供します | +| `bodySerializer` | BodySerializer | (任意) [bodySerializer](#bodyserializer) を提供します | +| `parseAs` | `"json"` \| `"text"` \| `"arrayBuffer"` \| `"blob"` \| `"stream"` | (任意) [組み込みのインスタンスメソッド](https://developer.mozilla.org/en-US/docs/Web/API/Response#instance_methods) を使用してレスポンスを解析します (デフォルト: `"json"`). `"stream"` は解析をスキップし、未処理のストリームを返します。 | +| `fetch` | `fetch` | リクエストに使用する Fetch インスタンス (デフォルト: `createClient` で指定された fetch ) | +| `middleware` | `Middleware[]` | [ドキュメントを参照](/openapi-fetch/middleware-auth) | +| (Fetch options) | | 有効なすべての fetch オプション(`headers`, `mode`, `cache`, `signal`など) ([ドキュメント](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options)) | ## wrapAsPathBasedClient @@ -53,7 +53,7 @@ pathBasedClient["/my-url"].GET(fetchOptions); `fetchOptions` はベースクライアントと同じです。 -Pathベースのクライアントは型推論の向上に役立ちますが、Proxyを使用するためランタイムのコストがかかります。 +Path ベースのクライアントは型推論の向上に役立ちますが、Proxy を使用するためランタイムのコストがかかります。 **createPathBasedClient** は `createClient` と `wrapAsPathBasedClient` を結合した便利なメソッドで、パスに基づく呼び出しスタイルを使用したい場合にのみ使用します。 @@ -79,13 +79,13 @@ pathBasedClient["/my-url"].GET(fetchOptions); ## querySerializer -OpenAPIは、パラメータに対してオブジェクトや配列をシリアライズする際に、[さまざまな方法をサポート](https://swagger.io/docs/specification/serialization/#query)しています(文字列、数値、ブール値などのプリミティブ型は常に同じ方法で処理されます)。デフォルトでは、このライブラリは配列を `style: "form"`, `explode: true` でシリアライズし、オブジェクトを `style: "deepObject"`, `explode: true` でシリアライズしますが、`querySerializer` オプションを使用して、この動作をカスタマイズすることができます(すべてのリクエストに対して `createClient()` で指定するか、個別のリクエストに対してのみ指定することができます)。 +OpenAPIは、パラメータに対してオブジェクトや配列をシリアライズする際に、[さまざまな方法をサポート](https://swagger.io/docs/specification/serialization/#query)しています(文字列、数値、ブール値などのプリミティブ型は常に同じ方法で処理されます)。デフォルトでは、このライブラリは配列を `style: "form", explode: true` でシリアライズし、オブジェクトを `style: "deepObject", explode: true` でシリアライズしますが、`querySerializer` オプションを使用して、この動作をカスタマイズすることができます(すべてのリクエストに対して `createClient()` で指定するか、個別のリクエストに対してのみ指定することができます)。 ### オブジェクト構文 openapi-fetchは、一般的なシリアル化方法を標準で提供しています: -| Option | Type | Description | +| オプション | 型 | 説明 | | :-------------- | :---------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `array` | SerializerOptions | 配列の `style` と `explode` を設定します ([ドキュメント](https://swagger.io/docs/specification/serialization/#query))。 デフォルト: `{ style: "form", explode: true }` | | `object` | SerializerOptions | オブジェクトの `style` と `explode` を設定します ([ドキュメント](https://swagger.io/docs/specification/serialization/#query))。 デフォルト: `{ style: "deepObject", explode: true }` | @@ -108,7 +108,7 @@ const client = createClient({ #### 配列のstyles -| Style | Array `id = [3, 4, 5]` | +| Style | 配列 `id = [3, 4, 5]` | | :--------------------------- | :---------------------- | | form | `/users?id=3,4,5` | | **form (exploded, default)** | `/users?id=3&id=4&id=5` | @@ -119,11 +119,11 @@ const client = createClient({ #### オブジェクトのstyles -| Style | Object `id = {"role": "admin", "firstName": "Alex"}` | -| :----------------------- | :--------------------------------------------------- | -| form | `/users?id=role,admin,firstName,Alex` | -| form (exploded) | `/users?role=admin&firstName=Alex` | -| **deepObject (default)** | `/users?id[role]=admin&id[firstName]=Alex` | +| Style | オブジェクト `id = {"role": "admin", "firstName": "Alex"}` | +| :----------------------- | :--------------------------------------------------------- | +| form | `/users?id=role,admin,firstName,Alex` | +| form (exploded) | `/users?role=admin&firstName=Alex` | +| **deepObject (default)** | `/users?id[role]=admin&id[firstName]=Alex` | ::: tip @@ -184,14 +184,14 @@ const { data, error } = await client.PUT("/submit", { openapi-fetchは、[3.1仕様書に記載されている](https://swagger.io/docs/specification/serialization/#path)ように、pathのシリアライズをサポートしています。これは、OpenAPIスキーマ内の特定のフォーマットに基づいて自動的に行われます。 -| Template | Style | Primitive `id = 5` | Array `id = [3, 4, 5]` | Object `id = {"role": "admin", "firstName": "Alex"}` | -| :---------------- | :------------------- | :----------------- | :----------------------- | :--------------------------------------------------- | -| **`/users/{id}`** | **simple (default)** | **`/users/5`** | **`/users/3,4,5`** | **`/users/role,admin,firstName,Alex`** | -| `/users/{id*}` | simple (exploded) | `/users/5` | `/users/3,4,5` | `/users/role=admin,firstName=Alex` | -| `/users/{.id}` | label | `/users/.5` | `/users/.3,4,5` | `/users/.role,admin,firstName,Alex` | -| `/users/{.id*}` | label (exploded) | `/users/.5` | `/users/.3.4.5` | `/users/.role=admin.firstName=Alex` | -| `/users/{;id}` | matrix | `/users/;id=5` | `/users/;id=3,4,5` | `/users/;id=role,admin,firstName,Alex` | -| `/users/{;id*}` | matrix (exploded) | `/users/;id=5` | `/users/;id=3;id=4;id=5` | `/users/;role=admin;firstName=Alex` | +| テンプレート | Style | プリミティブ `id = 5` | 配列 `id = [3, 4, 5]` | オブジェクト `id = {"role": "admin", "firstName": "Alex"}` | +| :---------------- | :------------------- | :-------------------- | :----------------------- | :--------------------------------------------------------- | +| **`/users/{id}`** | **simple (default)** | **`/users/5`** | **`/users/3,4,5`** | **`/users/role,admin,firstName,Alex`** | +| `/users/{id*}` | simple (exploded) | `/users/5` | `/users/3,4,5` | `/users/role=admin,firstName=Alex` | +| `/users/{.id}` | label | `/users/.5` | `/users/.3,4,5` | `/users/.role,admin,firstName,Alex` | +| `/users/{.id*}` | label (exploded) | `/users/.5` | `/users/.3.4.5` | `/users/.role=admin.firstName=Alex` | +| `/users/{;id}` | matrix | `/users/;id=5` | `/users/;id=3,4,5` | `/users/;id=role,admin,firstName,Alex` | +| `/users/{;id*}` | matrix (exploded) | `/users/;id=5` | `/users/;id=3;id=4;id=5` | `/users/;role=admin;firstName=Alex` | ## ミドルウェア @@ -226,7 +226,7 @@ client.use(myMiddleware); 各ミドルウェアのコールバックは、以下の内容を持つ `options` オブジェクトを受け取ります。 -| Name | Type | Description | +| 名前 | 型 | 説明 | | :----------- | :-------------- | :-------------------------------------------------------------------------------------------------- | | `request` | `Request` | エンドポイントに送信される現在の `Request` オブジェクト。 | | `response` | `Response` | エンドポイントから返された `Response` オブジェクト(`onRequest` の場合は `undefined` になります)。 | @@ -239,8 +239,8 @@ client.use(myMiddleware); 各ミドルウェアのコールバックは以下を返すことができます: -- **onRequest** リクエストを変更する `Request` またはそのままにする場合は `undefined`(スキップ)。 -- **onResponse** レスポンスを変更する `Response` またはそのままにする場合は `undefined`(スキップ)。 +- **onRequest** リクエストを変更するための `Request` またはそのままにする場合は `undefined`(スキップ)。 +- **onResponse** レスポンスを変更するための `Response` またはそのままにする場合は `undefined`(スキップ)。 ### ミドルウェアの削除 @@ -258,4 +258,4 @@ client.use(myMiddleware); client.eject(myMiddleware); ``` -追加のガイドと例については、[Middleware & Auth](/openapi-fetch/middleware-auth) を参照してください。 +追加のガイドと例については、[Middleware & Auth](/ja/openapi-fetch/middleware-auth) を参照してください。 diff --git a/docs/ja/openapi-fetch/examples.md b/docs/ja/openapi-fetch/examples.md index c1bcc06ed..d2a1d74bd 100644 --- a/docs/ja/openapi-fetch/examples.md +++ b/docs/ja/openapi-fetch/examples.md @@ -20,7 +20,7 @@ openapi-fetchを他のフレームワークやライブラリと組み合わせ ## Svelte / SvelteKit -[SvelteKit](https://kit.svelte.dev) の自動型推論機能は、クライアントサイドでのデータ取得や[ページデータの取得](https://kit.svelte.dev/docs/load#page-data)において、openapi-fetchの型を簡単に活用できます。また、追加のライブラリを必要とせずに動作します。SvelteKitは、ロード関数内で[カスタムフェッチ](https://kit.svelte.dev/docs/load#making-fetch-requests)を使用することを推奨しており、これは[フェッチオプション](/openapi-fetch/api#fetch-options)で実現できます。 +[SvelteKit](https://kit.svelte.dev) の自動型推論機能は、クライアントサイドでのデータ取得や[ページデータ](https://kit.svelte.dev/docs/load#page-data)の取得において、openapi-fetchの型を簡単に活用できます。また、追加のライブラリを必要とせずに動作します。SvelteKitは、ロード関数内で[カスタムフェッチ](https://kit.svelte.dev/docs/load#making-fetch-requests)を使用することを推奨しており、これは[フェッチオプション](/ja/openapi-fetch/api#fetch-オプション)で実現できます。 _注: SvelteKitを使用しない場合でも、`src/routes/+page.svelte` 内のルート例は、SvelteKitの機能を使用しておらず、どのようなセットアップにも適用可能です。_ diff --git a/docs/ja/openapi-fetch/index.md b/docs/ja/openapi-fetch/index.md index f42db0a0a..0536f6df5 100644 --- a/docs/ja/openapi-fetch/index.md +++ b/docs/ja/openapi-fetch/index.md @@ -9,7 +9,8 @@ openapi-fetchは、あなたのOpenAPIスキーマを取り込み、型安全な | ライブラリ | サイズ (min) | “GET” リクエスト\* | | :------------------------- | -----------: | :----------------------- | | openapi-fetch | `6 kB` | `300k` ops/s (最速) | -| openapi-typescript-fetch | `4 kB` | `150k` ops/s (2倍遅い) | +| openapi-typescript-fetch | `3 kB` | `300k` ops/s (最速) | +| feature-fetch | `15 kB` | `300k` ops/s (最速) | | axios | `32 kB` | `225k` ops/s (1.3倍遅い) | | superagent | `55 kB` | `50k` ops/s (6倍遅い) | | openapi-typescript-codegen | `367 kB` | `100k` ops/s (3倍遅い) | @@ -44,7 +45,7 @@ await client.PUT("/blogposts", { ::: -`data` と `error` は型チェックが行われ、VS Codeや他のTypeScript対応IDEでIntellisenseによる補完が利用可能です。同様に、リクエストの `body` もフィールドが型チェックされ、必要なパラメータが不足している場合や型の不一致がある場合にはエラーが発生します。 +`data` と `error` は型チェックが行われ、VS Code や他の TypeScript 対応 IDE で Intellisense による補完が利用可能です。同様に、リクエストの `body` もフィールドが型チェックされ、必要なパラメータが不足している場合や型の不一致がある場合にはエラーが発生します。 `GET()`, `PUT()`, `POST()` などは、ネイティブの [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) の薄いラッパーとして動作します([任意の呼び出しに変更することも可能です](/openapi-fetch/api#create-client))。 @@ -54,12 +55,12 @@ await client.PUT("/blogposts", { - ✅ すべてのパラメータ、リクエストボディ、レスポンスが型チェックされ、スキーマと100%一致する - ✅ APIの手動での型指定が不要 - ✅ バグを隠す可能性がある `any` 型の排除 -- ✅ バグを隠す可能性がある `as` 型の上書きも排除 -- ✅ これらすべてが**5 kb**のクライアントパッケージで実現 🎉 +- ✅ バグを隠す可能性がある `as` による型の上書きも排除 +- ✅ これらすべてが**6 kb**のクライアントパッケージで実現 🎉 ## セットアップ -このライブラリと [openapi-typescript](/introduction) をインストールします: +このライブラリと [openapi-typescript](/ja/introduction) をインストールします: ```bash npm i openapi-fetch @@ -68,7 +69,7 @@ npm i -D openapi-typescript typescript ::: tip 強く推奨 -`tsconfig.json`で [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) を有効にしてください ([ドキュメント](/advanced#enable-nouncheckedindexaccess-in-your-tsconfigjson)) +`tsconfig.json`で [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) を有効にしてください ([ドキュメント](/ja/advanced#tsconfigで-nouncheckedindexedaccess-を有効にする)) ::: @@ -131,17 +132,17 @@ const { data, error } = await client.PUT("/blogposts", { ::: -1. HTTPメソッドは `createClient()` から直接取得します。 -2. `GET()` , `PUT()` , などに希望するpathを渡します。 +1. HTTPメソッドを `createClient()` から直接取得します。 +2. `GET()` , `PUT()` などに希望する `path` を渡します。 3. TypeScriptが欠落しているものや無効なものがあれば有用なエラーを返します。 ### Pathname -`GET()` , `PUT()` , `POST()` などのpathnameは、スキーマと厳密に一致している必要があります。例では、URLは `/blogposts/{post_id}` です。このライブラリは、すべての `path` パラメータをすぐに置き換え、それらが型チェックされるようにします。 +`GET()` , `PUT()` , `POST()` などのpathnameは、**スキーマと厳密に一致している必要があります**。例では、URLは `/blogposts/{post_id}` です。このライブラリは、すべての `path` パラメータをすぐに置き換え、それらが型チェックされるようにします。 ::: tip -openapi-fetchはURLから型を推論します。動的な実行時の値よりも静的な文字列値を優先してください。例: +openapi-fetch は URL から型を推論します。動的な実行時の値よりも静的な文字列値を優先してください。例: - ✅ `"/blogposts/{post_id}"` - ❌ `[...pathParts].join("/") + "{post_id}"` @@ -188,8 +189,8 @@ client["/blogposts/{post_id}"].GET({ }); ``` -これにはパフォーマンスの影響があり、ミドルウェアを直接アタッチすることはできません。 -詳細については、[`wrapAsPathBasedClient`](/openapi-fetch/api#wrapAsPathBasedClient) を参照してください。 +これにはパフォーマンスの影響があり、ミドルウェアを直接付与することはできません。 +詳細については、[`wrapAsPathBasedClient`](/ja/openapi-fetch/api#wrapaspathbasedclient) を参照してください。 ## サポート diff --git a/docs/ja/openapi-react-query/index.md b/docs/ja/openapi-react-query/index.md index 1579e20f0..ada9a3be5 100644 --- a/docs/ja/openapi-react-query/index.md +++ b/docs/ja/openapi-react-query/index.md @@ -4,15 +4,15 @@ title: openapi-react-query # Introduction -openapi-react-queryは、[@tanstack/react-query](https://tanstack.com/query/latest/docs/framework/react/overview) と連携してOpenAPIスキーマを扱うための、1kbの型安全な軽量ラッパーです。 +openapi-react-queryは、[@tanstack/react-query](https://tanstack.com/query/latest/docs/framework/react/overview) と連携してOpenAPIスキーマを扱うための型安全な軽量ラッパー(1kb)です。 -これは [openapi-fetch](../openapi-fetch/)] および [openapi-typescript](../introduction) を使用することで、以下のすべての機能が提供されます: +これは [openapi-fetch](../openapi-fetch/) および [openapi-typescript](../introduction) を使用することで、以下のすべての機能が提供されます: - ✅ URLやパラメータのタイプミスが起こらない - ✅ すべてのパラメータ、リクエストボディ、レスポンスが型チェックされ、スキーマと100%一致する - ✅ APIの手動での型指定が不要 - ✅ バグを隠す可能性がある `any` 型の排除 -- ✅ バグを隠す可能性がある `as` 型の上書きも排除 +- ✅ バグを隠す可能性がある `as` による型の上書きも排除 ::: code-group @@ -58,7 +58,7 @@ npm i -D openapi-typescript typescript ::: tip 強く推奨 -`tsconfig.json`で [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) を有効にしてください ([ドキュメント](/advanced#enable-nouncheckedindexaccess-in-your-tsconfigjson)) +`tsconfig.json`で [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) を有効にしてください ([ドキュメント](/ja/advanced#tsconfigで-nouncheckedindexedaccess-を有効にする)) ::: @@ -70,7 +70,7 @@ npx openapi-typescript ./path/to/api/v1.yaml -o ./src/lib/api/v1.d.ts ## 基本的な使い方 -スキーマから型が生成されたら、[fetchクライアント](../introduction.md)とreact-queryクライアントを作成し、APIにクエリを実行できます。 +スキーマから型が生成されたら、[fetch クライアント](../introduction.md)と react-query クライアントを作成し、API にクエリを実行できます。 ::: code-group diff --git a/docs/ja/openapi-react-query/use-mutation.md b/docs/ja/openapi-react-query/use-mutation.md index 75fce3a9d..4172efed1 100644 --- a/docs/ja/openapi-react-query/use-mutation.md +++ b/docs/ja/openapi-react-query/use-mutation.md @@ -4,9 +4,9 @@ title: useMutation # {{ $frontmatter.title }} -`useMutation` メソッドを使用すると、react-query本来の [useMutation](https://tanstack.com/query/latest/docs/framework/react/guides/mutations) を利用できます。 +`useMutation` メソッドを使用すると、react-query 本来の [useMutation](https://tanstack.com/query/latest/docs/framework/react/guides/mutations) を利用できます。 -- resultは本来の関数と同じです。 +- result は本来の関数と同じです。 - `mutationKey` は `[method, path]`です。 - `data` と `error` は完全に型付けされています。 @@ -26,7 +26,7 @@ export const App = () => { return ( ); }; @@ -54,15 +54,15 @@ const query = $api.useQuery(method, path, options, queryOptions, queryClient); **引数** - `method` **(必須)** - - リクエストに使用するHTTPメソッド + - リクエストに使用する HTTP メソッド - このメソッドがキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 - `path` **(必須)** - リクエストに使用するパス名 - スキーマ内で指定されたメソッドに対応する利用可能なパスでなければなりません。 - パス名はキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 - `queryOptions` - - 本来の useMutation オプション + - 本来の `useMutation` オプション - [See more information](https://tanstack.com/query/latest/docs/framework/react/reference/useMutation) - `queryClient` - - 本来の queryClient オプション + - 本来の `queryClient` オプション - [See more information](https://tanstack.com/query/latest/docs/framework/react/reference/useMutation) diff --git a/docs/ja/openapi-react-query/use-query.md b/docs/ja/openapi-react-query/use-query.md index fcdeb428f..a44f0c2e4 100644 --- a/docs/ja/openapi-react-query/use-query.md +++ b/docs/ja/openapi-react-query/use-query.md @@ -1,11 +1,12 @@ --- title: useQuery --- + # {{ $frontmatter.title }} -`useQuery` メソッドを使用すると、react-query本来の [useQuery](https://tanstack.com/query/latest/docs/framework/react/guides/queries) を利用できます。 +`useQuery` メソッドを使用すると、react-query 本来の [useQuery](https://tanstack.com/query/latest/docs/framework/react/guides/queries) を利用できます。 -- resultは本来の関数と同じです。 +- result は本来の関数と同じです。 - `functionKey` は `[method, path, params]` です。 - `data` と `error` は完全に型付けされています。 - 第4引数としてクエリオプションを渡すことができます。 @@ -28,8 +29,8 @@ export const App = () => { }, }); - if (!data || isLoading) return "Loading..."; - if (error) return `An error occured: ${error.message}`; + if (!data || isLoading) return "読み込み中..."; + if (error) return `エラーが発生しました: ${error.message}`; return
{data.firstname}
; }; @@ -57,15 +58,15 @@ const query = $api.useQuery(method, path, options, queryOptions, queryClient); **引数** - `method` **(必須)** - - リクエストに使用するHTTPメソッド + - リクエストに使用する HTTP メソッド - このメソッドがキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 - `path` **(必須)** - リクエストに使用するパス名 - スキーマ内で指定されたメソッドに対応する利用可能なパスでなければなりません。 - パス名はキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 - `options` - - リクエストに使用するfetchオプション - - OpenAPIスキーマがパラメータを要求する場合のみ必要です。 + - リクエストに使用する fetch オプション + - OpenAPI スキーマがパラメータを要求する場合のみ必要です。 - オプションの `params` はキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 - `queryOptions` - 本来の `useQuery` オプション diff --git a/docs/ja/openapi-react-query/use-suspense-query.md b/docs/ja/openapi-react-query/use-suspense-query.md index 20ae88e67..622c3d94a 100644 --- a/docs/ja/openapi-react-query/use-suspense-query.md +++ b/docs/ja/openapi-react-query/use-suspense-query.md @@ -4,9 +4,9 @@ title: useSuspenseQuery # {{ $frontmatter.title }} -`useSuspenseQuery` メソッドを使用すると、react-query本来の [useSuspenseQuery](https://tanstack.com/query/latest/docs/framework/react/guides/suspense)を利用できます。 +`useSuspenseQuery` メソッドを使用すると、react-query 本来の [useSuspenseQuery](https://tanstack.com/query/latest/docs/framework/react/guides/suspense) を利用できます。 -- resultは本来の関数と同じです。 +- result は本来の関数と同じです。 - `functionKey` は `[method, path, params]` です。 - `data` と `error` は完全に型付けされています。 - 第4引数としてクエリオプションを渡すことができます。 @@ -45,7 +45,7 @@ export const App = () => { ```ts [src/api.ts] import createFetchClient from "openapi-fetch"; import createClient from "openapi-react-query"; -import type { paths } from "./my-openapi-3-schema"; // generated by openapi-typescript +import type { paths } from "./my-openapi-3-schema"; // openapi-typescriptで生成された型 const fetchClient = createFetchClient({ baseUrl: "https://myapi.dev/v1/", @@ -70,15 +70,15 @@ const query = $api.useSuspenseQuery( **引数** - `method` **(必須)** - - リクエストに使用するHTTPメソッド + - リクエストに使用する HTTP メソッド - このメソッドがキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 - `path` **(必須)** - リクエストに使用するパス名 - スキーマ内で指定されたメソッドに対応する利用可能なパスでなければなりません。 - パス名はキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 - `options` - - リクエストに使用するfetchオプション - - OpenAPIスキーマがパラメータを要求する場合のみ必要です。 + - リクエストに使用する fetch オプション + - OpenAPI スキーマがパラメータを要求する場合のみ必要です。 - オプションの `params` はキーとして使用されます。詳細については [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) を参照してください。 - `queryOptions` - 本来の `useSuspenseQuery` オプション diff --git a/docs/node.md b/docs/node.md index d99ebbd67..cad478d8a 100644 --- a/docs/node.md +++ b/docs/node.md @@ -81,7 +81,7 @@ const ast = await openapiTS(mySchema, { redocly }); ## Options -The Node API supports all the [CLI flags](/cli#options) in `camelCase` format, plus the following additional options: +The Node API supports all the [CLI flags](/cli#flags) in `camelCase` format, plus the following additional options: | Name | Type | Default | Description | | :-------------- | :-------------: | :-------------: | :------------------------------------------------------------------------------------------- | From f42bea9b2cdd8fb0ac326cecf4baadb0d82f4f49 Mon Sep 17 00:00:00 2001 From: Hikaru Yoshino Date: Sat, 17 Aug 2024 02:15:57 +0900 Subject: [PATCH 23/24] docs(en, zh): fix link --- docs/openapi-fetch/index.md | 4 ++-- docs/openapi-react-query/index.md | 2 +- docs/zh/introduction.md | 2 +- docs/zh/openapi-fetch/index.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/openapi-fetch/index.md b/docs/openapi-fetch/index.md index 0298aa08c..844eb9dbc 100644 --- a/docs/openapi-fetch/index.md +++ b/docs/openapi-fetch/index.md @@ -69,7 +69,7 @@ npm i -D openapi-typescript typescript ::: tip Highly recommended -Enable [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) in your `tsconfig.json` ([docs](/advanced#enable-nouncheckedindexaccess-in-your-tsconfigjson)) +Enable [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) in your `tsconfig.json` ([docs](/advanced#enable-nouncheckedindexedaccess-in-tsconfig)) ::: @@ -189,7 +189,7 @@ client["/blogposts/{post_id}"].GET({ ``` Note that this has performance implications and does not allow to attach middlewares directly. -See [`wrapAsPathBasedClient`](/openapi-fetch/api#wrapAsPathBasedClient) for more. +See [`wrapAsPathBasedClient`](/openapi-fetch/api#wrapaspathbasedclient) for more. ## Support diff --git a/docs/openapi-react-query/index.md b/docs/openapi-react-query/index.md index 43d28dab7..9bb1d3470 100644 --- a/docs/openapi-react-query/index.md +++ b/docs/openapi-react-query/index.md @@ -57,7 +57,7 @@ npm i -D openapi-typescript typescript ::: tip Highly recommended -Enable [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) in your `tsconfig.json` ([docs](/advanced#enable-nouncheckedindexaccess-in-your-tsconfigjson)) +Enable [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) in your `tsconfig.json` ([docs](/advanced#enable-nouncheckedindexedaccess-in-tsconfig)) ::: diff --git a/docs/zh/introduction.md b/docs/zh/introduction.md index 80b98ae54..695b2f3b8 100644 --- a/docs/zh/introduction.md +++ b/docs/zh/introduction.md @@ -13,7 +13,7 @@ description: Quickstart openapi-typescript 使用 Node.js 快速将 [OpenAPI 3.0 & 3.1](https://spec.openapis.org/oas/latest.html) 模式转换为 TypeScript。无需 Java/node-gyp/运行 OpenAPI 服务器。 -该代码受到 [MIT 许可](https://github.com/openapi-ts/openapi-typescript/blob/main/packages/openapi-typescript/LICENSE") 保护,可免费使用。 +该代码受到 [MIT 许可](https://github.com/openapi-ts/openapi-typescript/blob/main/packages/openapi-typescript/LICENSE) 保护,可免费使用。 ## 特性 diff --git a/docs/zh/openapi-fetch/index.md b/docs/zh/openapi-fetch/index.md index 79bbd1e2f..4f6dcf79b 100644 --- a/docs/zh/openapi-fetch/index.md +++ b/docs/zh/openapi-fetch/index.md @@ -73,7 +73,7 @@ npm i -D openapi-typescript typescript ::: tip 强烈推荐 -在 `tsconfig.json` 中启用 [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess)([文档](/advanced#enable-nouncheckedindexaccess-in-your-tsconfigjson)) +在 `tsconfig.json` 中启用 [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess)([文档](/zh/advanced#在-tsconfig-中启用-nouncheckedindexedaccess)) ::: From e2e888a2ca631aab64806e60b5d7d0c433478388 Mon Sep 17 00:00:00 2001 From: Drew Powers Date: Fri, 16 Aug 2024 11:41:11 -0600 Subject: [PATCH 24/24] Deploy to Cloudflare