From 72803583e6f3d079197a9e80250fe2d08c5506f2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 21 Sep 2026 09:30:51 +0000 Subject: [PATCH] docs(arm): update guidance for new validation rules Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../knowledge/azure-resource-manager.md | 21 +++++++++++++++++++ .../azure-resource-manager.meta.json | 4 ++-- .../azure-resource-manager/step04.md | 9 +++++++- .../content/docs/docs/howtos/ARM/arm-rules.md | 8 +++++++ .../docs/howtos/ARM/resource-operations.md | 13 +++++------- .../docs/docs/howtos/ARM/versioning.md | 9 ++++---- 6 files changed, 49 insertions(+), 15 deletions(-) diff --git a/eng/scripts/doc-updater/knowledge/azure-resource-manager.md b/eng/scripts/doc-updater/knowledge/azure-resource-manager.md index 601aef43d4..eb039986f6 100644 --- a/eng/scripts/doc-updater/knowledge/azure-resource-manager.md +++ b/eng/scripts/doc-updater/knowledge/azure-resource-manager.md @@ -155,3 +155,24 @@ The former multi-purpose `arm-resource-operation` checks are represented by thre ## Resource Identity Resolution Concrete ARM resource identities are seeded only by registered read or createOrUpdate operations with valid ARM resource instance paths. List, action, update, delete, and check-existence operations can attach to an existing resolved resource but do not create resource identities by themselves. + +## ARM Operation Query and Payload Rules + +- Collection GET operations may use only `api-version` and case-sensitive `$filter` query parameters. Do not recommend `ArmTopParameter`, `ArmSkipParameter`, `order-by`, continuation tokens, or other custom query parameters for collection GET examples. +- Point GET, PUT, PATCH, and DELETE operations may use only `api-version`. +- POST operations may use only `api-version`; put request-specific input in a plain request-body model. +- ARM request bodies must be plain models without indexers. Primitive, union, array, and record request bodies are rejected; bodyless and multipart operations are allowed. +- ARM request and response bodies must resolve to `application/json`. In particular, `ArmResponse` resolves to a non-JSON scalar response; wrap scalar values in a response model. +- Collection GET responses should use standard ARM list templates. Custom list operations need `@list`, `@pageItems`, `@nextLink`, and an envelope containing only `value` and `nextLink`. + +## Long-Running Operation Results + +LRO final-result metadata must match operation semantics: PUT and PATCH return the resource, DELETE returns `void`, and POST actions use their response type (or `void` for no-content actions). Standard async templates configure these defaults. When overriding `LroHeaders`, preserve the matching `FinalResult`. + +## Feature File Versions + +`ArmFeatureFileOptions.version` optionally selects the API version used for clients generated from that feature file. Empty or whitespace-only values are invalid. This property exists only on the current `Azure.ResourceManager.featureFileOptions`; do not document it on deprecated `Legacy.featureOptions`. Feature files remain restricted to approved brownfield migrations. + +## Documentation Sample Links + +When linking to a canonical sample from an ARM guide, prefer its published documentation URL under `https://azure.github.io/typespec-azure/docs/samples/resource-manager/` instead of the GitHub source-tree URL. diff --git a/eng/scripts/doc-updater/knowledge/azure-resource-manager.meta.json b/eng/scripts/doc-updater/knowledge/azure-resource-manager.meta.json index 03b0f5afe1..471fb8fb9c 100644 --- a/eng/scripts/doc-updater/knowledge/azure-resource-manager.meta.json +++ b/eng/scripts/doc-updater/knowledge/azure-resource-manager.meta.json @@ -1,6 +1,6 @@ { - "lastCommit": "ec0efa31cccaadaf340043532eeaa62590ec9272", - "lastUpdated": "2026-08-31T09:31:31.540Z", + "lastCommit": "b85682f40152971d00d8bdcb4f6204d9c794bf3b", + "lastUpdated": "2026-09-21T09:25:43.311Z", "analyzedPaths": [ "packages/typespec-azure-resource-manager/src", "packages/typespec-azure-resource-manager/lib", diff --git a/website/src/content/docs/docs/getstarted/azure-resource-manager/step04.md b/website/src/content/docs/docs/getstarted/azure-resource-manager/step04.md index aa670d0c94..a93cf20690 100644 --- a/website/src/content/docs/docs/getstarted/azure-resource-manager/step04.md +++ b/website/src/content/docs/docs/getstarted/azure-resource-manager/step04.md @@ -18,6 +18,12 @@ model NotificationDetails { urgent: boolean; } +/** The result of sending a notification */ +model NotificationResult { + /** The identifier for the sent notification */ + notificationId: string; +} + @armResourceOperations interface Users { get is ArmResourceRead; @@ -53,10 +59,11 @@ In a custom operation, you define the operation parameters, responses, http verb ```typespec /** Send a notification to the user */ +@armResourceAction(User) @post @segment("notify") op NotifyUser(...ResourceInstanceParameters, @body notification: NotificationDetails): - | ArmResponse + | ArmResponse | ErrorResponse; ``` diff --git a/website/src/content/docs/docs/howtos/ARM/arm-rules.md b/website/src/content/docs/docs/howtos/ARM/arm-rules.md index 8548b95118..9128e63b29 100644 --- a/website/src/content/docs/docs/howtos/ARM/arm-rules.md +++ b/website/src/content/docs/docs/howtos/ARM/arm-rules.md @@ -121,18 +121,26 @@ The tables below provide guidance to rule authors and ARM reviewers on how to ev | [`beyond-nesting-levels`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/beyond-nesting-levels/) | [`TrackedResourceBeyondsThirdLevel`](https://github.com/Azure/azure-openapi-validator/blob/main/docs/tracked-resource-beyond-thrid-level.md) | **API.** RPC violation. | | [`empty-updateable-properties`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/empty-updateable-properties/) | — | **API.** Covered by patch-specific rules. | | [`improper-subscription-list-operation`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/improper-subscription-list-operation/) | — | **API.** Likely a modeling error; only subscription-based resources should have list operations. | +| [`list-operation-missing-pageable`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/list-operation-missing-pageable/) | [`XmsPageableForListCalls`](https://github.com/Azure/azure-openapi-validator/blob/main/docs/xms-pageable-for-list-calls.md) | **API, SDK.** Missing pagination metadata makes list operations inconsistent and adding continuation links later can be a breaking change. | +| [`list-response-envelope`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/list-response-envelope/) | [`GetCollectionOnlyHasValueAndNextLink`](https://github.com/Azure/azure-openapi-validator/blob/main/packages/rulesets/src/spectral/functions/get-collection-only-has-value-and-next-link.ts) | **API, SDK.** A non-standard collection envelope produces inconsistent client pagination behavior. | | [`lro-location-header`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/lro-location-header/) | [`LroLocationHeader`](https://github.com/Azure/azure-openapi-validator/blob/main/docs/lro-location-header.md) | **API.** RPC violation. | +| [`lro-response-mismatch`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/lro-response-mismatch/) | — | **API, SDK.** A mismatched final result can break generated SDKs or make them difficult to use. | | [`missing-operations-endpoint`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/missing-operations-endpoint/) | [R3023](https://github.com/Azure/azure-rest-api-specs/blob/main/documentation/openapi-authoring-automated-guidelines.md#r3023) | **API.** RPC violation. | | [`missing-x-ms-identifiers`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/missing-x-ms-identifiers/) | [R4041](https://github.com/Azure/azure-rest-api-specs/blob/main/documentation/openapi-authoring-automated-guidelines.md#r4041) (warning) | **API.** No real impact (an old pattern). | | [`no-empty-model`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/no-empty-model/) | [R4037](https://github.com/Azure/azure-rest-api-specs/blob/main/documentation/openapi-authoring-automated-guidelines.md#r4037) | **API, SDK.** Accepting any schema makes the API and SDK difficult to use. | | [`no-override-props`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/no-override-props/) | — | **SDK, Tooling.** Violations can crash the breaking-change tool and are unsupported by most languages. | +| [`no-query-in-collection`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/no-query-in-collection/) | [`QueryParametersInCollectionGet`](https://github.com/Azure/azure-openapi-validator/blob/main/packages/rulesets/src/spectral/functions/query-parameters-in-collection-get.ts) | **API, SDK.** Query parameters other than `api-version` and `$filter` make collection GET operations and generated SDK methods inconsistent. | +| [`no-query-in-point-op`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/no-query-in-point-op/) | [`ValidQueryParametersForPointOperations`](https://github.com/Azure/azure-openapi-validator/blob/main/docs/valid-query-parameters-for-point-operations.md) | **API, SDK.** Query parameters other than `api-version` make point operations inconsistent and complicate generated SDK methods. | +| [`no-query-in-post`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/no-query-in-post/) | [`ParametersInPost`](https://github.com/Azure/azure-openapi-validator/blob/main/docs/parameters-in-post.md) | **API, SDK.** Request-specific POST input in query parameters violates the ARM request contract and produces inconsistent SDK methods. | | [`no-resource-delete-operation`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/no-resource-delete-operation/) | [`AllTrackedResourcesMustHaveDelete`](https://github.com/Azure/azure-openapi-validator/blob/main/docs/all-tracked-resources-must-have-delete.md) | **API.** RPC violation. | | [`no-response-body`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/no-response-body/) | — | **API.** A non-empty response, usually for a 202. | +| [`no-tenant-level-apis`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/no-tenant-level-apis/) | [`TenantLevelAPIsNotAllowed`](https://github.com/Azure/azure-openapi-validator/blob/main/docs/tenant-level-apis-not-allowed.md) | **API.** Tenant-level PUT operations require additional security review and should use subscription or resource-group scope. | | [`patch-envelope`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/patch-envelope/) | — | **API.** A Patch operation is missing updatable envelope properties. | | [`resource-name`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/resource-name/) | — | **API, SDK.** Invalid characters in a name violate the RPC and create invalid client parameter names, which prevents SDK generation. | | [`secret-prop`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/secret-prop/) | [`XMSSecretInResponse`](https://github.com/Azure/azure-openapi-validator/blob/main/docs/xms-secret-in-response.md) | **API.** RPC violation. | | [`unsupported-type`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/unsupported-type/) | — | **SDK.** The data type cannot be modeled in SDKs. | | [`use-api-version`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/use-api-version/) | [`ApiVersionParameterRequired`](https://github.com/Azure/azure-openapi-validator/blob/main/docs/api-version-parameter-required.md) | **API, SDK.** An operation without the standard API version parameter cannot evolve safely and is difficult for SDKs to represent consistently. | +| [`use-application-json-content-type`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/use-application-json-content-type/) | [`NonApplicationJsonType`](https://github.com/Azure/azure-openapi-validator/blob/main/packages/rulesets/src/spectral/az-arm.ts) | **API, SDK.** Non-JSON request or response bodies are incompatible with ARM tooling and prevent predictable SDK serialization. | | [`use-create-for-put`](https://azure.github.io/typespec-azure/docs/libraries/typespec-client-generator-core/rules/use-create-for-put/) | [PutInOperationName (R1006)](https://github.com/Azure/azure-rest-api-specs/blob/main/documentation/openapi-authoring-automated-guidelines.md#r1006) | **SDK.** TCGC checks the common SDK method name, including unscoped `@clientName` overrides; renaming a shipped method may break SDK compatibility. | | [`use-interface`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/use-interface/) | — | **API, SDK, Emitters.** Resource operations outside interfaces can break ARM resource-operation modeling and downstream tooling assumptions. | | [`use-model-request-body`](https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/use-model-request-body/) | [`ParametersSchemaAsTypeObject`](https://github.com/Azure/azure-openapi-validator/blob/main/docs/parameters-schema-as-type-object.md) | **API, SDK.** Non-model, array, and record request bodies cannot evolve with additional properties without a breaking change. | diff --git a/website/src/content/docs/docs/howtos/ARM/resource-operations.md b/website/src/content/docs/docs/howtos/ARM/resource-operations.md index 843b322ce9..4145b095fd 100644 --- a/website/src/content/docs/docs/howtos/ARM/resource-operations.md +++ b/website/src/content/docs/docs/howtos/ARM/resource-operations.md @@ -200,19 +200,16 @@ The `ArmListBySubscriptionScope` template is used for listing a resource directl scope, generating a flat subscription-level path regardless of the resource's parent hierarchy. Use this instead of `ArmListBySubscription` when you need a subscription-level list operation for a child resource. -#### Adding standard `$top`, `$filter`, and `$skip` query parameters +#### Adding the standard `$filter` query parameter -Pass ARM's standard list query parameters through the `Parameters` template argument instead of -defining custom `@query("$top")`, `@query("$filter")`, or `@query("$skip")` properties yourself. -Compose the reusable ARM parameter models for the options your operation supports. +ARM collection GET operations may use only the standard `api-version` and `$filter` query +parameters. Pass `ArmFilterParameter` through the `Parameters` template argument instead of +defining a custom `@query("$filter")` property. ```typespec @armResourceOperations interface Employees { - listBySubscription is ArmListBySubscription< - Employee, - Parameters = ArmTopParameter & ArmFilterParameter & ArmSkipParameter - >; + listBySubscription is ArmListBySubscription; } ``` diff --git a/website/src/content/docs/docs/howtos/ARM/versioning.md b/website/src/content/docs/docs/howtos/ARM/versioning.md index 49d65ef83a..083323508a 100644 --- a/website/src/content/docs/docs/howtos/ARM/versioning.md +++ b/website/src/content/docs/docs/howtos/ARM/versioning.md @@ -158,7 +158,7 @@ interface Employees { In version `v2`, you want to: - Make the `location` header parameter optional. -- Add a new optional query parameter `orderBy`. +- Add the standard optional `$filter` query parameter. You can achieve this using the `@madeOptional` and `@added` decorators: @@ -173,8 +173,8 @@ interface Employees { location?: string; @added(Versions.v2) - @query("order-by") - orderBy?: string; + @query("$filter") + filter?: string; } >; } @@ -183,7 +183,8 @@ interface Employees { **Explanation:** - `@madeOptional(Versions.v2)` makes `location` optional starting in v2. -- `@added(Versions.v2)` adds the `orderBy` query parameter in v2 and later. +- `@added(Versions.v2)` adds the `$filter` query parameter in v2 and later. ARM collection GET + operations do not allow other query parameters besides `api-version`. ### Converting an Operation from Synchronous to Asynchronous