umbraco-repository-pattern について
Umbraco バックオフィスのリポジトリとデータソースを構築するスキルです。データ操作、任意のセッションストア、コンテキストによる調整を整理し、独自 API 呼び出しには Umbraco 認証を設定した生成済み OpenAPI クライアントを使うよう案内します。
主な機能
- 01リポジトリとデータソースのパターン
- 02CRUD 操作の構成
- 03任意のセッションストア
- 04コンテキストによる調整
- 05OpenAPI クライアント認証の案内
活用シーン
- 01UI とデータアクセスの分離
- 02基盤となるデータソースの切り替え
- 03コンテキストでデータと状態を調整
- 04ツリーリポジトリの構築
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ umbraco/ umbraco-cms-backoffice-skills --skill umbraco-repository-patternインストール後、Claude Code で/umbraco-repository-patternを入力して読み込まれたか確認します。
詳細
Umbraco リポジトリパターン
これは何ですか?
リポジトリは、データ要求と更新通知に対するバックオフィスのエントリポイントであり、さまざまなソース(サーバー、オフラインデータベース、ストア、Signal-R)からのデータアクセスを抽象化します。データ操作を管理する構造化された方法を提供し、ビジネスロジックを直接的なデータアクセスから分離することで、保守と拡張を容易にします。リポジトリは背後でデータソースを使用するため、利用側はデータがどこに、どのように保存されているかを知らなくてもデータを扱うことができます。
重要: API 認証
カスタム API 呼び出しに生の fetch() を決して使用しないでください。 これは 401 Unauthorized エラーの原因となります。
必ず Umbraco の認証コンテキストで構成された生成済みの OpenAPI クライアントを使用してください。 セットアップ手順については umbraco-openapi-client スキルを参照してください。
ドキュメント
実装する前に、必ず最新のドキュメントを取得してください:
- メインドキュメント: https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/foundation/repositories
- データの操作: https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/foundation
- ストア: https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/foundation
- 基盤: https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/foundation
ワークフロー
- ドキュメントを取得 - 上記の URL に対して WebFetch を使用します
- 質問する - どのデータを管理しますか? 必要な CRUD 操作は何ですか? データソースの種類は何ですか?
- コードを生成 - 最新のドキュメントに基づいてリポジトリとデータソースを実装します
- 説明 - 作成したものとその使用方法を示します
最小限の例
リポジトリの登録
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { MyRepository } from './my-repository.js';
const repositoryManifest = {
type: 'repository',
alias: 'My.Repository',
name: 'My Repository',
api: MyRepository,
};
umbExtensionsRegistry.register(repositoryManifest);
基本的なリポジトリの実装(OpenAPI クライアントの使用)
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
// Import from generated OpenAPI client (see umbraco-openapi-client skill)
import { MyExtensionService } from '../api/index.js';
export class MyRepository extends UmbControllerBase {
constructor(host: UmbControllerHost) {
super(host);
}
async getAll() {
// Use generated OpenAPI client - handles auth automatically
const response = await MyExtensionService.getAll();
return response.data;
}
async getById(id: string) {
const response = await MyExtensionService.getById({ path: { id } });
return response.data;
}
async create(data: any) {
const response = await MyExtensionService.create({ body: data });
return response.data;
}
async update(id: string, data: any) {
const response = await MyExtensionService.update({
path: { id },
body: data,
});
return response.data;
}
async delete(id: string) {
await MyExtensionService.delete({ path: { id } });
}
}
コンテキストでのリポジトリの使用
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
import { MyRepository } from './my-repository.js';
export class MyContext extends UmbContextBase<MyContext> {
#repository = new MyRepository(this);
#items = new UmbArrayState([]);
readonly items = this.#items.asObservable();
async loadItems() {
const data = await this.#repository.getAll();
this.#items.setValue(data);
}
async createItem(item: any) {
const newItem = await this.#repository.create(item);
this.#items.setValue([...this.#items.getValue(), newItem]);
}
async deleteItem(id: string) {
await this.#repository.delete(id);
this.#items.setValue(
this.#items.getValue().filter(item => item.id !== id)
);
}
}
データソースを使用したリポジトリ(OpenAPI クライアントの使用)
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { MyDataSource } from './my-data-source.js';
export class MyRepository extends UmbControllerBase {
#dataSource = new MyDataSource(this);
async getAll() {
return await this.#dataSource.getAll();
}
async getById(id: string) {
return await this.#dataSource.getById(id);
}
}
// Data Source - uses generated OpenAPI client
import { MyExtensionService } from '../api/index.js';
export class MyDataSource extends UmbControllerBase {
async getAll() {
// Use OpenAPI client - NEVER raw fetch()
const response = await MyExtensionService.getAll();
return response.data;
}
async getById(id: string) {
const response = await MyExtensionService.getById({ path: { id } });
return response.data;
}
}
ツリーリポジトリの例
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
export class MyTreeRepository extends UmbControllerBase {
#dataSource: UmbTreeDataSource;
constructor(host: UmbControllerHost) {
super(host);
this.#dataSource = new MyTreeDataSource(this);
}
async getRootItems() {
return await this.#dataSource.getRootItems();
}
async getChildrenOf(parentKey: string) {
return await this.#dataSource.getChildrenOf(parentKey);
}
async getAncestorsOf(key: string) {
return await this.#dataSource.getAncestorsOf(key);
}
}
主要な概念
リポジトリ: データ操作のエントリポイントであり、データアクセスを抽象化します
データソース: 実際にデータを取得/保存する基盤となる仕組み
ストア: State オブジェクトを使用してセッションを通じてデータを保持するオプションのレイヤー
ホスト要素: リポジトリは、適切なコンテキストのレンダリングのためにホストと共にインスタンス化する必要があります
関心の分離:
- リポジトリ = 利用可能な操作は何か
- データソース = データがどのように取得/保存されるか
- ストア = データがどこにキャッシュされるか
- コンテキスト = それらすべてを誰が調整するか
利点:
- UI とデータレイヤー間の疎結合
- 交換可能なデータソース
- テストと保守の容易化
- 一貫したデータアクセスパターン
使用パターン:
- CRUD メソッドを持つリポジトリを定義します
- 実際の I/O 用のデータソースを実装します
- コンテキストでリポジトリをインスタンス化します
- コンテキストが状態とリポジトリを調整します
- UI がコンテキストから状態を監視します
以上です! 常に最新のドキュメントを取得し、例は最小限に保ち、完全に動作するコードを生成してください。