You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: azure/ConsiderationsForServiceDesign.md
+5Lines changed: 5 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -91,6 +91,11 @@ An important consideration when defining a new service is support for pagination
91
91
92
92
:ballot_box_with_check:**YOU SHOULD** support server-side paging, even if your resource does not currently need paging. This avoids a breaking change when your service expands. See [Collections](./Guidelines.md#collections) for specific guidance.
93
93
94
+
Another consideration for collections is support for sorting the set of returned items with the _orderby_ query parameter.
95
+
Sorting collection results can be extremely expensive for a service to implement as it must retrieve all items to sort them. And if the operation supports paging (which is likely), then a client request to get another page may have to retrieve all items and sort them again to determine which items are on the desired page.
96
+
97
+
:heavy_check_mark:**YOU MAY** support _orderby_ if customer scenarios really demand it and the service is confident that it can support it in perpetuity (even if the backing storage service changes someday).
98
+
94
99
Another important design pattern for avoiding surprises is idempotency. An operation is idempotent if it can be performed multiple times and have the same result as a single execution.
95
100
HTTP requires certain operations like GET, PUT, and DELETE to be idempotent, but for cloud services it is important to make _all_ operations idempotent so that clients can use retry in failure scenarios without risk of unintended consequences.
96
101
See the [HTTP Request / Response Pattern section of the Guidelines](./Guidelines.md#http-request--response-pattern) for detailed guidance on making operations idempotent.
The HTTP Request / Response pattern dictates how your API behaves. For example: POST methods that create resources must be idempotent, GET method results may be cached, the If-Modified and etag headers offer optimistic concurrency. The URL of a service, along with its request/response bodies, establishes the overall contract that developers have with your service. As a service provider, how you manage the overall request / response pattern should be one of the first implementation decisions you make.
106
+
The HTTP Request / Response pattern dictates how your API behaves. For example: POST methods that create resources must be idempotent, GET method results may be cached, the If-Modified and ETag headers offer optimistic concurrency. The URL of a service, along with its request/response bodies, establishes the overall contract that developers have with your service. As a service provider, how you manage the overall request / response pattern should be one of the first implementation decisions you make.
107
107
108
108
Cloud applications embrace failure. Therefore, to enable customers to write fault-tolerant applications, <b>all</b> service operations (including POST) <b>must</b> be idempotent. Implementing services in an idempotent manner, with an "exactly once" semantic, enables developers to retry requests without the risk of unintended consequences.
109
109
@@ -138,7 +138,7 @@ DELETE | Remove the resource | 204-No Content\; avoid 404-Not Found
138
138
139
139
:white_check_mark:**DO** return a ```403-Forbidden``` when the user does not have access to the resource _unless_ this would leak information about the existence of the resource that should not be revealed for security/privacy reasons, in which case the response should be ```404-Not Found```. [Rationale: a ```403-Forbidden``` is easier to debug for customers, but should not be used if even admitting the existence of things could potentially leak customer secrets.]
140
140
141
-
:white_check_mark:**DO** support caching and optimistic concurrency by honoring the the if-match, if-none-match, if-modified-since, and if-unmodified-since request headers and by returning the etag and last-modified response headers
141
+
:white_check_mark:**DO** support caching and optimistic concurrency by honoring the the if-match, if-none-match, if-modified-since, and if-unmodified-since request headers and by returning the ETag and last-modified response headers
142
142
143
143
### HTTP Query Parameters and Header Values
144
144
Because information in the service URL, as well as the request / response, are strings, there must be a predictable, well-defined scheme to convert strings to their corresponding values.
@@ -177,7 +177,7 @@ date | Both | Sun, 06 Nov 1994 08:49:37 GMT (see [RFC7231,
177
177
*content-type* | Both | application/merge-patch+json
etag | Response | "67ab43" see [Conditional Requests](#Conditional-Requests)
180
+
ETag | Response | "67ab43" see [Conditional Requests](#Conditional-Requests)
181
181
last-modified | Response | Sun, 06 Nov 1994 08:49:37 GMT
182
182
*x-ms-error-code* | Response | see [Handling Errors](#Handling-Errors)
183
183
retry-after | Response | 180 (see [RFC 7231, Section 7.1.3](https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.3))
@@ -437,7 +437,7 @@ Note: To avoid potential collision of actions and resource ids, you should disal
437
437
}
438
438
```
439
439
440
-
:white_check_mark:**DO** include the id field and etag field (if supported) for each item as this allows the customer to modify the item in a future operation.
440
+
:white_check_mark:**DO** include the _id_ field and _etag_ field (if supported) for each item as this allows the customer to modify the item in a future operation.
441
441
442
442
:white_check_mark:**DO** clearly document that resources may be skipped or duplicated across pages of a paginated collection unless the operation has made special provisions to prevent this (like taking a time-expiring snapshot of the collection).
443
443
@@ -523,6 +523,8 @@ __Grouping Operators__ | |
523
523
| Conditional AND | and | Logical And |
524
524
| Conditional OR | or | Logical Or |
525
525
526
+
> :heavy_check_mark:**YOU MAY** support orderby and filter functions such as concat and contains. For more information, see [odata Canonical Functions](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#_Toc31360979).
527
+
526
528
##### Operator examples
527
529
The following examples illustrate the use and semantics of each of the logical operators.
528
530
@@ -809,9 +811,9 @@ For each of the "output" sections the following apply:
809
811
### Conditional Requests
810
812
When designing an API, you will almost certainly have to manage how your resource is updated. For example, if your resource is a bank account, you will want to ensure that one transaction--say depositing money--does not overwrite a previous transaction. Similarly, it could be very expensive to send a resource to a client. This could be because of its size, network conditions, or a myriad of other reasons. To enable this level of control, services should leverage an ```ETag``` header, or "entity tag," which will identify the 'version' or 'instance' of the resource a particular client is working with. An ```ETag``` is always set by the service and will enable you to *conditionally* control how your service responds to requests, enabling you to provide predictable updates and more efficient access.
811
813
812
-
:ballot_box_with_check:**YOU SHOULD** return an ```ETag``` with any operation returning the resource or part of a resource or any update of the resource (whether the resource is returned or not).
814
+
:ballot_box_with_check:**YOU SHOULD** return an ```ETag``` with any operation returning the resource or part of a resource or any update of the resource (whether the resource is returned or not).
813
815
814
-
:ballot_box_with_check:**YOU SHOULD** use ```etags``` consistently across your API, i.e. if you use an ```ETag```, accept it on all other operations.
816
+
:ballot_box_with_check:**YOU SHOULD** use ```ETag```s consistently across your API, i.e. if you use an ```ETag```, accept it on all other operations.
815
817
816
818
You can learn more about conditional requests by reading [RFC7232](https://datatracker.ietf.org/doc/html/rfc7232).
817
819
@@ -827,8 +829,8 @@ When supporting conditional read strategies:
|etag value = if-none-match value | 304 Not Modified | no additional information |
831
-
|etag value != if-none-match value | 200 OK | Response body include the serialized value of the resource (typically JSON) |
832
+
|ETag value = if-none-match value | 304 Not Modified | no additional information |
833
+
|ETag value != if-none-match value | 200 OK | Response body include the serialized value of the resource (typically JSON) |
832
834
833
835
For more control over caching, please refer to the ```cache-control```[HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control).
834
836
@@ -840,14 +842,14 @@ An ```ETag``` should also be used to reflect the create, update, and delete poli
840
842
When supporting optimistic concurrency:
841
843
:white_check_mark:**DO** adhere to the following table for guidance:
| PATCH / PUT | if-none-match | * | check for *any* version of the resource ('*' is a wildcard used to match anything), if none are found, create the resource. | 200 OK or </br> 201 Created </br> | Response header MUST include the new ```ETag``` value. Response body SHOULD include the serialized value of the resource (typically JSON). |
846
848
| PATCH / PUT | if-none-match | * | check for *any* version of the resource, if one is found, fail the operation | 412 Precondition Failed | Response body SHOULD return the serialized value of the resource (typically JSON) that was passed along with the request.|
847
-
| PATCH / PUT | if-match | value of etag| value of if-match equals the latest etag value on the server, confirming that the version of the resource is the most current | 200 OK or </br> 201 Created </br> | Response header MUST include the new ```ETag``` value. Response body SHOULD include the serialized value of the resource (typically JSON). |
848
-
| PATCH / PUT | if-match | value of etag| value of if-match header DOES NOT equal the latest etag value on the server, indicating a change has ocurred since after the client fetched the resource| 412 Precondition Failed | Response body SHOULD return the serialized value of the resource (typically JSON) that was passed along with the request.|
849
-
| DELETE | if-none-match | value of etag| value does NOT match the latest value on the server | 412 Preconditioned Failed | Response body SHOULD be empty.|
850
-
| DELETE | if-none-match | value of etag| value matches the latest value on the server | 204 No Content | Response body SHOULD be empty. |
849
+
| PATCH / PUT | if-match | value of ETag| value of if-match equals the latest ETag value on the server, confirming that the version of the resource is the most current | 200 OK or </br> 201 Created </br> | Response header MUST include the new ```ETag``` value. Response body SHOULD include the serialized value of the resource (typically JSON). |
850
+
| PATCH / PUT | if-match | value of ETag| value of if-match header DOES NOT equal the latest ETag value on the server, indicating a change has ocurred since after the client fetched the resource| 412 Precondition Failed | Response body SHOULD return the serialized value of the resource (typically JSON) that was passed along with the request.|
851
+
| DELETE | if-none-match | value of ETag| value does NOT match the latest value on the server | 412 Preconditioned Failed | Response body SHOULD be empty.|
852
+
| DELETE | if-none-match | value of ETag| value matches the latest value on the server | 204 No Content | Response body SHOULD be empty. |
851
853
852
854
#### Computing ETags
853
855
The strategy that you use to compute the ```ETag``` depends on its semantic. For example, it is natural, for resources that are inherently versioned, to use the version as the value of the ```ETag```. Another common strategy for determining the value of an ```ETag``` is to use a hash of the resource. If a resource is not versioned, and unless computing a hash is prohibitively expensive, this is the preferred mechanism.
0 commit comments