Created
February 6, 2026 08:02
-
-
Save daneuchar/6f53dc31eefdde3a8bc82c87b4da4cfa to your computer and use it in GitHub Desktop.
openapi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Document Azure Function API Endpoints as Versioned OpenAPI Specs | |
| ## Purpose | |
| Scan the entire TypeScript Azure Functions codebase, discover all HTTP-triggered | |
| functions, extract their API metadata (route, method, request/response schemas, | |
| auth level, parameters), group them by API version, and generate one OpenAPI 3.0 | |
| YAML file per version. | |
| ## Output Convention | |
| | Version discovered | Output file | | |
| | ------------------ | ------------------------- | | |
| | `v1` | `docs/api/{module}-v1.yml` | | |
| | `v2` | `docs/api/{module}-v2.yml` | | |
| | `v3` | `docs/api/{module}-v3.yml` | | |
| | *(no version)* | `docs/api/{module}-unversioned.yml` | | |
| `{module}` is derived from the folder name, function app name, or logical | |
| grouping found in the codebase. If the project is a single module, use the | |
| project/package name. | |
| --- | |
| ## Step-by-Step Instructions | |
| ### 1. Discover All HTTP Trigger Functions | |
| Scan every TypeScript file (`*.ts`) in the project for Azure Function HTTP | |
| triggers. Look for **all** of the following patterns: | |
| #### Programming Model v4 (Node.js v4) | |
| ```typescript | |
| // Pattern A – app.http / app.get / app.post / app.put / app.patch / app.delete | |
| import { app } from "@azure/functions"; | |
| app.http("functionName", { | |
| methods: ["GET", "POST"], | |
| authLevel: "anonymous", | |
| route: "v1/users/{id}", | |
| handler: handlerFn, | |
| }); | |
| // Pattern B – app.route grouped | |
| app.http("createUser", { methods: ["POST"], route: "v2/users", handler: ... }); | |
| app.http("getUser", { methods: ["GET"], route: "v2/users/{id}", handler: ... }); | |
| ``` | |
| #### Programming Model v3 (function.json based) | |
| ```jsonc | |
| // function.json | |
| { | |
| "bindings": [ | |
| { | |
| "type": "httpTrigger", | |
| "direction": "in", | |
| "methods": ["get"], | |
| "route": "v1/products/{productId}", | |
| "authLevel": "function" | |
| }, | |
| { "type": "http", "direction": "out" } | |
| ] | |
| } | |
| ``` | |
| Also check `host.json` for a global `routePrefix` (commonly `"api"`). | |
| ### 2. Extract Metadata for Each Endpoint | |
| For every discovered HTTP trigger, collect: | |
| | Field | Source | | |
| | ------------------ | --------------------------------------------------------------------------------------------- | | |
| | **Route** | `route` property (combine with `routePrefix` from `host.json`) | | |
| | **HTTP Methods** | `methods` array (default to all methods if omitted) | | |
| | **Auth Level** | `authLevel` (`anonymous`, `function`, `admin`) | | |
| | **Path Parameters**| Segments like `{id}`, `{productId}` in the route string | | |
| | **Query Params** | Parsed from `request.query` / `req.query` usage in the handler | | |
| | **Request Body** | TypeScript interfaces/types used for `await request.json()` or `req.body` | | |
| | **Response Body** | Return type or `response.json(...)` calls — infer schema from TS types | | |
| | **Status Codes** | Any explicit `status: 200`, `status: 404`, `new HttpResponse({ status: ... })` in the handler | | |
| | **Description** | JSDoc `@description` / `@summary` on the handler, or inline comments | | |
| | **Tags** | Derive from folder name, route prefix, or JSDoc `@tag` | | |
| ### 3. Determine API Version | |
| Extract the version from the **route** string using these rules (in priority order): | |
| 1. **Explicit path segment**: `/v1/...`, `/v2/...`, `/v3/...` → version is `v1`, `v2`, `v3` | |
| 2. **Query parameter convention**: if handlers read `req.query.get("api-version")` → note each value | |
| 3. **Header convention**: if handlers read `x-api-version` header → note each value | |
| 4. **Folder structure**: `src/functions/v1/...`, `src/functions/v2/...` | |
| 5. **No version found**: classify as `unversioned` | |
| ### 4. Resolve TypeScript Types into JSON Schema | |
| For every request/response type referenced by handlers: | |
| - Follow `import` chains to find the interface or type alias definition. | |
| - Convert TypeScript types to JSON Schema / OpenAPI `schema` objects: | |
| | TypeScript | OpenAPI Schema | | |
| | ----------------------- | ----------------------------------------------- | | |
| | `string` | `{ type: "string" }` | | |
| | `number` | `{ type: "number" }` | | |
| | `boolean` | `{ type: "boolean" }` | | |
| | `Date` | `{ type: "string", format: "date-time" }` | | |
| | `string[]` | `{ type: "array", items: { type: "string" } }` | | |
| | `Record<string, T>` | `{ type: "object", additionalProperties: <T> }` | | |
| | `T \| null` | `{ oneOf: [<T>, { type: "null" }] }` | | |
| | `T \| undefined` | mark property as **not required** | | |
| | Enum | `{ type: "string", enum: [...] }` | | |
| | Interface / Type alias | `$ref: "#/components/schemas/TypeName"` | | |
| Place all shared schemas under `components.schemas` in the output YAML. | |
| ### 5. Generate the OpenAPI YAML Files | |
| For each API version, produce a well-formed **OpenAPI 3.0.3** YAML document. | |
| Use this skeleton: | |
| ```yaml | |
| openapi: "3.0.3" | |
| info: | |
| title: "{Module Name} API – {Version}" | |
| description: > | |
| Auto-generated OpenAPI specification for the {module} Azure Functions | |
| module, API version {version}. | |
| version: "{version}" | |
| contact: | |
| name: "API Team" | |
| servers: | |
| - url: "https://{functionAppName}.azurewebsites.net/api" | |
| description: "Azure Functions Host" | |
| paths: | |
| /{route}: | |
| {method}: | |
| operationId: "{functionName}" | |
| summary: "{summary from JSDoc or inferred}" | |
| description: "{description from JSDoc or inferred}" | |
| tags: | |
| - "{tag}" | |
| security: | |
| - functionKey: [] # if authLevel is "function" | |
| - {} # if authLevel is "anonymous" | |
| parameters: | |
| - name: "{paramName}" | |
| in: "path" # or "query" | |
| required: true # path params are always required | |
| schema: | |
| type: "string" | |
| requestBody: # only for POST/PUT/PATCH | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/{RequestType}" | |
| responses: | |
| "200": | |
| description: "Successful response" | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/{ResponseType}" | |
| "400": | |
| description: "Bad request" | |
| "404": | |
| description: "Not found" | |
| "500": | |
| description: "Internal server error" | |
| components: | |
| schemas: | |
| {TypeName}: | |
| type: "object" | |
| required: | |
| - "field1" | |
| properties: | |
| field1: | |
| type: "string" | |
| description: "{from JSDoc @property or inline comment}" | |
| securitySchemes: | |
| functionKey: | |
| type: "apiKey" | |
| in: "header" | |
| name: "x-functions-key" | |
| adminKey: | |
| type: "apiKey" | |
| in: "header" | |
| name: "x-functions-key" | |
| ``` | |
| ### 6. Quality Checks | |
| Before writing each file, verify: | |
| - [ ] Every `$ref` target exists in `components.schemas`. | |
| - [ ] Path parameters in the route have matching `parameters` entries. | |
| - [ ] `operationId` values are unique across the entire file. | |
| - [ ] HTTP methods are lowercase (`get`, `post`, `put`, `delete`, `patch`). | |
| - [ ] Required fields are listed for every object schema. | |
| - [ ] No empty `paths` — if a version has no endpoints, skip the file. | |
| - [ ] YAML is valid and parseable. | |
| ### 7. Generate a Summary Index | |
| After all versioned files are created, produce a `docs/api/README.md` with: | |
| ```markdown | |
| # API Documentation Index | |
| > Auto-generated by Copilot from the Azure Functions TypeScript codebase. | |
| ## Modules & Versions | |
| | Module | Version | File | Endpoints | | |
| | ------------ | ------- | ----------------------------- | --------- | | |
| | {module} | v1 | [{module}-v1.yml](./{module}-v1.yml) | 12 | | |
| | {module} | v2 | [{module}-v2.yml](./{module}-v2.yml) | 8 | | |
| ## Quick Stats | |
| - **Total endpoints**: {N} | |
| - **Versions**: v1, v2 | |
| - **Auth levels used**: anonymous, function | |
| ## Changelog Hints | |
| List any endpoints that exist in v1 but are missing in v2 (deprecated), | |
| and any endpoints added in v2 that don't exist in v1 (new). | |
| ``` | |
| --- | |
| ## Important Rules | |
| 1. **Do NOT hallucinate endpoints.** Only document functions you can find in the | |
| source code with actual HTTP trigger bindings. | |
| 2. **Preserve the developer's naming.** Use the exact route strings, function | |
| names, and type names from the code — do not rename them. | |
| 3. **Be thorough.** Walk every `src/` directory, every `functions/` folder, and | |
| every `function.json`. Do not stop at the first file. | |
| 4. **Handle monorepos.** If the repo has multiple function apps (e.g., | |
| `apps/api-users`, `apps/api-orders`), treat each as a separate module. | |
| 5. **Idempotent.** Running this prompt again should produce the same output if | |
| the source hasn't changed. | |
| 6. **Create the output directory** `docs/api/` if it doesn't exist. | |
| 7. **UTF-8 YAML** with `.yml` extension, 2-space indentation, no tabs. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment