From 97b50d1902a4fc88ba2e26b3fe302163b3f10ba2 Mon Sep 17 00:00:00 2001 From: Jeffrey Richter Date: Wed, 17 Jan 2024 10:49:44 -0800 Subject: [PATCH 01/10] Added LRO guidelines --- azure/Guidelines.md | 192 +++++++++++++++++++++++++++++++------------- 1 file changed, 137 insertions(+), 55 deletions(-) diff --git a/azure/Guidelines.md b/azure/Guidelines.md index 70c99a43..cc31c24a 100644 --- a/azure/Guidelines.md +++ b/azure/Guidelines.md @@ -16,6 +16,7 @@ Please ensure that you add an anchor tag to any new guidelines that you add and | Date | Notes | | ----------- | -------------------------------------------------------------- | +| 2024-Feb-17 | Updated LRO guidelines | | 2024-Jan-17 | Added guidelines on returning string offsets & lengths | | 2023-May-12 | Explain service response for missing/unsupported `api-version` | | 2023-Apr-21 | Update/clarify guidelines on POST method repeatability | @@ -847,109 +848,189 @@ https://github.com/microsoft/api-guidelines/blob/vNext/azure/Guidelines.md#perfo - Any operation that does not support repeatability headers should return a 501 (Not Implemented) response for any request that contains valid repeatability request headers. -### Long-Running Operations & Jobs +### Long-Running Operations (LROs) -When the processing for an operation may take a significant amount of time to complete, it should be -implemented as a _long-running operation (LRO)_. This allows clients to continue running while the -operation is being processed. The client obtains the outcome of the operation at some later time -through another API call. -See the [Long Running Operations section](./ConsiderationsForServiceDesign.md#long-running-operations) in -Considerations for Service Design for an introduction to the design of long-running operations. +A _long-running operation (LRO)_ is typically an operation that should execute synchronously but due to services not wanting to maintain long-lived connections (>1 seconds) and load-balancer timeouts the operation must execute asynchronously. For this pattern, the client initiates the operation on the service and then the client repeatedly polls the service (via another API call) to track the operation's progress/completion. -:white_check_mark: **DO** implement an operation as an LRO if the 99th percentile response time is greater than 1s. +LROs are always started by 1 logical client and may be be polled (have their status checked) by the same client, another client, or even multiple clients/browsers. An example would be a dashboard or portal that shows all the operations along with their status. See the [Long Running Operations section](./ConsiderationsForServiceDesign.md#long-running-operations) in Considerations for Service Design for an introduction to the design of long-running operations. -:no_entry: **DO NOT** implement PATCH as an LRO. If LRO update is required it must be implemented with POST. +:white_check_mark: **DO** implement an operation as an LRO if the 99th percentile response time is greater than 1 second and when the client should poll the operation before making more progress. -In rare instances where an operation may take a _very long_ time to complete, e.g. longer than 15 minutes, -it may be better to expose this as a first class resource of the API rather than as an operation on another resource. +:no_entry: **DO NOT** implement PATCH as an LRO. If LRO update semantics are required, implement it using the [LRO POST action pattern](#lro-existing-resource) . -There are two basic patterns for long-running operations in Azure. The first pattern is used for a POST and DELETE -operations that initiate the LRO. These return a `202 Accepted` response with a JSON status monitor in the response body. -The second pattern applies only in the case of a PUT operation to create a resource that also involves additional long-running processing. -For guidance on when to use a specific pattern, please refer to [Considerations for Service Design, Long Running Operations](./ConsiderationsForServiceDesign.md#long-running-operations). -These are described in the following two sections. +## Patterns to Initiate a Long-Running Operation -#### POST or DELETE LRO pattern +:white_check_mark: **DO** perform as much validation as practical when initiating an LRO operation to alert clients of errors early. -A POST or DELETE long-running operation accepts a request from the client to initiate the operation processing and returns -a [status monitor](https://datatracker.ietf.org/doc/html/rfc7231#section-6.3.3) that reports the operation's progress. +:ballot_box_with_check: **YOU SHOULD** include an `operation-location` response header with the absolute URL of the status monitor for the operation. -:no_entry: **DO NOT** use a long-running POST to create a resource -- use PUT as described below. +:ballot_box_with_check: **YOU SHOULD** include the `api-version` query parameter in the `operation-location` response header with the same version passed on the initial request but expect a client to change the `api-version` value to whatever a new/different client desires it to be. -:white_check_mark: **DO** allow the client to pass an `Operation-Id` header with an ID for the operation's status monitor. +:white_check_mark: **DO** include response headers with any additional values needed for a [GET polling request](#lro-poll) to the status monitor (e.g. location). -:white_check_mark: **DO** generate an ID (typically a GUID) for the status monitor if the `Operation-Id` header was not passed by the client. +:white_check_mark: **DO** include a `retry-after` header in the response if the operation is not complete. The value of this header should be an integer number of seconds that the client should wait before polling the status monitor again. -:white_check_mark: **DO** fail a request with a `400-BadRequest` if the `Operation-Id` header matches an existing operation unless the request is identical to the prior request (a retry scenario). +:white_check_mark: **DO** use the following pattern when implementing an operation that creates a resource that takes time to initialize:

+``` +PUT /UrlToResourceBeingCreated +operation-id: ` + +``` -:white_check_mark: **DO** perform as much validation as practical when initiating the operation to alert clients of errors early. +The response must look like this:

+``` +200 OK +operation-id: +operation-location: https://operations/ +retry-after: (if status not terminal) + +``` -:white_check_mark: **DO** return a `202-Accepted` status code from the request that initiates an LRO if the processing of the operation was successfully initiated (except for "PUT with additional processing" type LRO). +- PUT creates the resource immediately and returns but the initialization of the resource can take time to complete. -:warning: **YOU SHOULD NOT** return any other `2xx` status code from the initial request of an LRO -- return `202-Accepted` and a status monitor even if processing was completed before the initiating request returns. +- The request & response body schemas must be identical & represent the resource. -:white_check_mark: **DO** return a status monitor in the response body as described in [Obtaining status and results of long-running operations](#obtaining-status-and-results-of-long-running-operations). + - The resource schema must contain an `initializationStatus` property indicating whether the initialization is `Running`, `Failed`, `Succeeded`, etc. -:ballot_box_with_check: **YOU SHOULD** include an `Operation-Location` header in the response with the absolute URL of the status monitor for the operation. +- This operation implicitly creates a status monitor resource and sets its `kind` property to something like `Initializing`; for example `VMInitializing`. -:ballot_box_with_check: **YOU SHOULD** include the `api-version` query parameter in the `Operation-Location` header with the same version passed on the initial request if it is required by the get operation on the status monitor. +- The `operation-id` header allows the client to specify the status monitor's resource ID and is also used for retries/idempotency. If unspecified, the service may create an operation-id (typically a GUID) and return it via the `operation-id` and `operation-location` response headers; in this case the service must figure out how to deal with retries/idempotency. -#### PUT operation with additional long-running processing + - For an idempotent PUT (same `operation-id` or same request body within some short time window), the service should return the same response as shown above. -For a PUT (create or replace) with additional long-running processing: + - For a non-idempotent PUT, the service can choose to overwrite the existing resource (as if the resource were deleted) or the service can return `409-Conflict` with the error's code property indicated why this PUT operation failed. + +:white_check_mark: **DO** use the following pattern when implementing an LRO operation to delete a resource:

+``` +DELETE /UrlToResourceBeingDeleted +operation-id: +``` -:white_check_mark: **DO** allow the client to pass an `Operation-Id` header with a ID for the status monitor for the operation. +The response must look like this:

+``` +202 Accepted +operation-id: +operation-location: https://operations/ +retry-after: (if status not terminal) +``` -:white_check_mark: **DO** generate an ID (typically a GUID) for the status monitor if the `Operation-Id` header was not passed by the client. +- If a request body is specified, return `400-Bad Request`. -:white_check_mark: **DO** fail a request with a `400-BadRequest` if the `Operation-Id` header that matches an existing operation unless the request is identical to the prior request (a retry scenario). +- Do not return a response body. -:white_check_mark: **DO** perform as much validation as practical when initiating the operation to alert clients of errors early. +- This operation implicitly creates a status monitor resource and sets its `kind` property to something like `Deleting`; for example `VMDeleting`. -:white_check_mark: **DO** return a `201-Created` status code for create or `200-OK` for replace from the initial request with a representation of the resource if the resource was created successfully. +- The `operation-id` header allows the client to specify the status monitor's resource ID and is also used for retries/idempotency. If unspecified, the service may create an operation-id (typically a GUID) and return it via the `operation-id` and `operation-location` response headers; in this case the service must figure out how to deal with retries/idempotency. -:white_check_mark: **DO** include an `Operation-Id` header in the response with the ID of the status monitor for the operation. +:white_check_mark: **DO** use the following pattern when implementing an LRO action operating on an existing resource:

+``` +POST /UrlToExistingResource: +operation-id: ` + +``` -:white_check_mark: **DO** include response headers with any additional values needed for a GET request to the status monitor (e.g. location). +The response must look like this:

+``` +202 Accepted +operation-id: +operation-location: https://operations/ +retry-after: (if status not terminal) + +``` + +- The request body identifies parameters required to execute the action. + +- This operation implicitly creates a status monitor resource and sets its `kind` property to something like ``; for example `VMRebooting`. + +- The response body must be the implicily created status monitor resource. + +- The `operation-id` header allows the client to specify the status monitor's resource ID and is also used for retries/idempotency. If unspecified, the service may create an operation-id (typically a GUID) and return it via the `operation-id` and `operation-location` response headers; in this case, the service must figure out how to deal with retries/idempotency. -:ballot_box_with_check: **YOU SHOULD** include an `Operation-Location` header in the response with the absolute URL of the status monitor for the operation. + - For an idempotent POST (same `operation-id` or same request body within some short time window), the service should return the same response as shown above. -:ballot_box_with_check: **YOU SHOULD** include the `api-version` query parameter in the `Operation-Location` header with the same version passed on the initial request if it is required by the get operation on the status monitor. + - For a non-idempotent POST, the service can treat the POST operation as idempotent (if performed within a short time window) or can treat the POST operation as initiating a brand new LRO action operation. -#### Obtaining status and results of long-running operations +:white_check_mark: **DO** use the following pattern when implementing an LRO action not related to a specific resource (such as a batch operation):

