mcpField
T
typespec-api-operations

typespec-api-operations

github.com/github開発40.5k8.8k 回インストール今日更新
リポジトリ

typespec-api-operations について

typespec-api-operationsは、Microsoft 365 Copilot向けの既存TypeSpec APIプラグインにREST操作を追加するスキルです。CRUDの例、パラメーター、確認、アダプティブカード、テスト用プロンプトを扱います。

主な機能

  1. 01GET、POST、PATCH、DELETEの例
  2. 02パス、クエリ、ボディ、ヘッダーのパラメーター
  3. 03確認とアダプティブカードのパターン
  4. 04レスポンスモデルとエラーレスポンス
  5. 05ルーティングとドキュメントの指針

活用シーン

  1. 01TypeSpec APIへのCRUD操作の追加
  2. 02フィルターと項目識別子の定義
  3. 03破壊的な操作への確認の追加
  4. 04プロンプトによるCopilot API操作の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/github/awesome-copilot --skill typespec-api-operations

インストール後、Claude Code で/typespec-api-operationsを入力して読み込まれたか確認します。

詳細

TypeSpec API 操作の追加

Microsoft 365 Copilot 用の既存の TypeSpec API プラグインに RESTful 操作を追加します。

GET 操作の追加

シンプルな GET - すべての項目を一覧表示
/**
 * List all items.
 */
@route("/items")
@get op listItems(): Item[];
クエリパラメーター付き GET - 結果を絞り込む
/**
 * List items filtered by criteria.
 * @param userId Optional user ID to filter items
 */
@route("/items")
@get op listItems(@query userId?: integer): Item[];
パスパラメーター付き GET - 単一の項目を取得
/**
 * Get a specific item by ID.
 * @param id The ID of the item to retrieve
 */
@route("/items/{id}")
@get op getItem(@path id: integer): Item;
Adaptive Card 付き GET
/**
 * List items with adaptive card visualization.
 */
@route("/items")
@card(#{
  dataPath: "$",
  title: "$.title",
  file: "item-card.json"
})
@get op listItems(): Item[];

Adaptive Card を作成します (appPackage/item-card.json):

{
  "type": "AdaptiveCard",
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.5",
  "body": [
    {
      "type": "Container",
      "$data": "${$root}",
      "items": [
        {
          "type": "TextBlock",
          "text": "**${if(title, title, 'N/A')}**",
          "wrap": true
        },
        {
          "type": "TextBlock",
          "text": "${if(description, description, 'N/A')}",
          "wrap": true
        }
      ]
    }
  ],
  "actions": [
    {
      "type": "Action.OpenUrl",
      "title": "View Details",
      "url": "https://example.com/items/${id}"
    }
  ]
}

POST 操作の追加

シンプルな POST - 項目を作成
/**
 * Create a new item.
 * @param item The item to create
 */
@route("/items")
@post op createItem(@body item: CreateItemRequest): Item;

model CreateItemRequest {
  title: string;
  description?: string;
  userId: integer;
}
確認付き POST
/**
 * Create a new item with confirmation.
 */
@route("/items")
@post
@capabilities(#{
  confirmation: #{
    type: "AdaptiveCard",
    title: "Create Item",
    body: """
    Are you sure you want to create this item?
      * **Title**: {{ function.parameters.item.title }}
      * **User ID**: {{ function.parameters.item.userId }}
    """
  }
})
op createItem(@body item: CreateItemRequest): Item;

PATCH 操作の追加

シンプルな PATCH - 項目を更新
/**
 * Update an existing item.
 * @param id The ID of the item to update
 * @param item The updated item data
 */
@route("/items/{id}")
@patch op updateItem(
  @path id: integer,
  @body item: UpdateItemRequest
): Item;

model UpdateItemRequest {
  title?: string;
  description?: string;
  status?: "active" | "completed" | "archived";
}
確認付き PATCH
/**
 * Update an item with confirmation.
 */
@route("/items/{id}")
@patch
@capabilities(#{
  confirmation: #{
    type: "AdaptiveCard",
    title: "Update Item",
    body: """
    Updating item #{{ function.parameters.id }}:
      * **Title**: {{ function.parameters.item.title }}
      * **Status**: {{ function.parameters.item.status }}
    """
  }
})
op updateItem(
  @path id: integer,
  @body item: UpdateItemRequest
): Item;

DELETE 操作の追加

シンプルな DELETE
/**
 * Delete an item.
 * @param id The ID of the item to delete
 */
@route("/items/{id}")
@delete op deleteItem(@path id: integer): void;
確認付き DELETE
/**
 * Delete an item with confirmation.
 */
@route("/items/{id}")
@delete
@capabilities(#{
  confirmation: #{
    type: "AdaptiveCard",
    title: "Delete Item",
    body: """
    ⚠️ Are you sure you want to delete item #{{ function.parameters.id }}?
    This action cannot be undone.
    """
  }
})
op deleteItem(@path id: integer): void;

完全な CRUD の例

サービスとモデルを定義する
@service
@server("https://api.example.com")
@actions(#{
  nameForHuman: "Items API",
  descriptionForHuman: "Manage items",
  descriptionForModel: "Read, create, update, and delete items"
})
namespace ItemsAPI {
  
