umbraco-openapi-client について
Umbraco のバックオフィス拡張からカスタム API を呼び出す開発者向けの実装ガイドです。型付き TypeScript OpenAPI クライアントの生成と、Umbraco の認証コンテキストを使った設定を扱います。
主な機能
- 01TypeScript OpenAPI クライアントの生成
- 02Umbraco のベアラートークン認証設定
- 03C# モデルからの型生成
- 04クライアント設定と認証手順の解説
- 05よくある認証ミスの確認
活用シーン
- 01バックオフィス UI からカスタム API を呼び出す
- 02ツリーやワークスペースに API データを読み込む
- 03カスタムコントローラー用クライアントを生成する
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ umbraco/ umbraco-cms-backoffice-skills --skill umbraco-openapi-clientインストール後、Claude Code で/umbraco-openapi-clientを入力して読み込まれたか確認します。
詳細
Umbraco OpenAPI クライアントのセットアップ
重要: これが重要な理由
Umbraco バックオフィス API との通信に生の fetch() 呼び出しを決して使用しないでください。 生の fetch 呼び出しは、Umbraco が要求するベアラートークン認証を含まないため、401 Unauthorized エラーになります。
常に Umbraco の認証コンテキストで構成された生成済みの OpenAPI クライアントを使用してください。 これにより以下が保証されます。
- 適切なベアラートークン認証
- 型安全な API 呼び出し
- トークン更新の自動処理
これを使用する場面
以下のいずれかに該当する場合は常にこのパターンを使用してください。
[BackOfficeRoute]を付けたカスタム C# API コントローラーを作成する場合- バックオフィスのフロントエンドからカスタム API を呼び出す必要がある場合
- カスタムエンドポイントからデータを読み込むツリー、ワークスペース、その他の UI を構築する場合
セットアップの概要
セットアップは 4 つの部分から構成されます。
- C# バックエンド: Swagger/OpenAPI ドキュメントを持つコントローラー
- クライアントの依存関係:
@hey-api/openapi-ts(@hey-api/client-fetchプラグインはこれに同梱されています) - 生成スクリプト: swagger.json を取得して TypeScript クライアントを生成します
- エントリポイントの構成: クライアントを Umbraco 認証で構成します
手順ごとの実装
1. C# バックエンドのセットアップ(Swagger/OpenAPI)
API はバックオフィスの OpenAPI ドキュメントとして公開する必要があります。コンポーザーを作成します。
Umbraco 18 以降: OpenAPI スタックは Swashbuckle の
SwaggerGenOptions(およびBackOfficeSecurityRequirementsOperationFilterBase/OperationIdHandler型)から、流暢なAddBackOfficeOpenApiDocument(...)ビルダーへ移行しました。以下 のパターンを使用してください。以前のSwaggerGenOptionsのアプローチは v18 では コンパイルできなくなりました。
// Composers/MyApiComposer.cs
using Umbraco.Cms.Api.Common.OpenApi;
using Umbraco.Cms.Api.Management.OpenApi;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
namespace MyExtension.Composers;
public class MyApiComposer : IComposer
{
public void Compose(IUmbracoBuilder builder) =>
// Registers a dedicated backoffice OpenAPI document, served at
// /umbraco/openapi/{ApiName}.json and browsable via Swagger UI.
// See https://docs.umbraco.com/umbraco-cms/extend-your-project/tutorials/creating-a-backoffice-api
builder.AddBackOfficeOpenApiDocument(
Constants.ApiName,
document => document
.WithTitle("My Extension API")
.WithBackOfficeAuthentication()
.WithJsonOptions(Umbraco.Cms.Core.Constants.JsonOptionsNames.BackOffice)
.ConfigureOpenApiOptions(options =>
options.AddDocumentTransformer((doc, _, _) =>
{
doc.Info.Version = "1.0";
return Task.CompletedTask;
})));
}
// Constants
public static class Constants
{
public const string ApiName = "myextension";
}
2. クライアントの package.json 依存関係
Client/package.json に追加します。
{
"scripts": {
"generate-client": "node scripts/generate-openapi.js https://localhost:44325/umbraco/openapi/myextension.json"
},
"devDependencies": {
"@hey-api/openapi-ts": "^0.97.0",
"chalk": "^5.4.1",
"node-fetch": "^3.3.2"
}
}
3. 生成スクリプト
Client/scripts/generate-openapi.js を作成します。
import fetch from "node-fetch";
import chalk from "chalk";
import { createClient, defaultPlugins } from "@hey-api/openapi-ts";
console.log(chalk.green("Generating OpenAPI client..."));
const swaggerUrl = process.argv[2];
if (swaggerUrl === undefined) {
console.error(chalk.red(`ERROR: Missing URL to OpenAPI spec`));
process.exit(1);
}
// Ignore self-signed certificates on localhost
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
console.log(`Fetching OpenAPI definition from ${chalk.yellow(swaggerUrl)}`);
fetch(swaggerUrl)
.then(async (response) => {
if (!response.ok) {
console.error(chalk.red(`ERROR: ${response.status} ${response.statusText}`));
return;
}
await createClient({
input: swaggerUrl,
output: "src/api",
plugins: [
...defaultPlugins,
{
name: "@hey-api/client-fetch",
bundle: true,
exportFromIndex: true,
throwOnError: true,
},
{
name: "@hey-api/typescript",
enums: "typescript",
},
{
name: "@hey-api/sdk",
asClass: true,
},
],
});
console.log(chalk.green("Client generated successfully!"));
})
.catch((error) => {
console.error(`ERROR: ${chalk.red(error.message)}`);
});
4. エントリポイントの構成(重要)
エントリポイントで、生成されたクライアントを Umbraco の認証コンテキストで構成します。
// src/entrypoints/entrypoint.ts
import type { UmbEntryPointOnInit, UmbEntryPointOnUnload } from "@umbraco-cms/backoffice/extension-api";
import { UMB_AUTH_CONTEXT } from "@umbraco-cms/backoffice/auth";
import { client } from "../api/client.gen.js";
export const onInit: UmbEntryPointOnInit = (host, _extensionRegistry) => {
// CRITICAL: Configure the OpenAPI client with authentication
host.consumeContext(UMB_AUTH_CONTEXT, (authContext) => {
if (!authContext) return;
// configureClient() sets baseUrl/credentials/bearer token AND binds the
// default interceptors (401 retry, problem-details error notifications).
// It guards against configuring the same client twice, so it's safe to
// call for umbHttpClient and your own generated client alike.
authContext.configureClient(client);
console.log("API client configured with auth");
});
};
export const onUnload: UmbEntryPointOnUnload = (_host, _extensionRegistry) => {
// Cleanup if needed
};
手動による代替方法(デフォルトのインターセプターをスキップする)
クライアント構成を完全に制御する必要があり、デフォルトの インターセプターを必要としない場合は、代わりにクライアントを手動で構成できます。
const config = authContext.getOpenApiConfiguration();
client.setConfig({
baseUrl: config.base,
credentials: config.credentials,
auth: config.token, // This provides the bearer token!
});
これは正しく認証されますが、configureClient() が組み込む 401 リトライと
problem-details のエラー処理が失われます。また、認証をブラックボックスとして扱う
のではなく、現在のベアラートークンの仕組みに結合されることになります。
5. 生成されたクライアントの使用
npm run generate-client を実行した後、生成されたサービスを使用します。
// In your workspace context, repository, or data source
import { MyExtensionService } from "../api/index.js";
// The client handles auth automatically!
const response = await MyExtensionService.getItems({
query: { skip: 0, take: 50 },
});
const item = await MyExtensionService.getItem({
path: { id: "some-guid" },
});
await MyExtensionService.createItem({
body: { name: "New Item", value: 123 },
});
生成ワークフロー
- Umbraco を起動 - swagger.json エンドポイントにアクセスできる必要があります
- 生成を実行:
npm run generate-client - 生成されたファイルは
src/api/に出力されます。types.gen.ts- C# モデルから生成された TypeScript 型sdk.gen.ts- 型付きメソッドを持つサービスクラスclient.gen.ts- HTTP クライアントの構成index.ts- すべてを再エクスポート
よくある間違い
❌ 間違い: 生の fetch
// This will get 401 Unauthorized!
const response = await fetch('/umbraco/myextension/api/v1/items');
❌ 間違い: credentials のみを指定した fetch
// Still fails - cookies don't work for Management API
const response = await fetch('/umbraco/myextension/api/v1/items', {
credentials: 'include'
});
✅ 正しい: 生成された OpenAPI クライアント
// Client is configured with bearer token in entry point
const response = await MyExtensionService.getItems();
参考例
以下で完全な動作する実装を確認できます。
examples/notes-wiki/Client/- 完全な OpenAPI クライアントのセットアップexamples/tree-example/Client/- OpenAPI 統合を備えたツリー
作成する主要ファイル
Composers/MyApiComposer.cs- Swagger の登録Client/scripts/generate-openapi.js- 生成スクリプトClient/src/entrypoints/entrypoint.ts- 認証の構成Client/src/api/- 生成済み(手動で編集しないでください)
以上です! 常に API クライアントを生成し、認証で構成してください。認証が必要なエンドポイントに生の fetch を決して使用しないでください。