+``` +PUT /operations/ + +``` -For all long-running operations, the client will issue a GET on a status monitor resource to obtain the current status of the operation. +The response must look like this:

+``` +200 OK +retry-after: (if status not terminal) + +``` -:white_check_mark: **DO** support the GET method on the status monitor endpoint that returns a `200-OK` response with the current state of the status monitor. +- This operation *explicitly* creates a status monitor resource as passed in the request body. -:ballot_box_with_check: **YOU SHOULD** allow any valid value of the `api-version` query parameter to be used in the get operation on the status monitor. + - The request's `kind` property must be set by the client to some value pre-defined by the service; for example `batchDocumentTranslate`. -Note: Clients may replace the value of `api-version` in the `Operation-Location` URI with a value appropriate for their application. +- The response body is the status monitor resource whose schema must be idential to the request's body. -:white_check_mark: **DO** return a status monitor in the response body that conforms with the following structure: +- The `operation-id` URL segment (not header) is *mandatory* forcing the client to specify the status monitor's resource ID and is also used for retries/idempotency. -**OperationStatus** : Object +## The Status Monitor Resource +All patterns that initiate a LRO either implicitly or explicitly create a [Status Monitor resource](https://datatracker.ietf.org/doc/html/rfc7231#section-6.3.3) in the service's `operations` collection. A Status Monitor resource must look like this: Property | Type | Required | Description -------- | ----------- | :------: | ----------- `id` | string | true | The unique id of the operation -`status` | string | true | enum that includes values "NotStarted", "Running", "Succeeded", "Failed", and "Canceled" -`error` | ErrorDetail | | Error object that describes the error when status is "Failed" -`result` | object | | Only for POST action-type LRO, the results of the operation when completed successfully -additional
properties | | | Additional named or dynamic properties of the operation +`kind` | string enum | true | The kind of operation +`status` | string enum | true | The operation's current status: "NotStarted", "Running", "Succeeded", "Failed", and "Canceled" +`error` | ErrorDetail | | If `status`=="Failed", contains reason for failure +`result` | object | | if Action LRO (POST or PUT) && `status`=="Succeeded", contains success result +additional
properties | | | Additional named or dynamic properties of the operation -:white_check_mark: **DO** include the `id` of the operation and any other values needed for the client to form a GET request to the status monitor (e.g. a `location` path parameter). +- Because services can support different kinds of operations, status monitor resources in this collection *must be* polymorphic; the `kind` property indicates the kind of long-running operation. -:white_check_mark: **DO** include a `Retry-After` header in the response to GET requests to the status monitor if the operation is not complete. The value of this header should be an integer number of seconds to wait before making the next request to the status monitor. +## Pattern to Poll a Long-Running Operation's Status -:white_check_mark: **DO** include the `result` property (if any) in the status monitor for a POST action-type long-running operation when the operation completes successfully. +:white_check_mark: **DO** use the following pattern to allow clients to poll the current state of a Status Monitor resource:

+``` +GET /operations/ +``` + +The response must look like this:

+``` +200 OK +retry-after: (if status not terminal) + +``` + +:ballot_box_with_check: **YOU SHOULD** allow any valid value of the `api-version` query parameter to be used in the GET operation on the status monitor. -:no_entry: **DO NOT** include a `result` property in the status monitor for a long-running operation that is not a POST action-type long-running operation. + - Note: Clients may replace the value of `api-version` in the `operation-location` URL with a value appropriate for their application. Remember that the client initiating the LRO may not be the same client polling the LRO's status. :white_check_mark: **DO** retain the status monitor resource for some publicly documented period of time (at least 24 hours) after the operation completes. +## Pattern to List Status Monitors (optional) + +:white_check_mark: **DO** use the following pattern to allow clients to list Status Monitor resources:

+``` +GET /operations?kind=VMInitializing,VMRebooting&status=NotStarted,Succeeded +``` + +The response must look like this:

