diff --git a/docs/odata-json-format/odata-json-format.html b/docs/odata-json-format/odata-json-format.html index 1ef20a2c..63b87fa3 100644 --- a/docs/odata-json-format/odata-json-format.html +++ b/docs/odata-json-format/odata-json-format.html @@ -348,6 +348,11 @@
Non-binding parameters that are nullable or annotated with the term Core.OptionalParameter
defined in OData-VocCore MAY be omitted from the request body. If an omitted parameter is not annotated (and thus nullable), it MUST be interpreted as having the null
value. If it is annotated and the annotation specifies a DefaultValue
, the omitted parameter is interpreted as having that default value. If omitted and the annotation does not specify a default value, the service is free on how to interpret the omitted parameter. Note: a nullable non-binding parameter is equivalent to being annotated as optional with a default value of null
.
Alternatively, values of non-binding parameters MAY be specified as common expressions OData-URL, section 5.1.1. In the case of a bound action these MAY contain path expressions OData-URL, section 5.1.1.15, which the service evaluates on the binding parameter value. Such parameters are encoded as name/value pairs where the name is the name of the parameter followed by @expression
and the value is the common expression. As the following example demonstrates, non-transient entities can be passed as non-binding action parameters through a resource path in this way.
Example 51:
-{
-"param1": 42,
- "param2": {
- "Street": "One Microsoft Way",
- "Zip": 98052
- },
- "param3": [ 1, 42, 99 ],
- "param4": null
+ Example 51: An employee requests leave from their manager for the next two weeks:
+POST /service/Employees(23)/self.RequestLeave
+Host: host
+Content-Type: application/json
+
+{
+"StartDate@expression": "now()",
+ "EndDate@expression": "now() add duration'P14D'",
+ "Approver@expression": "Manager"
}
+The expression Manager
is evaluated on the binding parameter value Employees(23)
.
+When invoking an unbound action through an action import, expressions involving paths must start with $root
:
+POST /service/RequestLeave
+Host: host
+Content-Type: application/json
+
+{
+"Requester@expression": "$root/services/Employee(23)",
+ "StartDate@expression": "now()",
+ "EndDate@expression": "now() add duration'P14D'",
+ "Approver@expression": "$root/services/Employee(23)/Manager"
+ }
+
Inside a batch request the common expressions can also be value references starting with $
, as introduced in OData-Protocol, section 11.7.6.
Non-binding parameters that are nullable or annotated with the term Core.OptionalParameter
defined in OData-VocCore MAY be omitted from the request body. If an omitted parameter is not annotated (and thus nullable), it MUST be interpreted as having the null
value. If it is annotated and the annotation specifies a DefaultValue
, the omitted parameter is interpreted as having that default value. If omitted and the annotation does not specify a default value, the service is free on how to interpret the omitted parameter. Note: a nullable non-binding parameter is equivalent to being annotated as optional with a default value of null
.
Example 52:
+{
+"param1": 42,
+ "param2": {
+ "Street": "One Microsoft Way",
+ "Zip": 98052
+ },
+ "param3": [ 1, 42, 99 ],
+ "param4": null
+ }
In order to invoke an action with no non-binding parameters, the client passes an empty JSON object in the body of the request. 4.01 Services MUST also support clients passing an empty request body for this case.
@@ -2009,7 +2040,7 @@A body
MUST NOT be specified if the method
is get
or delete
.
The request object and the headers
object MUST NOT contain name/value pairs with duplicate names. This is in conformance with RFC7493.
Example 52: a batch request that contains the following individual requests in the order listed
+Example 53: a batch request that contains the following individual requests in the order listed
Note: For brevity, in the example, request bodies are excluded in favor of English descriptions inside <>
brackets and OData-Version
headers are omitted.
POST /service/$batch HTTP/1.1
-Host: host
-OData-Version: 4.01
-Content-Type: application/json
-Content-Length: ###
-
-{
-"requests": [
- {
- "id": "0",
- "method": "get",
- "url": "/service/Customers('ALFKI')"
- },
- {
- "id": "1",
- "atomicityGroup": "group1",
- "dependsOn": [ "0" ],
- "method": "patch",
- "url": "/service/Customers('ALFKI')",
- "headers": {
- "Prefer": "return=minimal"
- },
- "body": <JSON representation of changes to Customer ALFKI>
- },
- {
- "id": "2",
- "atomicityGroup": "group1",
- "method": "post",
- "url": "/service/Customers",
- "body": <JSON representation of a new Customer entity>
- },
- {
- "id": "3",
- "dependsOn": [ "group1" ],
- "method": "get",
- "url": "/service/Products"
- }
- ]
- }
POST /service/$batch HTTP/1.1
+Host: host
+OData-Version: 4.01
+Content-Type: application/json
+Content-Length: ###
+
+{
+"requests": [
+ {
+ "id": "0",
+ "method": "get",
+ "url": "/service/Customers('ALFKI')"
+ },
+ {
+ "id": "1",
+ "atomicityGroup": "group1",
+ "dependsOn": [ "0" ],
+ "method": "patch",
+ "url": "/service/Customers('ALFKI')",
+ "headers": {
+ "Prefer": "return=minimal"
+ },
+ "body": <JSON representation of changes to Customer ALFKI>
+ },
+ {
+ "id": "2",
+ "atomicityGroup": "group1",
+ "method": "post",
+ "url": "/service/Customers",
+ "body": <JSON representation of a new Customer entity>
+ },
+ {
+ "id": "3",
+ "dependsOn": [ "group1" ],
+ "method": "get",
+ "url": "/service/Products"
+ }
+ ]
+ }
Example 54: a batch request that contains the following operations in the order listed:
+Example 55: a batch request that contains the following operations in the order listed:
id
= 1)POST /service/$batch HTTP/1.1
-Host: host
-OData-Version: 4.01
-Content-Type: application/json
-Content-Length: ###
-
-{
-"requests": [
- {
- "id": "1",
- "method": "get",
- "url": "/service/Employees(0)",
- "headers": {
- "accept": "application/json"
- }
- },
- {
- "id": "2",
- "dependsOn": [ "1" ],
- "method": "patch",
- "url": "/service/Employees(0)",
- "headers": {
- "if-match": "$1"
- },
- "body": {
- "Salary": 75000
- }
- }
- ]
- }
POST /service/$batch HTTP/1.1
+Host: host
+OData-Version: 4.01
+Content-Type: application/json
+Content-Length: ###
+
+{
+"requests": [
+ {
+ "id": "1",
+ "method": "get",
+ "url": "/service/Employees(0)",
+ "headers": {
+ "accept": "application/json"
+ }
+ },
+ {
+ "id": "2",
+ "dependsOn": [ "1" ],
+ "method": "patch",
+ "url": "/service/Employees(0)",
+ "headers": {
+ "if-match": "$1"
+ },
+ "body": {
+ "Salary": 75000
+ }
+ }
+ ]
+ }
Example 55: a batch request that contains the following operations in the order listed:
+Example 56: a batch request that contains the following operations in the order listed:
Content-ID = 1
)POST /service/$batch HTTP/1.1
-Host: host
-OData-Version: 4.01
-Content-Type: application/json
-Content-Length: ###
-
-{
-"requests": [
- {
- "id": "1",
- "method": "get",
- "url": "/service/Employees/0?$select=Building",
- "headers": {
- "accept": "application/json"
- }
- },
- {
- "id": "2",
- "dependsOn": [ "1" ],
- "method": "get",
- "url": "/service/Employees?$filter=Building eq $1/Building",
- "headers": {
- "accept": "application/json"
- }
- }
- ]
- }
POST /service/$batch HTTP/1.1
+Host: host
+OData-Version: 4.01
+Content-Type: application/json
+Content-Length: ###
+
+{
+"requests": [
+ {
+ "id": "1",
+ "method": "get",
+ "url": "/service/Employees/0?$select=Building",
+ "headers": {
+ "accept": "application/json"
+ }
+ },
+ {
+ "id": "2",
+ "dependsOn": [ "1" ],
+ "method": "get",
+ "url": "/service/Employees?$filter=Building eq $1/Building",
+ "headers": {
+ "accept": "application/json"
+ }
+ }
+ ]
+ }
If the media type is not exactly equal to application/json
(i.e. it is a subtype or has format parameters), the headers
object MUST contain a name/value pair with the name content-type
whose value is the media type.
Relative URLs in a response object follow the rules for relative URLs based on the request URL of the corresponding request. Especially: URLs in responses MUST NOT contain $
-prefixed request identifiers.
Example 56: referencing the batch request example 52 above, assume all the requests except the final query request succeed. In this case the response would be
-HTTP/1.1 200 OK
-OData-Version: 4.01
-Content-Length: ####
-Content-Type: application/json
-
-{
-"responses": [
- {
- "id": "0",
- "status": 200,
- "body": <JSON representation of the Customer entity with key ALFKI>
- },
- {
- "id": "1",
- "status": 204
- },
- {
- "id": "2",
- "status": 201,
- "headers": {
- "location": "http://host/service.svc/Customer('POIUY')"
- },
- "body": <JSON representation of the new Customer entity>
- },
- {
- "id": "3",
- "status": 404,
- "body": <Error message>
- }
- ]
- }
Example 57: referencing the batch request example 53 above, assume all the requests except the final query request succeed. In this case the response would be
+HTTP/1.1 200 OK
+OData-Version: 4.01
+Content-Length: ####
+Content-Type: application/json
+
+{
+"responses": [
+ {
+ "id": "0",
+ "status": 200,
+ "body": <JSON representation of the Customer entity with key ALFKI>
+ },
+ {
+ "id": "1",
+ "status": 204
+ },
+ {
+ "id": "2",
+ "status": 201,
+ "headers": {
+ "location": "http://host/service.svc/Customer('POIUY')"
+ },
+ "body": <JSON representation of the new Customer entity>
+ },
+ {
+ "id": "3",
+ "status": 404,
+ "body": <Error message>
+ }
+ ]
+ }
respond-async
preference MAY be executed asynchronously. This means that the “outer” batch request is executed asynchronously; this preference does not automatically cascade down to the individual requests within the batch. After successful execution of the batch request the response to the batch request is returned in the body of a response to an interrogation request against the status monitor resource URL, see section “Asynchronous Requests” in OData-Protocol.
A service MAY return interim results to an asynchronously executing batch. It does this by responding with 200 OK
to a GET
request to the monitor resource and including a nextLink
control information in the JSON batch response, thus signaling that the response is only a partial result. A subsequent GET
request to the next link MAY result in a 202 Accepted
response with a location
header pointing to a new status monitor resource.
Example 57: referencing the example 52 above again, assume that the request is sent with the respond-async
preference. This results in a 202
response pointing to a status monitor resource:
HTTP/1.1 202 Accepted
-Location: http://service-root/async-monitor-0
-Retry-After: ###
When interrogating the monitor URL only the first request in the batch has finished processing and all the remaining requests are still being processed. The service signals that asynchronous processing is “finished” and returns a partial result with the first response and a next link. The client did not explicitly accept application/http
, so the response is “unwrapped” and only indicates with the AsyncResult
header that it is a response to a status monitor resource:
HTTP/1.1 200 OK
-AsyncResult: 200
-OData-Version: 4.01
-Content-Length: ###
-Content-Type: application/json
-
-{
-"responses": [
- {
- "id": "0",
- "status": 200,
- "body": <JSON representation of the Customer entity with key ALFKI>
- }
- ],
- "@nextLink": "…?$skiptoken=YmF0Y2gx"
- }
Client makes a GET
request to the next link and receives a 202
response with the location of a new monitor resource.
Example 58: referencing the example 53 above again, assume that the request is sent with the respond-async
preference. This results in a 202
response pointing to a status monitor resource:
HTTP/1.1 202 Accepted
-Location: http://service-root/async-monitor-1
+Location: http://service-root/async-monitor-0
Retry-After: ###
After some time a GET
request to the monitor resource returns the remainder of the result.
When interrogating the monitor URL only the first request in the batch has finished processing and all the remaining requests are still being processed. The service signals that asynchronous processing is “finished” and returns a partial result with the first response and a next link. The client did not explicitly accept application/http
, so the response is “unwrapped” and only indicates with the AsyncResult
header that it is a response to a status monitor resource:
HTTP/1.1 200 OK
AsyncResult: 200
OData-Version: 4.01
@@ -2272,48 +2282,69 @@ {
"responses": [
{
- "id": "1",
- "status": 204
- },
- {
- "id": "2",
- "status": 201,
- "headers": {
- "location": "http://host/service.svc/Customer('POIUY')"
- },
- "body": <JSON representation of the new Customer entity>
- },
- {
- "id": "3",
- "status": 404,
- "body": <Error message>
- }
- ]
- }
Client makes a GET
request to the next link and receives a 202
response with the location of a new monitor resource.
HTTP/1.1 202 Accepted
+Location: http://service-root/async-monitor-1
+Retry-After: ###
After some time a GET
request to the monitor resource returns the remainder of the result.
HTTP/1.1 200 OK
+AsyncResult: 200
+OData-Version: 4.01
+Content-Length: ###
+Content-Type: application/json
+
+{
+"responses": [
+ {
+ "id": "1",
+ "status": 204
+ },
+ {
+ "id": "2",
+ "status": 201,
+ "headers": {
+ "location": "http://host/service.svc/Customer('POIUY')"
+ },
+ "body": <JSON representation of the new Customer entity>
+ },
+ {
+ "id": "3",
+ "status": 404,
+ "body": <Error message>
+ }
+ ]
+ }
In addition to the above interaction pattern individual requests within a batch with no other requests depending on it and not part of an atomicity group MAY be executed asynchronously if they specify the respond-async
preference and if the service responds with a JSON batch response. In this case the response
array contains a response object for each asynchronously executed individual request with a status
of 202
, a location
header pointing to an individual status monitor resource, and optionally a retry-after
header.
Example 58: the first individual request is processed asynchronously, the second synchronously, the batch itself is processed synchronously
-HTTP/1.1 200 OK
-OData-Version: 4.01
-Content-Length: ###
-Content-Type: application/json
-
-{
-"responses": [
- {
- "id": "0",
- "status": 202,
- "headers": {
- "location": "http://service-root/async-monitor-0"
- }
- },
- {
- "id": "1",
- "status": 204
- }
- ]
- }
Example 59: the first individual request is processed asynchronously, the second synchronously, the batch itself is processed synchronously
+HTTP/1.1 200 OK
+OData-Version: 4.01
+Content-Length: ###
+Content-Type: application/json
+
+{
+"responses": [
+ {
+ "id": "0",
+ "status": 202,
+ "headers": {
+ "location": "http://service-root/async-monitor-0"
+ }
+ },
+ {
+ "id": "1",
+ "status": 204
+ }
+ ]
+ }
value
property and are not prefixed with a property name.
Example 59:
-{
-"@context": "http://host/service/$metadata#Customers",
- "@com.example.customer.setkind": "VIPs",
- "value": [
- {
- "@com.example.display.highlight": true,
- "ID": "ALFKI",
- "CompanyName@com.example.display.style": { "title": true, "order": 1 },
- "CompanyName": "Alfreds Futterkiste",
- "Orders@com.example.display.style#simple": { "order": 2 }
- }
- ]
- }
Example 60:
+{
+"@context": "http://host/service/$metadata#Customers",
+ "@com.example.customer.setkind": "VIPs",
+ "value": [
+ {
+ "@com.example.display.highlight": true,
+ "ID": "ALFKI",
+ "CompanyName@com.example.display.style": { "title": true, "order": 1 },
+ "CompanyName": "Alfreds Futterkiste",
+ "Orders@com.example.display.style#simple": { "order": 2 }
+ }
+ ]
+ }
Service implementations SHOULD carefully consider which information to include in production environments to guard against potential security concerns around information disclosure.
Error responses MAY contain annotations in any of its JSON objects.
Example 60:
-{
-"error": {
- "code": "err123",
- "message": "Unsupported functionality",
- "target": "query",
- "details": [
- {
- "code": "forty-two",
- "target": "$search",
- "message": "$search query option not supported"
- }
- ],
- "innererror": {
- "trace": […],
- "context": {…}
- }
- }
- }
Example 61:
+{
+"error": {
+ "code": "err123",
+ "message": "Unsupported functionality",
+ "target": "query",
+ "details": [
+ {
+ "code": "forty-two",
+ "target": "$search",
+ "message": "$search query option not supported"
+ }
+ ],
+ "innererror": {
+ "trace": […],
+ "context": {…}
+ }
+ }
+ }
Control characters (00
to 1F
and 7F
) and Unicode characters beyond 00FF
within JSON strings are encoded as \uXXXX
or \uXXXX\uXXXX
(see RFC8259, section 7)
Example 61: note that this is one HTTP header line without any line breaks or optional whitespace
-OData-error: {"code":"err123","message":"Unsupported
-functionality","target":"query","details":[{"code":"forty-two","target":"$search","message":"$search
-query option not supported"}]}
Example 62: note that this is one HTTP header line without any line breaks or optional whitespace
+OData-error: {"code":"err123","message":"Unsupported
+functionality","target":"query","details":[{"code":"forty-two","target":"$search","message":"$search
+query option not supported"}]}