{"id":"4547d9a1-7f46-40c5-932c-9567f4d3a7de","shortId":"dtf7aK","kind":"skill","title":"Typespec Api Operations","tagline":"Awesome Copilot skill by Github","description":"# Add TypeSpec API Operations\n\nAdd RESTful operations to an existing TypeSpec API plugin for Microsoft 365 Copilot.\n\n## Adding GET Operations\n\n### Simple GET - List All Items\n```typescript\n/**\n * List all items.\n */\n@route(\"/items\")\n@get op listItems(): Item[];\n```\n\n### GET with Query Parameter - Filter Results\n```typescript\n/**\n * List items filtered by criteria.\n * @param userId Optional user ID to filter items\n */\n@route(\"/items\")\n@get op listItems(@query userId?: integer): Item[];\n```\n\n### GET with Path Parameter - Get Single Item\n```typescript\n/**\n * Get a specific item by ID.\n * @param id The ID of the item to retrieve\n */\n@route(\"/items/{id}\")\n@get op getItem(@path id: integer): Item;\n```\n\n### GET with Adaptive Card\n```typescript\n/**\n * List items with adaptive card visualization.\n */\n@route(\"/items\")\n@card(#{\n  dataPath: \"$\",\n  title: \"$.title\",\n  file: \"item-card.json\"\n})\n@get op listItems(): Item[];\n```\n\n**Create the Adaptive Card** (`appPackage/item-card.json`):\n```json\n{\n  \"type\": \"AdaptiveCard\",\n  \"$schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\",\n  \"version\": \"1.5\",\n  \"body\": [\n    {\n      \"type\": \"Container\",\n      \"$data\": \"${$root}\",\n      \"items\": [\n        {\n          \"type\": \"TextBlock\",\n          \"text\": \"**${if(title, title, 'N/A')}**\",\n          \"wrap\": true\n        },\n        {\n          \"type\": \"TextBlock\",\n          \"text\": \"${if(description, description, 'N/A')}\",\n          \"wrap\": true\n        }\n      ]\n    }\n  ],\n  \"actions\": [\n    {\n      \"type\": \"Action.OpenUrl\",\n      \"title\": \"View Details\",\n      \"url\": \"https://example.com/items/${id}\"\n    }\n  ]\n}\n```\n\n## Adding POST Operations\n\n### Simple POST - Create Item\n```typescript\n/**\n * Create a new item.\n * @param item The item to create\n */\n@route(\"/items\")\n@post op createItem(@body item: CreateItemRequest): Item;\n\nmodel CreateItemRequest {\n  title: string;\n  description?: string;\n  userId: integer;\n}\n```\n\n### POST with Confirmation\n```typescript\n/**\n * Create a new item with confirmation.\n */\n@route(\"/items\")\n@post\n@capabilities(#{\n  confirmation: #{\n    type: \"AdaptiveCard\",\n    title: \"Create Item\",\n    body: \"\"\"\n    Are you sure you want to create this item?\n      * **Title**: {{ function.parameters.item.title }}\n      * **User ID**: {{ function.parameters.item.userId }}\n    \"\"\"\n  }\n})\nop createItem(@body item: CreateItemRequest): Item;\n```\n\n## Adding PATCH Operations\n\n### Simple PATCH - Update Item\n```typescript\n/**\n * Update an existing item.\n * @param id The ID of the item to update\n * @param item The updated item data\n */\n@route(\"/items/{id}\")\n@patch op updateItem(\n  @path id: integer,\n  @body item: UpdateItemRequest\n): Item;\n\nmodel UpdateItemRequest {\n  title?: string;\n  description?: string;\n  status?: \"active\" | \"completed\" | \"archived\";\n}\n```\n\n### PATCH with Confirmation\n```typescript\n/**\n * Update an item with confirmation.\n */\n@route(\"/items/{id}\")\n@patch\n@capabilities(#{\n  confirmation: #{\n    type: \"AdaptiveCard\",\n    title: \"Update Item\",\n    body: \"\"\"\n    Updating item #{{ function.parameters.id }}:\n      * **Title**: {{ function.parameters.item.title }}\n      * **Status**: {{ function.parameters.item.status }}\n    \"\"\"\n  }\n})\nop updateItem(\n  @path id: integer,\n  @body item: UpdateItemRequest\n): Item;\n```\n\n## Adding DELETE Operations\n\n### Simple DELETE\n```typescript\n/**\n * Delete an item.\n * @param id The ID of the item to delete\n */\n@route(\"/items/{id}\")\n@delete op deleteItem(@path id: integer): void;\n```\n\n### DELETE with Confirmation\n```typescript\n/**\n * Delete an item with confirmation.\n */\n@route(\"/items/{id}\")\n@delete\n@capabilities(#{\n  confirmation: #{\n    type: \"AdaptiveCard\",\n    title: \"Delete Item\",\n    body: \"\"\"\n    ⚠️ Are you sure you want to delete item #{{ function.parameters.id }}?\n    This action cannot be undone.\n    \"\"\"\n  }\n})\nop deleteItem(@path id: integer): void;\n```\n\n## Complete CRUD Example\n\n### Define the Service and Models\n```typescript\n@service\n@server(\"https://api.example.com\")\n@actions(#{\n  nameForHuman: \"Items API\",\n  descriptionForHuman: \"Manage items\",\n  descriptionForModel: \"Read, create, update, and delete items\"\n})\nnamespace ItemsAPI {\n  \n  // Models\n  model Item {\n    @visibility(Lifecycle.Read)\n    id: integer;\n    \n    userId: integer;\n    title: string;\n    description?: string;\n    status: \"active\" | \"completed\" | \"archived\";\n    \n    @format(\"date-time\")\n    createdAt: utcDateTime;\n    \n    @format(\"date-time\")\n    updatedAt?: utcDateTime;\n  }\n\n  model CreateItemRequest {\n    userId: integer;\n    title: string;\n    description?: string;\n  }\n\n  model UpdateItemRequest {\n    title?: string;\n    description?: string;\n    status?: \"active\" | \"completed\" | \"archived\";\n  }\n\n  // Operations\n  @route(\"/items\")\n  @card(#{ dataPath: \"$\", title: \"$.title\", file: \"item-card.json\" })\n  @get op listItems(@query userId?: integer): Item[];\n\n  @route(\"/items/{id}\")\n  @card(#{ dataPath: \"$\", title: \"$.title\", file: \"item-card.json\" })\n  @get op getItem(@path id: integer): Item;\n\n  @route(\"/items\")\n  @post\n  @capabilities(#{\n    confirmation: #{\n      type: \"AdaptiveCard\",\n      title: \"Create Item\",\n      body: \"Creating: **{{ function.parameters.item.title }}**\"\n    }\n  })\n  op createItem(@body item: CreateItemRequest): Item;\n\n  @route(\"/items/{id}\")\n  @patch\n  @capabilities(#{\n    confirmation: #{\n      type: \"AdaptiveCard\",\n      title: \"Update Item\",\n      body: \"Updating item #{{ function.parameters.id }}\"\n    }\n  })\n  op updateItem(@path id: integer, @body item: UpdateItemRequest): Item;\n\n  @route(\"/items/{id}\")\n  @delete\n  @capabilities(#{\n    confirmation: #{\n      type: \"AdaptiveCard\",\n      title: \"Delete Item\",\n      body: \"⚠️ Delete item #{{ function.parameters.id }}?\"\n    }\n  })\n  op deleteItem(@path id: integer): void;\n}\n```\n\n## Advanced Features\n\n### Multiple Query Parameters\n```typescript\n@route(\"/items\")\n@get op listItems(\n  @query userId?: integer,\n  @query status?: \"active\" | \"completed\" | \"archived\",\n  @query limit?: integer,\n  @query offset?: integer\n): ItemList;\n\nmodel ItemList {\n  items: Item[];\n  total: integer;\n  hasMore: boolean;\n}\n```\n\n### Header Parameters\n```typescript\n@route(\"/items\")\n@get op listItems(\n  @header(\"X-API-Version\") apiVersion?: string,\n  @query userId?: integer\n): Item[];\n```\n\n### Custom Response Models\n```typescript\n@route(\"/items/{id}\")\n@delete op deleteItem(@path id: integer): DeleteResponse;\n\nmodel DeleteResponse {\n  success: boolean;\n  message: string;\n  deletedId: integer;\n}\n```\n\n### Error Responses\n```typescript\nmodel ErrorResponse {\n  error: {\n    code: string;\n    message: string;\n    details?: string[];\n  };\n}\n\n@route(\"/items/{id}\")\n@get op getItem(@path id: integer): Item | ErrorResponse;\n```\n\n## Testing Prompts\n\nAfter adding operations, test with these prompts:\n\n**GET Operations:**\n- \"List all items and show them in a table\"\n- \"Show me items for user ID 1\"\n- \"Get the details of item 42\"\n\n**POST Operations:**\n- \"Create a new item with title 'My Task' for user 1\"\n- \"Add an item: title 'New Feature', description 'Add login'\"\n\n**PATCH Operations:**\n- \"Update item 10 with title 'Updated Title'\"\n- \"Change the status of item 5 to completed\"\n\n**DELETE Operations:**\n- \"Delete item 99\"\n- \"Remove the item with ID 15\"\n\n## Best Practices\n\n### Parameter Naming\n- Use descriptive parameter names: `userId` not `uid`\n- Be consistent across operations\n- Use optional parameters (`?`) for filters\n\n### Documentation\n- Add JSDoc comments to all operations\n- Describe what each parameter does\n- Document expected responses\n\n### Models\n- Use `@visibility(Lifecycle.Read)` for read-only fields like `id`\n- Use `@format(\"date-time\")` for date fields\n- Use union types for enums: `\"active\" | \"completed\"`\n- Make optional fields explicit with `?`\n\n### Confirmations\n- Always add confirmations to destructive operations (DELETE, PATCH)\n- Show key details in confirmation body\n- Use warning emoji (⚠️) for irreversible actions\n\n### Adaptive Cards\n- Keep cards simple and focused\n- Use conditional rendering with `${if(..., ..., 'N/A')}`\n- Include action buttons for common next steps\n- Test data binding with actual API responses\n\n### Routing\n- Use RESTful conventions:\n  - `GET /items` - List\n  - `GET /items/{id}` - Get one\n  - `POST /items` - Create\n  - `PATCH /items/{id}` - Update\n  - `DELETE /items/{id}` - Delete\n- Group related operations in the same namespace\n- Use nested routes for hierarchical resources\n\n## Common Issues\n\n### Issue: Parameter not showing in Copilot\n**Solution**: Check parameter is properly decorated with `@query`, `@path`, or `@body`\n\n### Issue: Adaptive card not rendering\n**Solution**: Verify file path in `@card` decorator and check JSON syntax\n\n### Issue: Confirmation not appearing\n**Solution**: Ensure `@capabilities` decorator is properly formatted with confirmation object\n\n### Issue: Model property not appearing in response\n**Solution**: Check if property needs `@visibility(Lifecycle.Read)` or remove it if it should be writable","tags":["typespec","api","operations","awesome","copilot","github"],"capabilities":["skill","source-github","category-awesome-copilot"],"categories":["awesome-copilot"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/github/awesome-copilot/typespec-api-operations","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"install_from":"skills.sh"}},"qualityScore":"0.300","qualityRationale":"deterministic score 0.30 from registry signals: · indexed on skills.sh · published under github/awesome-copilot","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T09:40:13.850Z","embedding":null,"createdAt":"2026-04-18T20:26:09.593Z","updatedAt":"2026-04-22T09:40:13.850Z","lastSeenAt":"2026-04-22T09:40:13.850Z","tsv":"'/items':39,65,97,118,197,224,282,314,360,379,487,502,518,537,561,588,619,639,669,881,884,889,892,896 '/items/$':176 '/schemas/adaptive-card.json':140 '1':705,724 '1.5':142 '10':738 '15':761 '365':24 '42':711 '5':748 '99':755 'across':775 'action':167,400,422,848,863 'action.openurl':169 'activ':301,452,482,597,821 'actual':873 'ad':26,178,254,341,682 'adapt':108,114,131,849,932 'adaptivecard':136,229,320,385,523,543,567 'adaptivecards.io':139 'adaptivecards.io/schemas/adaptive-card.json':138 'add':9,13,725,732,783,830 'advanc':581 'alway':829 'api':2,11,20,425,626,874 'api.example.com':421 'apivers':628 'appear':950,965 'apppackage/item-card.json':133 'archiv':303,454,484,599 'awesom':4 'best':762 'bind':871 'bodi':143,201,233,250,290,324,337,389,527,532,547,556,571,842,930 'boolean':614,651 'button':864 'cannot':401 'capabl':226,317,382,520,540,564,953 'card':109,115,119,132,488,504,850,852,933,941 'category-awesome-copilot' 'chang':743 'check':921,944,969 'code':662 'comment':785 'common':866,912 'complet':302,410,453,483,598,750,822 'condit':857 'confirm':215,222,227,306,312,318,371,377,383,521,541,565,828,831,841,948,959 'consist':774 'contain':145 'convent':879 'copilot':5,25,919 'creat':129,183,186,195,217,231,240,431,525,528,714,890 'createdat':459 'createitem':200,249,531 'createitemrequest':203,206,252,468,534 'criteria':55 'crud':411 'custom':634 'data':146,280,870 'datapath':120,489,505 'date':457,463,811,814 'date-tim':456,462,810 'decor':925,942,954 'defin':413 'delet':342,345,347,358,362,369,373,381,387,396,434,563,569,572,641,751,753,835,895,898 'deletedid':654 'deleteitem':364,405,576,643 'deleterespons':647,649 'describ':789 'descript':162,163,209,298,449,473,479,731,767 'descriptionforhuman':426 'descriptionformodel':429 'destruct':833 'detail':172,666,708,839 'document':782,794 'emoji':845 'ensur':952 'enum':820 'error':656,661 'errorrespons':660,678 'exampl':412 'example.com':175 'example.com/items/$':174 'exist':18,264 'expect':795 'explicit':826 'featur':582,730 'field':805,815,825 'file':123,492,508,938 'filter':48,53,62,781 'focus':855 'format':455,461,809,957 'function.parameters.id':327,398,550,574 'function.parameters.item.status':331 'function.parameters.item.title':244,329,529 'function.parameters.item.userid':247 'get':27,30,40,44,66,73,77,81,99,106,125,494,510,589,620,671,688,706,880,883,886 'getitem':101,512,673 'github':8 'group':899 'hasmor':613 'header':615,623 'hierarch':910 'id':60,86,88,90,98,103,177,246,267,269,283,288,315,335,351,353,361,366,380,407,443,503,514,538,554,562,578,640,645,670,675,704,760,807,885,893,897 'includ':862 'integ':71,104,212,289,336,367,408,444,446,470,499,515,555,579,594,602,605,612,632,646,655,676 'irrevers':847 'issu':913,914,931,947,961 'item':33,37,43,52,63,72,79,84,93,105,112,128,148,184,189,191,193,202,204,220,232,242,251,253,260,265,272,276,279,291,293,310,323,326,338,340,349,356,375,388,397,424,428,435,440,500,516,526,533,535,546,549,557,559,570,573,609,610,633,677,692,701,710,717,727,737,747,754,758 'item-card.json':124,493,509 'itemlist':606,608 'itemsapi':437 'jsdoc':784 'json':134,945 'keep':851 'key':838 'lifecycle.read':442,800,974 'like':806 'limit':601 'list':31,35,51,111,690,882 'listitem':42,68,127,496,591,622 'login':733 'make':823 'manag':427 'messag':652,664 'microsoft':23 'model':205,294,417,438,439,467,475,607,636,648,659,797,962 'multipl':583 'n/a':155,164,861 'name':765,769 'nameforhuman':423 'namespac':436,905 'need':972 'nest':907 'new':188,219,716,729 'next':867 'object':960 'offset':604 'one':887 'op':41,67,100,126,199,248,285,332,363,404,495,511,530,551,575,590,621,642,672 'oper':3,12,15,28,180,256,343,485,683,689,713,735,752,776,788,834,901 'option':58,778,824 'param':56,87,190,266,275,350 'paramet':47,76,585,616,764,768,779,792,915,922 'patch':255,258,284,304,316,539,734,836,891 'path':75,102,287,334,365,406,513,553,577,644,674,928,939 'plugin':21 'post':179,182,198,213,225,519,712,888 'practic':763 'prompt':680,687 'proper':924,956 'properti':963,971 'queri':46,69,497,584,592,595,600,603,630,927 'read':430,803 'read-on':802 'relat':900 'remov':756,976 'render':858,935 'resourc':911 'respons':635,657,796,875,967 'rest':14,878 'result':49 'retriev':95 'root':147 'rout':38,64,96,117,196,223,281,313,359,378,486,501,517,536,560,587,618,638,668,876,908 'schema':137 'server':420 'servic':415,419 'show':694,699,837,917 'simpl':29,181,257,344,853 'singl':78 'skill':6 'solut':920,936,951,968 'source-github' 'specif':83 'status':300,330,451,481,596,745 'step':868 'string':208,210,297,299,448,450,472,474,478,480,629,653,663,665,667 'success':650 'sure':236,392 'syntax':946 'tabl':698 'task':721 'test':679,684,869 'text':151,160 'textblock':150,159 'time':458,464,812 'titl':121,122,153,154,170,207,230,243,296,321,328,386,447,471,477,490,491,506,507,524,544,568,719,728,740,742 'total':611 'true':157,166 'type':135,144,149,158,168,228,319,384,522,542,566,818 'typescript':34,50,80,110,185,216,261,307,346,372,418,586,617,637,658 'typespec':1,10,19 'uid':772 'undon':403 'union':817 'updat':259,262,274,278,308,322,325,432,545,548,736,741,894 'updatedat':465 'updateitem':286,333,552 'updateitemrequest':292,295,339,476,558 'url':173 'use':766,777,798,808,816,843,856,877,906 'user':59,245,703,723 'userid':57,70,211,445,469,498,593,631,770 'utcdatetim':460,466 'verifi':937 'version':141,627 'view':171 'visibl':441,799,973 'visual':116 'void':368,409,580 'want':238,394 'warn':844 'wrap':156,165 'writabl':982 'x':625 'x-api-vers':624","prices":[{"id":"0bce8f09-7585-4528-954b-15cce048f6b2","listingId":"4547d9a1-7f46-40c5-932c-9567f4d3a7de","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"github","category":"awesome-copilot","install_from":"skills.sh"},"createdAt":"2026-04-18T20:26:09.593Z"}],"sources":[{"listingId":"4547d9a1-7f46-40c5-932c-9567f4d3a7de","source":"github","sourceId":"github/awesome-copilot/typespec-api-operations","sourceUrl":"https://github.com/github/awesome-copilot/tree/main/skills/typespec-api-operations","isPrimary":false,"firstSeenAt":"2026-04-18T21:51:29.643Z","lastSeenAt":"2026-04-22T06:52:33.106Z"},{"listingId":"4547d9a1-7f46-40c5-932c-9567f4d3a7de","source":"skills_sh","sourceId":"github/awesome-copilot/typespec-api-operations","sourceUrl":"https://skills.sh/github/awesome-copilot/typespec-api-operations","isPrimary":true,"firstSeenAt":"2026-04-18T20:26:09.593Z","lastSeenAt":"2026-04-22T09:40:13.850Z"}],"details":{"listingId":"4547d9a1-7f46-40c5-932c-9567f4d3a7de","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"github","slug":"typespec-api-operations","source":"skills_sh","category":"awesome-copilot","skills_sh_url":"https://skills.sh/github/awesome-copilot/typespec-api-operations"},"updatedAt":"2026-04-22T09:40:13.850Z"}}