+```200 OK +{ + "value": [ + { "id": "12345", "kind": "VMInitializing", "status": "Running", … }, + { … }, + { … }, + { "id": "abcde", "kind": "VMRebooting", "status": "Failed", … } + ], + "nextLink": "{opaqueUrl}" +} +``` + - The values for the `kind` and `status` query parameters are logically OR'd together. + + - The above example returns all status monitor resources whose `kind` is either "VMInitializing" *or* "VMRebooting" and whose status is "NotStarted" *or* "Succeeded". + ### Bring your own Storage (BYOS) + Many services need to store and retrieve data files. For this scenario, the service should not implement its own storage APIs and should instead leverage the existing Azure Storage service. When doing this, the customer "owns" the storage account and just tells your service to use it. Colloquially, we call this Bring Your Own Storage as the customer is bringing their storage account to another service. BYOS provides significant benefits to service implementors: security, performance, uptime, etc. And, of course, most Azure customers are already familiar with the Azure Storage service. @@ -1120,6 +1201,7 @@ See the [Returning String Offsets & Lengths] section in Considerations for Servi ### Distributed Tracing & Telemetry + Azure SDK client guidelines specify that client libraries must send telemetry data through the `User-Agent` header, `X-MS-UserAgent` header, and Open Telemetry. Client libraries are required to send telemetry and distributed tracing information on every request. Telemetry information is vital to the effective operation of your service and should be a consideration from the outset of design and implementation efforts. From 372bcd6ee9454d52d16bc148c9211716fd2e3417 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 26 Feb 2024 18:40:49 -0600 Subject: [PATCH 02/10] Restore all prior named guidelines with some edits where needed --- azure/ConsiderationsForServiceDesign.md | 215 ++++++++++++++++-------- azure/Guidelines.md | 121 +++++++++---- 2 files changed, 230 insertions(+), 106 deletions(-) diff --git a/azure/ConsiderationsForServiceDesign.md b/azure/ConsiderationsForServiceDesign.md index c9da5f42..fe422be5 100644 --- a/azure/ConsiderationsForServiceDesign.md +++ b/azure/ConsiderationsForServiceDesign.md @@ -6,6 +6,7 @@ | Date | Notes | | ----------- | -------------------------------------------------------------- | +| 2024-Mar-17 | Updated LRO guidelines | | 2024-Jan-17 | Added guidelines on returning string offsets & lengths | | 2022-Jul-15 | Update guidance on long-running operations | | 2022-Feb-01 | Updated error guidance | @@ -216,7 +217,7 @@ cannot collide with a resource path that contains user-specified resource ids. ## Long-Running Operations -Long-running operations are an API design pattern that should be used when the processing of +Long-running operations (LROs) are an API design pattern that should be used when the processing of an operation may take a significant amount of time -- longer than a client will want to block waiting for the result. @@ -225,16 +226,90 @@ a _status monitor_, which is an ephemeral resource that will track the status an The status monitor resource is distinct from the target resource (if any) and specific to the individual operation request. -A POST or DELETE operation returns a `202 Accepted` response with the status monitor in the response body. -A long-running POST should not be used for resource create -- use PUT as described below. -PATCH must never be used for long-running operations -- it should be reserved for simple resource updates. -If a long-running update is required it should be implemented with POST. +There are four types of LROs allowed in Azure REST APIs: + +1. An LRO to create or replace a resource that involves additional long-running processing. +2. An LRO to delete a resource. +3. An LRO to perform an action on or with an existing resource (or resource collection). +4. An LRO to perform an action not related to an existing resource (or resource collection). + +The following sections describe these patterns in detail. + +### Create or replace a resource requiring additional long-running processing + + +A special case of long-running operation that occurs often is a PUT operation to create or replace a resource +that involves some additional long-running processing. +One example is a resource that requires physical resources (e.g. servers) to be "provisioned" to make the resource functional. + +In this case: +- The operation must use the PUT method (NOTE: PATCH is never allowed here) +- The URL identifies resource being created or replaced. +- The request and response body have identical schemas & represent the resource. +- The request may contain an `Operation-Id` header that the service will use as +the ID of the status monitor created for the operation. + +```text +PUT /items/FooBar&api-version=2022-05-01 +Operation-Id: 22 + +{ + "prop1": 555, + "prop2": "something" +} +``` + +In this case the response to the initial request is a `201 Created` to indicate that +the resource has been created or `200 OK` when the resource was replaced. +A status monitor is created to track the additional processing and the ID of the status monitor +is returned in the `Operation-Id` header of the response. +The response may also include an `Operation-Location` header for backward compatibility. +If the resource supports ETags, the response may contain an `etag` header and possibly an `etag` property in the resource. + +```text +HTTP/1.1 201 Created +Operation-Id: 22 +Operation-Location: https://items/operations/22 +etag: "123abc" + +{ + "id": "FooBar", + "etag": "123abc", + "prop1": 555, + "prop2": "something" +} +``` + +The client will issue a GET to the status monitor to obtain the status of the operation performing the additional processing. + +```text +GET https://items/operations/22?api-version=2022-05-01 +``` -There is a special form of long-running operation initiated with PUT that is described -in [Create (PUT) with additional long-running processing](./Guidelines.md#put-operation-with-additional-long-running-processing). -The remainder of this section describes the pattern for long-running POST and DELETE operations. +When the additional processing completes, the status monitor will indicate if it succeeded or failed. -This diagram illustrates how a long-running operation with a status monitor is initiated and then how the client +```text +HTTP/1.1 200 OK + +{ + "id": "22", + "status": "Succeeded" +} +``` + +If the additional processing failed, the service may delete the original resource if it is not usable in this state, +but should clearly document this behavior. + +### Long-running delete operation + +A long-running delete operation follows the general pattern of a long-running operation -- +it returns a `202 Accepted` with a status monitor which the client uses to determine the outcome of the delete. + +The resource being deleted should remain visible (returned from a GET) until the delete operation completes successfully. + +When the delete operation completes successfully, a client must be able to create a new resource with same name without conflicts. + +This diagram illustrates how a long-running DELETE operation is initiated and then how the client determines it has completed and obtains its results: ```mermaid @@ -242,7 +317,7 @@ sequenceDiagram participant Client participant API Endpoint participant Status Monitor - Client->>API Endpoint: POST/DELETE + Client->>API Endpoint: DELETE API Endpoint->>Client: HTTP/1.1 202 Accepted
{ "id": "22", "status": "NotStarted" } Client->>Status Monitor: GET Status Monitor->>Client: HTTP/1.1 200 OK
Retry-After: 5
{ "id": "22", "status": "Running" } @@ -250,8 +325,7 @@ sequenceDiagram Status Monitor->>Client: HTTP/1.1 200 OK
{ "id": "22", "status": "Succeeded" } ``` -1. The client sends the request to initiate the long-running operation. -The initial request could be a POST or DELETE method. +1. The client sends the request to initiate the long-running DELETE operation. The request may contain an `Operation-Id` header that the service uses as the ID of the status monitor created for the operation. 2. The service validates the request and initiates the operation processing. @@ -274,11 +348,8 @@ If the operation is still being processed, the status field will contain a "non- 5. After the operation processing completes, a GET request to the status monitor returns the status monitor with a status field set to a terminal value -- `Succeeded`, `Failed`, or `Canceled` -- that indicates the result of the operation. If the status is `Failed`, the status monitor resource contains an `error` field with a `code` and `message` that describes the failure. -If the status is `Succeeded` and the LRO is an Action operation, the operation results will be returned in the `result` field of the status monitor. -If the status is `Succeeded` and the LRO is an operation on a resource, the client can perform a GET on the resource -to observe the result of the operation if desired. -6. There may be some cases where a long-running operation can be completed before the response to the initial request. +6. There may be some cases where a long-running DELETE operation can be completed before the response to the initial request. In these cases, the operation should still return a `202 Accepted` with the `status` property set to the appropriate terminal state. 7. The service is responsible for purging the status-monitor resource. @@ -291,6 +362,9 @@ An action operation that is also long-running combines the [Action Operations](# with the [Long Running Operations](#long-running-operations) pattern. The operation is initiated with a POST operation and the operation path ends in `:`. +A long-running POST should not be used for resource create -- use PUT as described above. +PATCH must never be used for long-running operations -- it should be reserved for simple resource updates. +If a long-running update is required it should be implemented with POST. ```text POST /:?api-version=2022-05-01 @@ -302,7 +376,7 @@ Operation-Id: 22 } ``` -The response is a `202 Accepted` as described above. +A long-running action operation returns a `202 Accepted` response with the status monitor in the response body. ```text HTTP/1.1 202 Accepted @@ -332,74 +406,77 @@ HTTP/1.1 200 OK } ``` -### PUT with additional long-running processing +This diagram illustrates how a long-running action operation is initiated and then how the client +determines it has completed and obtains its results: -A special case of long-running operation that occurs often is a PUT operation to create or replace a resource -that involves some additional long-running processing. -One example is a resource requires physical resources (e.g. servers) to be "provisioned" to make the resource functional. -In this case, the request may contain an `Operation-Id` header that the service will use as -the ID of the status monitor created for the operation. +```mermaid +sequenceDiagram + participant Client + participant API Endpoint + participant Status Monitor + Client->>API Endpoint: POST + API Endpoint->>Client: HTTP/1.1 202 Accepted
{ "id": "22", "status": "NotStarted" } + Client->>Status Monitor: GET + Status Monitor->>Client: HTTP/1.1 200 OK
Retry-After: 5
{ "id": "22", "status": "Running" } + Client->>Status Monitor: GET + Status Monitor->>Client: HTTP/1.1 200 OK
{ "id": "22", "status": "Succeeded", "result": { ... } } +``` -```text -PUT /items/FooBar&api-version=2022-05-01 -Operation-Id: 22 +1. The client sends the request to initiate the long-running action operation. +The request may contain an `Operation-Id` header that the service uses as the ID of the status monitor created for the operation. -{ - "prop1": 555, - "prop2": "something" -} -``` +2. The service validates the request and initiates the operation processing. +If there are any problems with the request, the service responds with a `4xx` status code and error response body. +Otherwise the service responds with a `202-Accepted` HTTP status code. +The response body is the status monitor for the operation including the ID, either from the request header or generated by the service. +When returning a status monitor whose status is not in a terminal state, the response must also include a `retry-after` header indicating the minimum number of seconds the client should wait +before polling (GETing) the status monitor URL again for an update. +For backward compatibility, the response may also include an `Operation-Location` header containing the absolute URL +of the status monitor resource (without an api-version query parameter). -In this case the response to the initial request is a `201 Created` to indicate that the resource has been created -or `200 OK` when the resource was replaced. -The response body contains a representation of the created resource, which is the standard pattern for a create operation. -A status monitor is created to track the additional processing and the ID of the status monitor -is returned in the `Operation-Id` header of the response. -The response may also include an `Operation-Location` header for backward compatibility. -If the resource supports ETags, the response may contain an `etag` header and possibly an `etag` property in the resource. +3. After waiting at least the amount of time specified by the previous response's `Retry-after` header, +the client issues a GET request to the status monitor using the ID in the body of the initial response. +The GET operation for the status monitor is documented in the REST API definition and the ID +is the last URL path segment. -```text -HTTP/1.1 201 Created -Operation-Id: 22 -Operation-Location: https://items/operations/22 -etag: "123abc" +4. The status monitor responds with information about the operation including its current status, +which should be represented as one of a fixed set of string values in a field named `status`. +If the operation is still being processed, the status field will contain a "non-terminal" value, like `NotStarted` or `Running`. -{ - "id": "FooBar", - "etag": "123abc", - "prop1": 555, - "prop2": "something" -} -``` +5. After the operation processing completes, a GET request to the status monitor returns the status monitor with a status field set to a terminal value -- `Succeeded`, `Failed`, or `Canceled` -- that indicates the result of the operation. +If the status is `Failed`, the status monitor resource contains an `error` field with a `code` and `message` that describes the failure. +If the status is `Succeeded`, the operation results will be returned in the `result` field of the status monitor. -The client will issue a GET to the status monitor to obtain the status of the operation performing the additional processing. +6. There may be some cases where a long-running action operation can be completed before the response to the initial request. +In these cases, the operation should still return a `202 Accepted` with the `status` property set to the appropriate terminal state. -```text -GET https://items/operations/22?api-version=2022-05-01 -``` +7. The service is responsible for purging the status-monitor resource. +It should auto-purge the status monitor resource after completion (at least 24 hours). +The service may offer DELETE of the status monitor resource due to GDPR/privacy. -When the additional processing completes, the status monitor will indicate if it succeeded or failed. +### Long-running action operation not related to a resource -```text -HTTP/1.1 200 OK +When an long-running action operation is not related to a specific resource (a batch operation is one example), +another approach is needed. -{ - "id": "22", - "status": "Succeeded" -} -``` +A long-running action operation not related to a resource should use a PUT operation for a resource that combines a status monitor with the request and results of the operation. In this pattern, clients obtain the status of the operation by issuing a GET on the same URL as the PUT operation. -If the additional processing failed, the service may delete the original resource if it is not usable in this state, -but would have to clearly document this behavior. +The following examples illustrate this pattern. -### Long-running delete operation +```text +PUT /translate-operations/ -A long-running delete operation follows the general pattern of a long-running operation -- -it returns a `202 Accepted` with a status monitor which the client uses to determine the outcome of the delete. + +``` -The resource being deleted should remain visible (returned from a GET) until the delete operation completes successfully. +Note that the client specifies the operation id in the URL path. -When the delete operation completes successfully, a client must be able to create new resource with same name without conflicts. +A successful response to the PUT operation should have a `201 Created` status and response body +of the same structure as the request body, possibly with some additional output-only fields. + +The service is responsible for purging the combined status-monitor/request/response resource. +It should auto-purge this resource after completion (at least 24 hours). +The service may offer DELETE of the status monitor resource due to GDPR/privacy. ### Controlling a long-running operation diff --git a/azure/Guidelines.md b/azure/Guidelines.md index cc31c24a..66ba5c1c 100644 --- a/azure/Guidelines.md +++ b/azure/Guidelines.md @@ -16,7 +16,7 @@ Please ensure that you add an anchor tag to any new guidelines that you add and | Date | Notes | | ----------- | -------------------------------------------------------------- | -| 2024-Feb-17 | Updated LRO guidelines | +| 2024-Mar-17 | Updated LRO guidelines | | 2024-Jan-17 | Added guidelines on returning string offsets & lengths | | 2023-May-12 | Explain service response for missing/unsupported `api-version` | | 2023-Apr-21 | Update/clarify guidelines on POST method repeatability | @@ -847,10 +847,10 @@ https://github.com/microsoft/api-guidelines/blob/vNext/azure/Guidelines.md#perfo - Document the POST operation's support for the `Repeatability-First-Sent`, `Repeatability-Request-ID`, and `Repeatability-Result` headers in the API contract and documentation. - Any operation that does not support repeatability headers should return a 501 (Not Implemented) response for any request that contains valid repeatability request headers. - ### Long-Running Operations (LROs) + -A _long-running operation (LRO)_ is typically an operation that should execute synchronously but due to services not wanting to maintain long-lived connections (>1 seconds) and load-balancer timeouts the operation must execute asynchronously. For this pattern, the client initiates the operation on the service and then the client repeatedly polls the service (via another API call) to track the operation's progress/completion. +A _long-running operation (LRO)_ is typically an operation that should execute synchronously but due to services not wanting to maintain long-lived connections (>1 seconds) and load-balancer timeouts the operation must execute asynchronously. For this pattern, the client initiates the operation on the service and then the client repeatedly polls the service (via another API call) to track the operation's progress/completion. LROs are always started by 1 logical client and may be be polled (have their status checked) by the same client, another client, or even multiple clients/browsers. An example would be a dashboard or portal that shows all the operations along with their status. See the [Long Running Operations section](./ConsiderationsForServiceDesign.md#long-running-operations) in Considerations for Service Design for an introduction to the design of long-running operations. @@ -858,7 +858,7 @@ LROs are always started by 1 logical client and may be be polled (have their sta :no_entry: **DO NOT** implement PATCH as an LRO. If LRO update semantics are required, implement it using the [LRO POST action pattern](#lro-existing-resource) . -## Patterns to Initiate a Long-Running Operation +#### Patterns to Initiate a Long-Running Operation :white_check_mark: **DO** perform as much validation as practical when initiating an LRO operation to alert clients of errors early. @@ -868,17 +868,20 @@ LROs are always started by 1 logical client and may be be polled (have their sta :white_check_mark: **DO** include response headers with any additional values needed for a [GET polling request](#lro-poll) to the status monitor (e.g. location). -:white_check_mark: **DO** include a `retry-after` header in the response if the operation is not complete. The value of this header should be an integer number of seconds that the client should wait before polling the status monitor again. +#### Create or replace operation with additional long-running processing + -:white_check_mark: **DO** use the following pattern when implementing an operation that creates a resource that takes time to initialize:

