{"id":"4547d9a1-7f46-40c5-932c-9567f4d3a7de","shortId":"dtf7aK","kind":"skill","title":"typespec-api-operations","tagline":"Add GET, POST, PATCH, and DELETE operations to a TypeSpec API plugin with proper routing, parameters, and adaptive cards","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","agent-skills","agents","custom-agents","github-copilot","hacktoberfest","prompt-engineering"],"capabilities":["skill","source-github","skill-typespec-api-operations","topic-agent-skills","topic-agents","topic-awesome","topic-custom-agents","topic-github-copilot","topic-hacktoberfest","topic-prompt-engineering"],"categories":["awesome-copilot"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/github/awesome-copilot/typespec-api-operations","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add github/awesome-copilot","source_repo":"https://github.com/github/awesome-copilot","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 33270 github stars · SKILL.md body (8,969 chars)","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-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:52:26.989Z","embedding":null,"createdAt":"2026-04-18T20:26:09.593Z","updatedAt":"2026-05-18T18:52:26.989Z","lastSeenAt":"2026-05-18T18:52:26.989Z","tsv":"'/items':54,80,112,133,212,239,297,329,375,394,502,517,533,552,576,603,634,654,684,896,899,904,907,911 '/items/$':191 '/schemas/adaptive-card.json':155 '1':720,739 '1.5':157 '10':753 '15':776 '365':39 '42':726 '5':763 '99':770 'across':790 'action':182,415,437,863,878 'action.openurl':184 'activ':316,467,497,612,836 'actual':888 'ad':41,193,269,356,697 'adapt':22,123,129,146,864,947 'adaptivecard':151,244,335,400,538,558,582 'adaptivecards.io':154 'adaptivecards.io/schemas/adaptive-card.json':153 'add':5,24,28,740,747,798,845 'advanc':596 'alway':844 'api':3,15,26,35,440,641,889 'api.example.com':436 'apivers':643 'appear':965,980 'apppackage/item-card.json':148 'archiv':318,469,499,614 'best':777 'bind':886 'bodi':158,216,248,265,305,339,352,404,542,547,562,571,586,857,945 'boolean':629,666 'button':879 'cannot':416 'capabl':241,332,397,535,555,579,968 'card':23,124,130,134,147,503,519,865,867,948,956 'chang':758 'check':936,959,984 'code':677 'comment':800 'common':881,927 'complet':317,425,468,498,613,765,837 'condit':872 'confirm':230,237,242,321,327,333,386,392,398,536,556,580,843,846,856,963,974 'consist':789 'contain':160 'convent':894 'copilot':40,934 'creat':144,198,201,210,232,246,255,446,540,543,729,905 'createdat':474 'createitem':215,264,546 'createitemrequest':218,221,267,483,549 'criteria':70 'crud':426 'custom':649 'data':161,295,885 'datapath':135,504,520 'date':472,478,826,829 'date-tim':471,477,825 'decor':940,957,969 'defin':428 'delet':10,357,360,362,373,377,384,388,396,402,411,449,578,584,587,656,766,768,850,910,913 'deletedid':669 'deleteitem':379,420,591,658 'deleterespons':662,664 'describ':804 'descript':177,178,224,313,464,488,494,746,782 'descriptionforhuman':441 'descriptionformodel':444 'destruct':848 'detail':187,681,723,854 'document':797,809 'emoji':860 'ensur':967 'enum':835 'error':671,676 'errorrespons':675,693 'exampl':427 'example.com':190 'example.com/items/$':189 'exist':33,279 'expect':810 'explicit':841 'featur':597,745 'field':820,830,840 'file':138,507,523,953 'filter':63,68,77,796 'focus':870 'format':470,476,824,972 'function.parameters.id':342,413,565,589 'function.parameters.item.status':346 'function.parameters.item.title':259,344,544 'function.parameters.item.userid':262 'get':6,42,45,55,59,81,88,92,96,114,121,140,509,525,604,635,686,703,721,895,898,901 'getitem':116,527,688 'group':914 'hasmor':628 'header':630,638 'hierarch':925 'id':75,101,103,105,113,118,192,261,282,284,298,303,330,350,366,368,376,381,395,422,458,518,529,553,569,577,593,655,660,685,690,719,775,822,900,908,912 'includ':877 'integ':86,119,227,304,351,382,423,459,461,485,514,530,570,594,609,617,620,627,647,661,670,691 'irrevers':862 'issu':928,929,946,962,976 'item':48,52,58,67,78,87,94,99,108,120,127,143,163,199,204,206,208,217,219,235,247,257,266,268,275,280,287,291,294,306,308,325,338,341,353,355,364,371,390,403,412,439,443,450,455,515,531,541,548,550,561,564,572,574,585,588,624,625,648,692,707,716,725,732,742,752,762,769,773 'item-card.json':139,508,524 'itemlist':621,623 'itemsapi':452 'jsdoc':799 'json':149,960 'keep':866 'key':853 'lifecycle.read':457,815,989 'like':821 'limit':616 'list':46,50,66,126,705,897 'listitem':57,83,142,511,606,637 'login':748 'make':838 'manag':442 'messag':667,679 'microsoft':38 'model':220,309,432,453,454,482,490,622,651,663,674,812,977 'multipl':598 'n/a':170,179,876 'name':780,784 'nameforhuman':438 'namespac':451,920 'need':987 'nest':922 'new':203,234,731,744 'next':882 'object':975 'offset':619 'one':902 'op':56,82,115,141,214,263,300,347,378,419,510,526,545,566,590,605,636,657,687 'oper':4,11,27,30,43,195,271,358,500,698,704,728,750,767,791,803,849,916 'option':73,793,839 'param':71,102,205,281,290,365 'paramet':20,62,91,600,631,779,783,794,807,930,937 'patch':8,270,273,299,319,331,554,749,851,906 'path':90,117,302,349,380,421,528,568,592,659,689,943,954 'plugin':16,36 'post':7,194,197,213,228,240,534,727,903 'practic':778 'prompt':695,702 'proper':18,939,971 'properti':978,986 'queri':61,84,512,599,607,610,615,618,645,942 'read':445,818 'read-on':817 'relat':915 'remov':771,991 'render':873,950 'resourc':926 'respons':650,672,811,890,982 'rest':29,893 'result':64 'retriev':110 'root':162 'rout':19,53,79,111,132,211,238,296,328,374,393,501,516,532,551,575,602,633,653,683,891,923 'schema':152 'server':435 'servic':430,434 'show':709,714,852,932 'simpl':44,196,272,359,868 'singl':93 'skill' 'skill-typespec-api-operations' 'solut':935,951,966,983 'source-github' 'specif':98 'status':315,345,466,496,611,760 'step':883 'string':223,225,312,314,463,465,487,489,493,495,644,668,678,680,682 'success':665 'sure':251,407 'syntax':961 'tabl':713 'task':736 'test':694,699,884 'text':166,175 'textblock':165,174 'time':473,479,827 'titl':136,137,168,169,185,222,245,258,311,336,343,401,462,486,492,505,506,521,522,539,559,583,734,743,755,757 'topic-agent-skills' 'topic-agents' 'topic-awesome' 'topic-custom-agents' 'topic-github-copilot' 'topic-hacktoberfest' 'topic-prompt-engineering' 'total':626 'true':172,181 'type':150,159,164,173,183,243,334,399,537,557,581,833 'typescript':49,65,95,125,200,231,276,322,361,387,433,601,632,652,673 'typespec':2,14,25,34 'typespec-api-oper':1 'uid':787 'undon':418 'union':832 'updat':274,277,289,293,323,337,340,447,560,563,751,756,909 'updatedat':480 'updateitem':301,348,567 'updateitemrequest':307,310,354,491,573 'url':188 'use':781,792,813,823,831,858,871,892,921 'user':74,260,718,738 'userid':72,85,226,460,484,513,608,646,785 'utcdatetim':475,481 'verifi':952 'version':156,642 'view':186 'visibl':456,814,988 'visual':131 'void':383,424,595 'want':253,409 'warn':859 'wrap':171,180 'writabl':997 'x':640 'x-api-vers':639","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-05-18T18:52:26.989Z"},{"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-05-07T22:40:18.841Z"}],"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","github":{"repo":"github/awesome-copilot","stars":33270,"topics":["agent-skills","agents","ai","awesome","custom-agents","github-copilot","hacktoberfest","prompt-engineering"],"license":"mit","html_url":"https://github.com/github/awesome-copilot","pushed_at":"2026-05-18T01:26:59Z","description":"Community-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.","skill_md_sha":"0c9c31734f64c3c231ad97772de95d4ab9431ddd","skill_md_path":"skills/typespec-api-operations/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/github/awesome-copilot/tree/main/skills/typespec-api-operations"},"layout":"multi","source":"github","category":"awesome-copilot","frontmatter":{"name":"typespec-api-operations","description":"Add GET, POST, PATCH, and DELETE operations to a TypeSpec API plugin with proper routing, parameters, and adaptive cards"},"skills_sh_url":"https://skills.sh/github/awesome-copilot/typespec-api-operations"},"updatedAt":"2026-05-18T18:52:26.989Z"}}