  // Models
  model Item {
    @visibility(Lifecycle.Read)
    id: integer;
    
    userId: integer;
    title: string;
    description?: string;
    status: "active" | "completed" | "archived";
    
    @format("date-time")
    createdAt: utcDateTime;
    
    @format("date-time")
    updatedAt?: utcDateTime;
  }

  model CreateItemRequest {
    userId: integer;
    title: string;
    description?: string;
  }

  model UpdateItemRequest {
    title?: string;
    description?: string;
    status?: "active" | "completed" | "archived";
  }

  // Operations
  @route("/items")
  @card(#{ dataPath: "$", title: "$.title", file: "item-card.json" })
  @get op listItems(@query userId?: integer): Item[];

  @route("/items/{id}")
  @card(#{ dataPath: "$", title: "$.title", file: "item-card.json" })
  @get op getItem(@path id: integer): Item;

  @route("/items")
  @post
  @capabilities(#{
    confirmation: #{
      type: "AdaptiveCard",
      title: "Create Item",
      body: "Creating: **{{ function.parameters.item.title }}**"
    }
  })
  op createItem(@body item: CreateItemRequest): Item;

  @route("/items/{id}")
  @patch
  @capabilities(#{
    confirmation: #{
      type: "AdaptiveCard",
      title: "Update Item",
      body: "Updating item #{{ function.parameters.id }}"
    }
  })
  op updateItem(@path id: integer, @body item: UpdateItemRequest): Item;

  @route("/items/{id}")
  @delete
  @capabilities(#{
    confirmation: #{
      type: "AdaptiveCard",
      title: "Delete Item",
      body: "⚠️ Delete item #{{ function.parameters.id }}?"
    }
  })
  op deleteItem(@path id: integer): void;
}

高度な機能

複数のクエリパラメーター
@route("/items")
@get op listItems(
  @query userId?: integer,
  @query status?: "active" | "completed" | "archived",
  @query limit?: integer,
  @query offset?: integer
): ItemList;

model ItemList {
  items: Item[];
  total: integer;
  hasMore: boolean;
}
ヘッダーパラメーター
@route("/items")
@get op listItems(
  @header("X-API-Version") apiVersion?: string,
  @query userId?: integer
): Item[];
カスタム応答モデル
@route("/items/{id}")
@delete op deleteItem(@path id: integer): DeleteResponse;

model DeleteResponse {
  success: boolean;
  message: string;
  deletedId: integer;
}
エラー応答
model ErrorResponse {
  error: {
    code: string;
    message: string;
    details?: string[];
  };
}

@route("/items/{id}")
@get op getItem(@path id: integer): Item | ErrorResponse;

プロンプトのテスト

操作を追加したら、以下のプロンプトでテストします:

GET 操作:

  • 「すべての項目を一覧表示して表で示して」
  • 「ユーザー ID 1 の項目を見せて」
  • 「項目 42 の詳細を取得して」

POST 操作:

  • 「ユーザー 1 にタイトル『My Task』の新しい項目を作成して」
  • 「項目を追加して: タイトル『New Feature』、説明『Add login』」

PATCH 操作:

  • 「項目 10 をタイトル『Updated Title』で更新して」
  • 「項目 5 のステータスを完了に変更して」

DELETE 操作:

  • 「項目 99 を削除して」
  • 「ID 15 の項目を削除して」

ベストプラクティス

パラメーターの命名
  • 説明的なパラメーター名を使用する: uid ではなく userId
  • 操作間で一貫性を保つ
  • フィルターにはオプションのパラメーター (?) を使用する
ドキュメント
  • すべての操作に JSDoc コメントを追加する
  • 各パラメーターの役割を説明する
  • 想定される応答を記述する
モデル
  • id のような読み取り専用フィールドには @visibility(Lifecycle.Read) を使用する
  • 日付フィールドには @format("date-time") を使用する
  • 列挙型にはユニオン型を使用する: "active" | "completed"
  • オプションのフィールドは ? で明示する
確認
  • 破壊的な操作 (DELETE、PATCH) には必ず確認を追加する
  • 確認本文に重要な詳細を表示する
  • 取り消せない操作には警告絵文字 (⚠️) を使用する
Adaptive Card
  • カードはシンプルかつ焦点を絞ったものにする
  • ${if(..., ..., 'N/A')} による条件付きレンダリングを使用する
  • 一般的な次のステップにはアクションボタンを含める
  • 実際の API 応答でデータバインディングをテストする
ルーティング
  • RESTful の慣例に従う:
    • GET /items - 一覧表示
    • GET /items/{id} - 1 件取得
    • POST /items - 作成
    • PATCH /items/{id} - 更新
    • DELETE /items/{id} - 削除
  • 関連する操作は同じ名前空間にグループ化する
  • 階層的なリソースにはネストされたルートを使用する

よくある問題

問題: パラメーターが Copilot に表示されない

解決策: パラメーターが @query、@path、または @body で適切にデコレートされているか確認します

問題: Adaptive Card がレンダリングされない

解決策: @card デコレーターのファイルパスを確認し、JSON 構文をチェックします

問題: 確認が表示されない

解決策: @capabilities デコレーターが confirmation オブジェクトで適切にフォーマットされているか確認します

問題: モデルのプロパティが応答に表示されない

解決策: そのプロパティに @visibility(Lifecycle.Read) が必要か確認するか、書き込み可能であるべき場合は削除します

コメント