-``` +:white_check_mark: **DO** use the following pattern when implementing an operation that creates or replaces a resource that involves additional long-running processing: + +```text PUT /UrlToResourceBeingCreated operation-id: ` ``` -The response must look like this:

-``` +The response must look like this: + +```text 200 OK operation-id: operation-location: https://operations/ @@ -886,20 +889,34 @@ retry-after: (if status not terminal) ``` -- PUT creates the resource immediately and returns but the initialization of the resource can take time to complete. +The request and response body schemas must be identical and represent the resource. -- The request & response body schemas must be identical & represent the resource. +The PUT creates or replaces the resource immediately and returns but the additional long-running processing can take time to complete. - - The resource schema must contain an `initializationStatus` property indicating whether the initialization is `Running`, `Failed`, `Succeeded`, etc. +For an idempotent PUT (same `operation-id` or same request body within some short time window), the service should return the same response as shown above. -- This operation implicitly creates a status monitor resource and sets its `kind` property to something like `Initializing`; for example `VMInitializing`. +For a non-idempotent PUT, the service can choose to overwrite the existing resource (as if the resource were deleted) or the service can return `409-Conflict` with the error's code property indicated why this PUT operation failed. -- The `operation-id` header allows the client to specify the status monitor's resource ID and is also used for retries/idempotency. If unspecified, the service may create an operation-id (typically a GUID) and return it via the `operation-id` and `operation-location` response headers; in this case the service must figure out how to deal with retries/idempotency. +:white_check_mark: **DO** allow the client to pass an `Operation-Id` header with a ID for the status monitor for the operation. - - For an idempotent PUT (same `operation-id` or same request body within some short time window), the service should return the same response as shown above. +If the `Operation-Id` header is not specified, the service may create an operation-id (typically a GUID) and return it via the `operation-id` and `operation-location` response headers; in this case the service must figure out how to deal with retries/idempotency. + +:white_check_mark: **DO** generate an ID (typically a GUID) for the status monitor if the `Operation-Id` header was not passed by the client. + +:white_check_mark: **DO** fail a request with a `400-BadRequest` if the `Operation-Id` header that matches an existing operation unless the request is identical to the prior request (a retry scenario). + +:white_check_mark: **DO** perform as much validation as practical when initiating the operation to alert clients of errors early. + +:white_check_mark: **DO** return a `201-Created` status code for create or `200-OK` for replace from the initial request with a representation of the resource if the resource was created successfully. + +:white_check_mark: **DO** include an `Operation-Id` header in the response with the ID of the status monitor for the operation. + +:ballot_box_with_check: **YOU SHOULD** include an `Operation-Location` header in the response with the absolute URL of the status monitor for the operation. + +:ballot_box_with_check: **YOU SHOULD** include the `api-version` query parameter in the `Operation-Location` header with the same version passed on the initial request if it is required by the get operation on the status monitor. + +#### DELETE LRO pattern - - For a non-idempotent PUT, the service can choose to overwrite the existing resource (as if the resource were deleted) or the service can return `409-Conflict` with the error's code property indicated why this PUT operation failed. - :white_check_mark: **DO** use the following pattern when implementing an LRO operation to delete a resource:

``` DELETE /UrlToResourceBeingDeleted @@ -914,13 +931,18 @@ operation-location: https://operations/ retry-after: (if status not terminal) ``` -- If a request body is specified, return `400-Bad Request`. +Consistent with non-LRO DELETE operations, if a request body is specified, return `400-Bad Request`. + +:white_check_mark: **DO** allow the client to pass an `Operation-Id` header with an ID for the operation's status monitor. -- Do not return a response body. +:white_check_mark: **DO** generate an ID (typically a GUID) for the status monitor if the `Operation-Id` header was not passed by the client. -- This operation implicitly creates a status monitor resource and sets its `kind` property to something like `Deleting`; for example `VMDeleting`. +:white_check_mark: **DO** return a `202-Accepted` status code from the request that initiates an LRO if the processing of the operation was successfully initiated. -- The `operation-id` header allows the client to specify the status monitor's resource ID and is also used for retries/idempotency. If unspecified, the service may create an operation-id (typically a GUID) and return it via the `operation-id` and `operation-location` response headers; in this case the service must figure out how to deal with retries/idempotency. +:warning: **YOU SHOULD NOT** return any other `2xx` status code from the initial request of an LRO -- return `202-Accepted` and a status monitor even if processing was completed before the initiating request returns. + +#### LRO action on a resource pattern + :white_check_mark: **DO** use the following pattern when implementing an LRO action operating on an existing resource:

``` @@ -938,17 +960,27 @@ retry-after: (if status not terminal) ``` -- The request body identifies parameters required to execute the action. +The request body contains information to be used to execute the action. + +For an idempotent POST (same `operation-id` and request body within some short time window), the service should return the same response as the initial request. + +For a non-idempotent POST, the service can treat the POST operation as idempotent (if performed within a short time window) or can treat the POST operation as initiating a brand new LRO action operation. + +:no_entry: **DO NOT** use a long-running POST to create a resource -- use PUT as described above. + +:white_check_mark: **DO** allow the client to pass an `Operation-Id` header with an ID for the operation's status monitor. -- This operation implicitly creates a status monitor resource and sets its `kind` property to something like ``; for example `VMRebooting`. +:white_check_mark: **DO** generate an ID (typically a GUID) for the status monitor if the `Operation-Id` header was not passed by the client. -- The response body must be the implicily created status monitor resource. +:white_check_mark: **DO** fail a request with a `400-BadRequest` if the `Operation-Id` header matches an existing operation unless the request is identical to the prior request (a retry scenario). -- The `operation-id` header allows the client to specify the status monitor's resource ID and is also used for retries/idempotency. If unspecified, the service may create an operation-id (typically a GUID) and return it via the `operation-id` and `operation-location` response headers; in this case, the service must figure out how to deal with retries/idempotency. +:white_check_mark: **DO** return a `202-Accepted` status code from the request that initiates an LRO if the processing of the operation was successfully initiated (except for "PUT with additional processing" type LRO). - - For an idempotent POST (same `operation-id` or same request body within some short time window), the service should return the same response as shown above. +:warning: **YOU SHOULD NOT** return any other `2xx` status code from the initial request of an LRO -- return `202-Accepted` and a status monitor even if processing was completed before the initiating request returns. - - For a non-idempotent POST, the service can treat the POST operation as idempotent (if performed within a short time window) or can treat the POST operation as initiating a brand new LRO action operation. +:white_check_mark: **DO** return a status monitor in the response body as described in [Obtaining status and results of long-running operations](#obtaining-status-and-results-of-long-running-operations). + +#### LRO action with no related resource pattern :white_check_mark: **DO** use the following pattern when implementing an LRO action not related to a specific resource (such as a batch operation):

``` @@ -969,10 +1001,13 @@ retry-after: (if status not terminal) - The response body is the status monitor resource whose schema must be idential to the request's body. -- The `operation-id` URL segment (not header) is *mandatory* forcing the client to specify the status monitor's resource ID and is also used for retries/idempotency. +- The `operation-id` URL segment (not header) is *mandatory* forcing the client to specify the status monitor's resource ID and is also used for retries/idempotency. + +#### The Status Monitor Resource -## The Status Monitor Resource -All patterns that initiate a LRO either implicitly or explicitly create a [Status Monitor resource](https://datatracker.ietf.org/doc/html/rfc7231#section-6.3.3) in the service's `operations` collection. A Status Monitor resource must look like this: +All patterns that initiate a LRO either implicitly or explicitly create a [Status Monitor resource](https://datatracker.ietf.org/doc/html/rfc7231#section-6.3.3) in the service's `operations` collection. + +:white_check_mark: **DO** return a status monitor in the response body that conforms with the following structure: Property | Type | Required | Description -------- | ----------- | :------: | ----------- @@ -985,27 +1020,39 @@ additional
properties | | | Additional named or dynamic properties of the op - Because services can support different kinds of operations, status monitor resources in this collection *must be* polymorphic; the `kind` property indicates the kind of long-running operation. -## Pattern to Poll a Long-Running Operation's Status +#### Obtaining status and results of long-running operations + +:white_check_mark: **DO** use the following pattern to allow clients to poll the current state of a Status Monitor resource: -:white_check_mark: **DO** use the following pattern to allow clients to poll the current state of a Status Monitor resource:

``` GET /operations/ ``` -The response must look like this:

+The response must look like this: + ``` 200 OK retry-after: (if status not terminal) ``` -:ballot_box_with_check: **YOU SHOULD** allow any valid value of the `api-version` query parameter to be used in the GET operation on the status monitor. +:white_check_mark: **DO** support the GET method on the status monitor endpoint that returns a `200-OK` response with the current state of the status monitor. + +:ballot_box_with_check: **YOU SHOULD** allow any valid value of the `api-version` query parameter to be used in the GET operation on the status monitor. - Note: Clients may replace the value of `api-version` in the `operation-location` URL with a value appropriate for their application. Remember that the client initiating the LRO may not be the same client polling the LRO's status. +:white_check_mark: **DO** include the `id` of the operation and any other values needed for the client to form a GET request to the status monitor (e.g. a `location` path parameter). + +:white_check_mark: **DO** include the `result` property (if any) in the status monitor for a POST action-type long-running operation when the operation completes successfully. + +:no_entry: **DO NOT** include a `result` property in the status monitor for a long-running operation that is not an action-type long-running operation. + +:white_check_mark: **DO** include a `retry-after` header in the response if the operation is not complete. The value of this header should be an integer number of seconds that the client should wait before polling the status monitor again. + :white_check_mark: **DO** retain the status monitor resource for some publicly documented period of time (at least 24 hours) after the operation completes. -## Pattern to List Status Monitors (optional) +#### Pattern to List Status Monitors (optional) :white_check_mark: **DO** use the following pattern to allow clients to list Status Monitor resources:

``` @@ -1024,8 +1071,8 @@ The response must look like this:

"nextLink": "{opaqueUrl}" } ``` - - The values for the `kind` and `status` query parameters are logically OR'd together. - + - The values for the `kind` and `status` query parameters are logically OR'd together. + - The above example returns all status monitor resources whose `kind` is either "VMInitializing" *or* "VMRebooting" and whose status is "NotStarted" *or* "Succeeded". From fc4193da7065968bb015619b0f2db94e01d713f7 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Wed, 3 Apr 2024 16:32:03 -0500 Subject: [PATCH 03/10] Address more PR review feedback --- azure/ConsiderationsForServiceDesign.md | 28 +++-- azure/Guidelines.md | 131 +++++++++++++----------- 2 files changed, 89 insertions(+), 70 deletions(-) diff --git a/azure/ConsiderationsForServiceDesign.md b/azure/ConsiderationsForServiceDesign.md index fe422be5..eacab316 100644 --- a/azure/ConsiderationsForServiceDesign.md +++ b/azure/ConsiderationsForServiceDesign.md @@ -208,7 +208,7 @@ It is good practice to define the path for action operations that is easily dist 2) use a special character not in the set of valid characters for resource names to distinguish the "action" in the path. In Azure we recommend distinguishing action operations by appending a ':' followed by an action verb to the final path segment. E.g. -```http +```text https://...//:? ``` @@ -238,7 +238,7 @@ The following sections describe these patterns in detail. ### Create or replace a resource requiring additional long-running processing -A special case of long-running operation that occurs often is a PUT operation to create or replace a resource +A special case of long-running operations that occurs often is a PUT operation to create or replace a resource that involves some additional long-running processing. One example is a resource that requires physical resources (e.g. servers) to be "provisioned" to make the resource functional. @@ -247,7 +247,7 @@ In this case: - The URL identifies resource being created or replaced. - The request and response body have identical schemas & represent the resource. - The request may contain an `Operation-Id` header that the service will use as -the ID of the status monitor created for the operation. + the ID of the status monitor created for the operation. ```text PUT /items/FooBar&api-version=2022-05-01 @@ -352,7 +352,7 @@ If the status is `Failed`, the status monitor resource contains an `error` field 6. There may be some cases where a long-running DELETE operation can be completed before the response to the initial request. In these cases, the operation should still return a `202 Accepted` with the `status` property set to the appropriate terminal state. -7. The service is responsible for purging the status-monitor resource. +7. The service is responsible for purging the status monitor resource. It should auto-purge the status monitor resource after completion (at least 24 hours). The service may offer DELETE of the status monitor resource due to GDPR/privacy. @@ -450,7 +450,7 @@ If the status is `Succeeded`, the operation results will be returned in the `res 6. There may be some cases where a long-running action operation can be completed before the response to the initial request. In these cases, the operation should still return a `202 Accepted` with the `status` property set to the appropriate terminal state. -7. The service is responsible for purging the status-monitor resource. +7. The service is responsible for purging the status monitor resource. It should auto-purge the status monitor resource after completion (at least 24 hours). The service may offer DELETE of the status monitor resource due to GDPR/privacy. @@ -459,22 +459,30 @@ The service may offer DELETE of the status monitor resource due to GDPR/privacy. When an long-running action operation is not related to a specific resource (a batch operation is one example), another approach is needed. -A long-running action operation not related to a resource should use a PUT operation for a resource that combines a status monitor with the request and results of the operation. In this pattern, clients obtain the status of the operation by issuing a GET on the same URL as the PUT operation. +This type of LRO should be initiated with a PUT method on a URL that represents the operation to be performed, +and includes a final path parameter for the user-specified operation ID. +The response of the PUT includes a response body containing a representation of the status monitor for the operation +and an `Operation-Location` response header that contains the absolute URL of the status monitor. +In this type of LRO, the status monitor should include any information from the request used to initiate the operation, +so that a failed operation could be reissued if necessary. + +Clients will use a GET on the status monitor URL to obtain the status and results of the operation. +For this type of LRO, the status monitor URL will often be the same URL as the PUT operation. The following examples illustrate this pattern. ```text PUT /translate-operations/ - + ``` Note that the client specifies the operation id in the URL path. A successful response to the PUT operation should have a `201 Created` status and response body -of the same structure as the request body, possibly with some additional output-only fields. +that contains a representation of the status monitor _and_ ny information from the request used to initiate the operation. -The service is responsible for purging the combined status-monitor/request/response resource. +The service is responsible for purging the status monitor after some period of time. It should auto-purge this resource after completion (at least 24 hours). The service may offer DELETE of the status monitor resource due to GDPR/privacy. @@ -484,7 +492,7 @@ It might be necessary to support some control action on a long-running operation This is implemented as a POST on the status monitor endpoint with `:` added. ```text -POST /:cancel?api-version=2022-05-01 +POST /:cancel?api-version=2022-05-01 ``` A successful response to a control operation should be a `200 OK` with a representation of the status monitor. diff --git a/azure/Guidelines.md b/azure/Guidelines.md index 66ba5c1c..a3f1d047 100644 --- a/azure/Guidelines.md +++ b/azure/Guidelines.md @@ -1,7 +1,7 @@ # Microsoft Azure REST API Guidelines - + -:white_check_mark: **DO** use the following pattern when implementing an LRO action operating on an existing resource:

-``` -POST /UrlToExistingResource: +:white_check_mark: **DO** use the following pattern when implementing an LRO action operating on an existing resource: + +```text +POST /UrlToExistingResource:?api-version= operation-id: ` + ``` -The response must look like this:

-``` +The response must look like this: + +```text 202 Accepted operation-id: operation-location: https://operations/ -retry-after: (if status not terminal) + ``` @@ -982,26 +986,41 @@ For a non-idempotent POST, the service can treat the POST operation as idempoten #### LRO action with no related resource pattern -:white_check_mark: **DO** use the following pattern when implementing an LRO action not related to a specific resource (such as a batch operation):

-``` -PUT /operations/ - -``` +:white_check_mark: **DO** use the following pattern when implementing an LRO action not related to a specific resource (such as a batch operation): -The response must look like this:

+```text +PUT / + +> ``` -200 OK -retry-after: (if status not terminal) + +The response must look like this: + +```text +201 Created +operation-location: + ``` -- This operation *explicitly* creates a status monitor resource as passed in the request body. +:ballot_box_with_check: **YOU SHOULD** +define a unique operation endpoint for each LRO action with no related resource. + +:white_check_mark: **DO** require the +`Operation-Id` as the final path segment in the URL. + +Note: The `operation-id` URL segment (not header) is *required*, forcing the client to specify the status monitor's resource ID +and is also used for retries/idempotency. - - The request's `kind` property must be set by the client to some value pre-defined by the service; for example `batchDocumentTranslate`. +:white_check_mark: **DO** return a `201 Created` status code +with an `operation-location` response header if the LRO Action operation was accepted for processing. -- The response body is the status monitor resource whose schema must be idential to the request's body. +:white_check_mark: **DO** return a +status monitor in the response body that contains the operation status, request parameters, and when the operation completes either +the operation result or error. -- The `operation-id` URL segment (not header) is *mandatory* forcing the client to specify the status monitor's resource ID and is also used for retries/idempotency. +Note: Since all request parameters must be present in the status monitor, +the request and response body of the PUT can be defined with a single schema. #### The Status Monitor Resource @@ -1012,27 +1031,29 @@ All patterns that initiate a LRO either implicitly or explicitly create a [Statu Property | Type | Required | Description -------- | ----------- | :------: | ----------- `id` | string | true | The unique id of the operation -`kind` | string enum | true | The kind of operation +`kind` | string enum | true(*) | The kind of operation `status` | string enum | true | The operation's current status: "NotStarted", "Running", "Succeeded", "Failed", and "Canceled" `error` | ErrorDetail | | If `status`=="Failed", contains reason for failure -`result` | object | | if Action LRO (POST or PUT) && `status`=="Succeeded", contains success result +`result` | object | | If `status`=="Succeeded" && Action LRO (POST or PUT), contains success result if needed additional
properties | | | Additional named or dynamic properties of the operation -- Because services can support different kinds of operations, status monitor resources in this collection *must be* polymorphic; the `kind` property indicates the kind of long-running operation. +(*): When a status monitor endpoint supports multiple operations with different result structures or additional properties, +the status monitor *must be* polymorphic -- it **must** contain a `kind` property that indicates the kind of long-running operation. #### Obtaining status and results of long-running operations :white_check_mark: **DO** use the following pattern to allow clients to poll the current state of a Status Monitor resource: -``` -GET /operations/ +```text +GET /operations/?api-version= ``` The response must look like this: -``` +```text 200 OK retry-after: (if status not terminal) + ``` @@ -1040,7 +1061,7 @@ retry-after: (if status not terminal) :ballot_box_with_check: **YOU SHOULD** allow any valid value of the `api-version` query parameter to be used in the GET operation on the status monitor. - - Note: Clients may replace the value of `api-version` in the `operation-location` URL with a value appropriate for their application. Remember that the client initiating the LRO may not be the same client polling the LRO's status. +- Note: Clients may replace the value of `api-version` in the `operation-location` URL with a value appropriate for their application. Remember that the client initiating the LRO may not be the same client polling the LRO's status. :white_check_mark: **DO** include the `id` of the operation and any other values needed for the client to form a GET request to the status monitor (e.g. a `location` path parameter). @@ -1052,28 +1073,18 @@ retry-after: (if status not terminal) :white_check_mark: **DO** retain the status monitor resource for some publicly documented period of time (at least 24 hours) after the operation completes. -#### Pattern to List Status Monitors (optional) +#### Pattern to List Status Monitors -:white_check_mark: **DO** use the following pattern to allow clients to list Status Monitor resources:

-``` -GET /operations?kind=VMInitializing,VMRebooting&status=NotStarted,Succeeded -``` +Use the following patterns to allow clients to list Status Monitor resources. -The response must look like this:

-```200 OK -{ - "value": [ - { "id": "12345", "kind": "VMInitializing", "status": "Running", … }, - { … }, - { … }, - { "id": "abcde", "kind": "VMRebooting", "status": "Failed", … } - ], - "nextLink": "{opaqueUrl}" -} -``` - - The values for the `kind` and `status` query parameters are logically OR'd together. +:heavy_check_mark: +**YOU MAY** support a GET method on any status monitor collection URL that returns a list of the status monitors in that collection. + +:ballot_box_with_check: +**YOU SHOULD** support a list operation for any status monitor collection that includes status monitors for LRO Actions with no related resource. - - The above example returns all status monitor resources whose `kind` is either "VMInitializing" *or* "VMRebooting" and whose status is "NotStarted" *or* "Succeeded". +:ballot_box_with_check: +**YOU SHOULD** support the `filter` query parameter on the list operation for any polymorphic status monitor collection and support filtering on the `kind` value of the status monitor. ### Bring your own Storage (BYOS) @@ -1086,7 +1097,7 @@ While Azure Managed Storage may be easier to get started with, as your service e :white_check_mark: **DO** use the Bring Your Own Storage pattern. -:white_check_mark: **DO** use a blob prefix for a logical folder (avoid terms such as ```directory```, ```folder```, or ```path```). +:white_check_mark: **DO** use a blob prefix for a logical folder (avoid terms such as `directory`, `folder`, or `path`). :no_entry: **DO NOT** require a fresh container per operation. From 0b5e4ea747eabf16faa1768b7789f38b1dfbd282 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Fri, 5 Apr 2024 10:50:25 -0500 Subject: [PATCH 04/10] More fixes --- azure/ConsiderationsForServiceDesign.md | 10 ++++++---- azure/Guidelines.md | 17 ++++++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/azure/ConsiderationsForServiceDesign.md b/azure/ConsiderationsForServiceDesign.md index eacab316..fb20971b 100644 --- a/azure/ConsiderationsForServiceDesign.md +++ b/azure/ConsiderationsForServiceDesign.md @@ -247,7 +247,7 @@ In this case: - The URL identifies resource being created or replaced. - The request and response body have identical schemas & represent the resource. - The request may contain an `Operation-Id` header that the service will use as - the ID of the status monitor created for the operation. +the ID of the status monitor created for the operation. ```text PUT /items/FooBar&api-version=2022-05-01 @@ -362,8 +362,8 @@ An action operation that is also long-running combines the [Action Operations](# with the [Long Running Operations](#long-running-operations) pattern. The operation is initiated with a POST operation and the operation path ends in `:`. -A long-running POST should not be used for resource create -- use PUT as described above. -PATCH must never be used for long-running operations -- it should be reserved for simple resource updates. +A long-running POST should not be used for resource create: use PUT as described above. +PATCH must never be used for long-running operations: it should be reserved for simple resource updates. If a long-running update is required it should be implemented with POST. ```text @@ -466,8 +466,10 @@ and an `Operation-Location` response header that contains the absolute URL of th In this type of LRO, the status monitor should include any information from the request used to initiate the operation, so that a failed operation could be reissued if necessary. +Since the HTTP semantic for PUT is to create a resource, a subsequent GET on the URL to initiate the LRO +should return the same response as the PUT: the status monitor for the operation. Clients will use a GET on the status monitor URL to obtain the status and results of the operation. -For this type of LRO, the status monitor URL will often be the same URL as the PUT operation. +So ror this type of LRO, the status monitor URL should be the same URL as the PUT operation. The following examples illustrate this pattern. diff --git a/azure/Guidelines.md b/azure/Guidelines.md index a3f1d047..e50592ce 100644 --- a/azure/Guidelines.md +++ b/azure/Guidelines.md @@ -861,7 +861,7 @@ LROs are always started by 1 logical client and may be polled (have their status :white_check_mark: **DO** perform as much validation as practical when initiating an LRO operation to alert clients of errors early. -:white_check_make: **DO** include an `operation-location` response header with the absolute URL of the status monitor for the operation. +:white_check_mark: **DO** include an `operation-location` response header with the absolute URL of the status monitor for the operation. :ballot_box_with_check: **YOU SHOULD** include the `api-version` query parameter in the `operation-location` response header with the same version passed on the initial request but expect a client to change the `api-version` value to whatever a new/different client desires it to be. @@ -903,7 +903,7 @@ If the `Operation-Id` header is not specified, the service may create an operati :white_check_mark: **DO** generate an ID (typically a GUID) for the status monitor if the `Operation-Id` header was not passed by the client. -:white_check_mark: **DO** fail a request with a `400-BadRequest` if the `Operation-Id` header that matches an existing operation unless the request is identical to the prior request (a retry scenario). +:white_check_mark: **DO** fail a request with a `400-BadRequest` if the `Operation-Id` header matches an existing operation unless the request is identical to the prior request (a retry scenario). :white_check_mark: **DO** perform as much validation as practical when initiating the operation to alert clients of errors early. @@ -1022,6 +1022,10 @@ the operation result or error. Note: Since all request parameters must be present in the status monitor, the request and response body of the PUT can be defined with a single schema. +:ballot_box_with_check: **YOU SHOULD** +return the status monitor for an operation for a subsequent GET on the URL that initiates the LRO, and use this endpoint as +the status monitor URL returned in the `operation-location` response header. + #### The Status Monitor Resource All patterns that initiate a LRO either implicitly or explicitly create a [Status Monitor resource](https://datatracker.ietf.org/doc/html/rfc7231#section-6.3.3) in the service's `operations` collection. @@ -1038,7 +1042,7 @@ Property | Type | Required | Description additional
properties | | | Additional named or dynamic properties of the operation (*): When a status monitor endpoint supports multiple operations with different result structures or additional properties, -the status monitor *must be* polymorphic -- it **must** contain a `kind` property that indicates the kind of long-running operation. +the status monitor **must** be polymorphic -- it **must** contain a `kind` property that indicates the kind of long-running operation. #### Obtaining status and results of long-running operations @@ -1086,6 +1090,13 @@ Use the following patterns to allow clients to list Status Monitor resources. :ballot_box_with_check: **YOU SHOULD** support the `filter` query parameter on the list operation for any polymorphic status monitor collection and support filtering on the `kind` value of the status monitor. +For example, the following request should returns all status monitor resources whose `kind` is either "VMInitializing" *or* "VMRebooting" +and whose status is "NotStarted" *or* "Succeeded". + +```text +GET /operations?filter=kind eq 'VMInitializing' or kind eq 'VMRebooting'&filter=status eq 'NotStarted' or status eq 'Succeeded' +``` + ### Bring your own Storage (BYOS) From f247aade766018966dcb1e3e4fb6aed15ec82b56 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Sat, 6 Apr 2024 12:29:29 -0500 Subject: [PATCH 05/10] More updates for PR comments --- azure/ConsiderationsForServiceDesign.md | 14 ++++++++++---- azure/Guidelines.md | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/azure/ConsiderationsForServiceDesign.md b/azure/ConsiderationsForServiceDesign.md index fb20971b..f223c88e 100644 --- a/azure/ConsiderationsForServiceDesign.md +++ b/azure/ConsiderationsForServiceDesign.md @@ -248,6 +248,9 @@ In this case: - The request and response body have identical schemas & represent the resource. - The request may contain an `Operation-Id` header that the service will use as the ID of the status monitor created for the operation. +- If the `Operation-Id` matches an existing operation and the request content is the same, +treat as a retry and return the same response as the earlier request. +Otherwise fail the request with a `400-BadRequest`. ```text PUT /items/FooBar&api-version=2022-05-01 @@ -261,9 +264,11 @@ Operation-Id: 22 In this case the response to the initial request is a `201 Created` to indicate that the resource has been created or `200 OK` when the resource was replaced. +The response body should be a representation of the resource that was created, +and should include a `status` field to indicate whether the additional processing has completed. A status monitor is created to track the additional processing and the ID of the status monitor is returned in the `Operation-Id` header of the response. -The response may also include an `Operation-Location` header for backward compatibility. +The response must also include an `Operation-Location` header for backward compatibility. If the resource supports ETags, the response may contain an `etag` header and possibly an `etag` property in the resource. ```text @@ -274,9 +279,10 @@ etag: "123abc" { "id": "FooBar", - "etag": "123abc", + "status": "Provisioning", "prop1": 555, - "prop2": "something" + "prop2": "something", + "etag": "123abc" } ``` @@ -334,7 +340,7 @@ Otherwise the service responds with a `202-Accepted` HTTP status code. The response body is the status monitor for the operation including the ID, either from the request header or generated by the service. When returning a status monitor whose status is not in a terminal state, the response must also include a `retry-after` header indicating the minimum number of seconds the client should wait before polling (GETing) the status monitor URL again for an update. -For backward compatibility, the response may also include an `Operation-Location` header containing the absolute URL +For backward compatibility, the response must also include an `Operation-Location` header containing the absolute URL of the status monitor resource (without an api-version query parameter). 3. After waiting at least the amount of time specified by the previous response's `Retry-after` header, diff --git a/azure/Guidelines.md b/azure/Guidelines.md index e50592ce..aaaac936 100644 --- a/azure/Guidelines.md +++ b/azure/Guidelines.md @@ -1090,7 +1090,7 @@ Use the following patterns to allow clients to list Status Monitor resources. :ballot_box_with_check: **YOU SHOULD** support the `filter` query parameter on the list operation for any polymorphic status monitor collection and support filtering on the `kind` value of the status monitor. -For example, the following request should returns all status monitor resources whose `kind` is either "VMInitializing" *or* "VMRebooting" +For example, the following request should return all status monitor resources whose `kind` is either "VMInitializing" *or* "VMRebooting" and whose status is "NotStarted" *or* "Succeeded". ```text From 8f9e59163afd5c2ab404e22b5f6e42a97ceda7e4 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Sun, 14 Apr 2024 14:07:34 -0500 Subject: [PATCH 06/10] Apply suggestions from PR review Co-authored-by: Jeffrey Richter --- azure/ConsiderationsForServiceDesign.md | 19 +++++++++---------- azure/Guidelines.md | 8 ++++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/azure/ConsiderationsForServiceDesign.md b/azure/ConsiderationsForServiceDesign.md index f223c88e..405ffbef 100644 --- a/azure/ConsiderationsForServiceDesign.md +++ b/azure/ConsiderationsForServiceDesign.md @@ -244,7 +244,7 @@ One example is a resource that requires physical resources (e.g. servers) to be In this case: - The operation must use the PUT method (NOTE: PATCH is never allowed here) -- The URL identifies resource being created or replaced. +- The URL identifies the resource being created or replaced. - The request and response body have identical schemas & represent the resource. - The request may contain an `Operation-Id` header that the service will use as the ID of the status monitor created for the operation. @@ -265,7 +265,7 @@ Operation-Id: 22 In this case the response to the initial request is a `201 Created` to indicate that the resource has been created or `200 OK` when the resource was replaced. The response body should be a representation of the resource that was created, -and should include a `status` field to indicate whether the additional processing has completed. +and should include a `status` field indicating the current status of the resource. A status monitor is created to track the additional processing and the ID of the status monitor is returned in the `Operation-Id` header of the response. The response must also include an `Operation-Location` header for backward compatibility. @@ -292,7 +292,7 @@ The client will issue a GET to the status monitor to obtain the status of the op GET https://items/operations/22?api-version=2022-05-01 ``` -When the additional processing completes, the status monitor will indicate if it succeeded or failed. +When the additional processing completes, the status monitor indicates if it succeeded or failed. ```text HTTP/1.1 200 OK @@ -308,12 +308,11 @@ but should clearly document this behavior. ### Long-running delete operation -A long-running delete operation follows the general pattern of a long-running operation -- -it returns a `202 Accepted` with a status monitor which the client uses to determine the outcome of the delete. +A long-running delete operation returns a `202 Accepted` with a status monitor which the client uses to determine the outcome of the delete. The resource being deleted should remain visible (returned from a GET) until the delete operation completes successfully. -When the delete operation completes successfully, a client must be able to create a new resource with same name without conflicts. +When the delete operation completes successfully, a client must be able to create a new resource with the same name without conflicts. This diagram illustrates how a long-running DELETE operation is initiated and then how the client determines it has completed and obtains its results: @@ -451,7 +450,7 @@ If the operation is still being processed, the status field will contain a "non- 5. After the operation processing completes, a GET request to the status monitor returns the status monitor with a status field set to a terminal value -- `Succeeded`, `Failed`, or `Canceled` -- that indicates the result of the operation. If the status is `Failed`, the status monitor resource contains an `error` field with a `code` and `message` that describes the failure. -If the status is `Succeeded`, the operation results will be returned in the `result` field of the status monitor. +If the status is `Succeeded`, the operation results (if any) are returned in the `result` field of the status monitor. 6. There may be some cases where a long-running action operation can be completed before the response to the initial request. In these cases, the operation should still return a `202 Accepted` with the `status` property set to the appropriate terminal state. @@ -462,7 +461,7 @@ The service may offer DELETE of the status monitor resource due to GDPR/privacy. ### Long-running action operation not related to a resource -When an long-running action operation is not related to a specific resource (a batch operation is one example), +When a long-running action operation is not related to a specific resource (a batch operation is one example), another approach is needed. This type of LRO should be initiated with a PUT method on a URL that represents the operation to be performed, @@ -475,7 +474,7 @@ so that a failed operation could be reissued if necessary. Since the HTTP semantic for PUT is to create a resource, a subsequent GET on the URL to initiate the LRO should return the same response as the PUT: the status monitor for the operation. Clients will use a GET on the status monitor URL to obtain the status and results of the operation. -So ror this type of LRO, the status monitor URL should be the same URL as the PUT operation. +So for this type of LRO, the status monitor URL should be the same URL as the PUT operation. The following examples illustrate this pattern. @@ -488,7 +487,7 @@ PUT /translate-operations/ Note that the client specifies the operation id in the URL path. A successful response to the PUT operation should have a `201 Created` status and response body -that contains a representation of the status monitor _and_ ny information from the request used to initiate the operation. +that contains a representation of the status monitor _and_ any information from the request used to initiate the operation. The service is responsible for purging the status monitor after some period of time. It should auto-purge this resource after completion (at least 24 hours). diff --git a/azure/Guidelines.md b/azure/Guidelines.md index aaaac936..65b441d2 100644 --- a/azure/Guidelines.md +++ b/azure/Guidelines.md @@ -913,7 +913,7 @@ If the `Operation-Id` header is not specified, the service may create an operati :ballot_box_with_check: **YOU SHOULD** include an `Operation-Location` header in the response with the absolute URL of the status monitor for the operation. -:ballot_box_with_check: **YOU SHOULD** include the `api-version` query parameter in the `Operation-Location` header with the same version passed on the initial request if it is required by the get operation on the status monitor. +:ballot_box_with_check: **YOU SHOULD** include the `api-version` query parameter in the `Operation-Location` header with the same version passed on the initial request. #### DELETE LRO pattern @@ -948,10 +948,10 @@ Consistent with non-LRO DELETE operations, if a request body is specified, retur :white_check_mark: **DO** use the following pattern when implementing an LRO action operating on an existing resource: ```text -POST /UrlToExistingResource:?api-version= +POST /UrlToExistingResource:?api-version=& operation-id: ` - + ``` The response must look like this: @@ -1094,7 +1094,7 @@ For example, the following request should return all status monitor resources wh and whose status is "NotStarted" *or* "Succeeded". ```text -GET /operations?filter=kind eq 'VMInitializing' or kind eq 'VMRebooting'&filter=status eq 'NotStarted' or status eq 'Succeeded' +GET /operations?filter=(kind eq 'VMInitializing' or kind eq 'VMRebooting') and (status eq 'NotStarted' or status eq 'Succeeded') ``` From ee199b3ddea0a6939cf1cf01ed995a4ab60651ee Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Sun, 14 Apr 2024 14:12:15 -0500 Subject: [PATCH 07/10] A few more small fixes --- azure/ConsiderationsForServiceDesign.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure/ConsiderationsForServiceDesign.md b/azure/ConsiderationsForServiceDesign.md index 405ffbef..3d4d3d19 100644 --- a/azure/ConsiderationsForServiceDesign.md +++ b/azure/ConsiderationsForServiceDesign.md @@ -340,7 +340,7 @@ The response body is the status monitor for the operation including the ID, eith When returning a status monitor whose status is not in a terminal state, the response must also include a `retry-after` header indicating the minimum number of seconds the client should wait before polling (GETing) the status monitor URL again for an update. For backward compatibility, the response must also include an `Operation-Location` header containing the absolute URL -of the status monitor resource (without an api-version query parameter). +of the status monitor resource, including an api-version query parameter. 3. After waiting at least the amount of time specified by the previous response's `Retry-after` header, the client issues a GET request to the status monitor using the ID in the body of the initial response. @@ -437,7 +437,7 @@ The response body is the status monitor for the operation including the ID, eith When returning a status monitor whose status is not in a terminal state, the response must also include a `retry-after` header indicating the minimum number of seconds the client should wait before polling (GETing) the status monitor URL again for an update. For backward compatibility, the response may also include an `Operation-Location` header containing the absolute URL -of the status monitor resource (without an api-version query parameter). +of the status monitor resource, including an api-version query parameter. 3. After waiting at least the amount of time specified by the previous response's `Retry-after` header, the client issues a GET request to the status monitor using the ID in the body of the initial response. From 188ec8130845a640289ec8d4b96491a73aa3af4a Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 22 Apr 2024 11:04:30 -0500 Subject: [PATCH 08/10] Another round of 'final' fixes --- azure/ConsiderationsForServiceDesign.md | 8 ++++---- azure/Guidelines.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/azure/ConsiderationsForServiceDesign.md b/azure/ConsiderationsForServiceDesign.md index 3d4d3d19..3c308279 100644 --- a/azure/ConsiderationsForServiceDesign.md +++ b/azure/ConsiderationsForServiceDesign.md @@ -250,7 +250,7 @@ In this case: the ID of the status monitor created for the operation. - If the `Operation-Id` matches an existing operation and the request content is the same, treat as a retry and return the same response as the earlier request. -Otherwise fail the request with a `400-BadRequest`. +Otherwise fail the request with a `409-Conflict`. ```text PUT /items/FooBar&api-version=2022-05-01 @@ -471,10 +471,10 @@ and an `Operation-Location` response header that contains the absolute URL of th In this type of LRO, the status monitor should include any information from the request used to initiate the operation, so that a failed operation could be reissued if necessary. -Since the HTTP semantic for PUT is to create a resource, a subsequent GET on the URL to initiate the LRO -should return the same response as the PUT: the status monitor for the operation. Clients will use a GET on the status monitor URL to obtain the status and results of the operation. -So for this type of LRO, the status monitor URL should be the same URL as the PUT operation. +Since the HTTP semantic for PUT is to create a resource, the same schema should be used for the PUT request body, +the PUT response body, and the response body of the GET for the status monitor for the operation. +For this type of LRO, the status monitor URL should be the same URL as the PUT operation. The following examples illustrate this pattern. diff --git a/azure/Guidelines.md b/azure/Guidelines.md index 65b441d2..c9e27082 100644 --- a/azure/Guidelines.md +++ b/azure/Guidelines.md @@ -903,7 +903,7 @@ If the `Operation-Id` header is not specified, the service may create an operati :white_check_mark: **DO** generate an ID (typically a GUID) for the status monitor if the `Operation-Id` header was not passed by the client. -:white_check_mark: **DO** fail a request with a `400-BadRequest` if the `Operation-Id` header matches an existing operation unless the request is identical to the prior request (a retry scenario). +:white_check_mark: **DO** fail a request with a `409-Conflict` if the `Operation-Id` header matches an existing operation unless the request is identical to the prior request (a retry scenario). :white_check_mark: **DO** perform as much validation as practical when initiating the operation to alert clients of errors early. @@ -976,7 +976,7 @@ For a non-idempotent POST, the service can treat the POST operation as idempoten :white_check_mark: **DO** generate an ID (typically a GUID) for the status monitor if the `Operation-Id` header was not passed by the client. -:white_check_mark: **DO** fail a request with a `400-BadRequest` if the `Operation-Id` header matches an existing operation unless the request is identical to the prior request (a retry scenario). +:white_check_mark: **DO** fail a request with a `409-Conflict` if the `Operation-Id` header matches an existing operation unless the request is identical to the prior request (a retry scenario). :white_check_mark: **DO** return a `202-Accepted` status code from the request that initiates an LRO if the processing of the operation was successfully initiated (except for "PUT with additional processing" type LRO). From 9fb3343dc16ca7fd06c4c0be3accdc662de44c7b Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Tue, 30 Apr 2024 11:35:35 -0500 Subject: [PATCH 09/10] Apply suggestions from PR review Thanks @weidongxu-microsoft for all the great suggestions! Co-authored-by: Weidong Xu --- azure/ConsiderationsForServiceDesign.md | 6 +++--- azure/Guidelines.md | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/azure/ConsiderationsForServiceDesign.md b/azure/ConsiderationsForServiceDesign.md index 3c308279..c2d48501 100644 --- a/azure/ConsiderationsForServiceDesign.md +++ b/azure/ConsiderationsForServiceDesign.md @@ -479,7 +479,7 @@ For this type of LRO, the status monitor URL should be the same URL as the PUT o The following examples illustrate this pattern. ```text -PUT /translate-operations/ +PUT /translate-operations/?api-version=2022-05-01 ``` @@ -489,8 +489,8 @@ Note that the client specifies the operation id in the URL path. A successful response to the PUT operation should have a `201 Created` status and response body that contains a representation of the status monitor _and_ any information from the request used to initiate the operation. -The service is responsible for purging the status monitor after some period of time. -It should auto-purge this resource after completion (at least 24 hours). +The service is responsible for purging the status monitor after some period of time, +but no earlier than 24 hours after the completion of the operation. The service may offer DELETE of the status monitor resource due to GDPR/privacy. ### Controlling a long-running operation diff --git a/azure/Guidelines.md b/azure/Guidelines.md index c9e27082..171da1a5 100644 --- a/azure/Guidelines.md +++ b/azure/Guidelines.md @@ -849,7 +849,7 @@ https://github.com/microsoft/api-guidelines/blob/vNext/azure/Guidelines.md#perfo ### Long-Running Operations & Jobs -A _long-running operation (LRO)_ is typically an operation that should execute synchronously but due to services not wanting to maintain long-lived connections (>1 seconds) and load-balancer timeouts the operation must execute asynchronously. For this pattern, the client initiates the operation on the service and then the client repeatedly polls the service (via another API call) to track the operation's progress/completion. +A _long-running operation (LRO)_ is typically an operation that should execute synchronously, but due to services not wanting to maintain long-lived connections (>1 seconds) and load-balancer timeouts, the operation must execute asynchronously. For this pattern, the client initiates the operation on the service, and then the client repeatedly polls the service (via another API call) to track the operation's progress/completion. LROs are always started by 1 logical client and may be polled (have their status checked) by the same client, another client, or even multiple clients/browsers. An example would be a dashboard or portal that shows all the operations along with their status. See the [Long Running Operations section](./ConsiderationsForServiceDesign.md#long-running-operations) in Considerations for Service Design for an introduction to the design of long-running operations. @@ -882,9 +882,9 @@ operation-id: The response must look like this: ```text -200 OK +201 Created operation-id: -operation-location: https://operations/ +operation-location: https://operations/?api-version= ``` @@ -907,7 +907,7 @@ If the `Operation-Id` header is not specified, the service may create an operati :white_check_mark: **DO** perform as much validation as practical when initiating the operation to alert clients of errors early. -:white_check_mark: **DO** return a `201-Created` status code for create or `200-OK` for replace from the initial request with a representation of the resource if the resource was created successfully. +:white_check_mark: **DO** return a `201-Created` status code for create or `200-OK` for replace from the initial request with a representation of the resource, if the resource was created or replaced successfully. :white_check_mark: **DO** include an `Operation-Id` header in the response with the ID of the status monitor for the operation. @@ -978,7 +978,7 @@ For a non-idempotent POST, the service can treat the POST operation as idempoten :white_check_mark: **DO** fail a request with a `409-Conflict` if the `Operation-Id` header matches an existing operation unless the request is identical to the prior request (a retry scenario). -:white_check_mark: **DO** return a `202-Accepted` status code from the request that initiates an LRO if the processing of the operation was successfully initiated (except for "PUT with additional processing" type LRO). +:white_check_mark: **DO** return a `202-Accepted` status code from the request that initiates an LRO action on a resource if the processing of the operation was successfully initiated. :warning: **YOU SHOULD NOT** return any other `2xx` status code from the initial request of an LRO -- return `202-Accepted` and a status monitor even if processing was completed before the initiating request returns. @@ -989,7 +989,7 @@ For a non-idempotent POST, the service can treat the POST operation as idempoten :white_check_mark: **DO** use the following pattern when implementing an LRO action not related to a specific resource (such as a batch operation): ```text -PUT / +PUT /?api-version= > ``` @@ -1049,7 +1049,7 @@ the status monitor **must** be polymorphic -- it **must** contain a `kind` prope :white_check_mark: **DO** use the following pattern to allow clients to poll the current state of a Status Monitor resource: ```text -GET /operations/?api-version= +GET /?api-version= ``` The response must look like this: @@ -1081,7 +1081,7 @@ retry-after: (if status not terminal) Use the following patterns to allow clients to list Status Monitor resources. -:heavy_check_mark: +:ballot_box_with_check: **YOU MAY** support a GET method on any status monitor collection URL that returns a list of the status monitors in that collection. :ballot_box_with_check: From 0217356f7652814a7898d59216dba89263335f88 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 6 May 2024 08:11:40 -0500 Subject: [PATCH 10/10] One more fix --- azure/Guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/Guidelines.md b/azure/Guidelines.md index 171da1a5..8785ff89 100644 --- a/azure/Guidelines.md +++ b/azure/Guidelines.md @@ -1042,7 +1042,7 @@ Property | Type | Required | Description additional
properties | | | Additional named or dynamic properties of the operation (*): When a status monitor endpoint supports multiple operations with different result structures or additional properties, -the status monitor **must** be polymorphic -- it **must** contain a `kind` property that indicates the kind of long-running operation. +the status monitor **must** be polymorphic -- it **must** contain a required `kind` property that indicates the kind of long-running operation. #### Obtaining status and results of long-running operations