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 @@

Removed reference to obsolete version of GeoJSON 456 + +Section 18 +Allow common expressions in action payloads +341 + @@ -1960,18 +1965,44 @@

entity reference, as appropriate to the action. Stream typed parameter values are represented following the same rules as inlined stream properties.

-

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 @@

19.1 Batc

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

  1. A query request
  2. An atomicity group that contains the following requests: @@ -2020,45 +2051,45 @@

    19.1 Batc
  3. A second query request

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"
+    }
+  ]
+}
@@ -2066,113 +2097,113 @@

-

Example 53: a batch request that contains the following operations in the order listed:

+

Example 54: a batch request that contains the following operations in the order listed:

  • Insert a new entity (with id = 1)
  • Insert a second new entity (references request with id = 1)
-
POST /service/$batch HTTP/1.1
-Host: host
-OData-Version: 4.01
-Content-Type: application/json
-Content-Length: ###
-
-{
-  "requests": [
-    {
-      "id": "1",
-      "method": "post",
-      "url": "/service/Customers",
-      "body": <JSON representation of a new Customer entity>
-    },
-    {
-      "id": "2",
-      "dependsOn": [ "1" ]
-      "method": "post",
-      "url": "$1/Orders",
-      "body": <JSON representation of a new Order>
-    }
-  ]
-}
+
POST /service/$batch HTTP/1.1
+Host: host
+OData-Version: 4.01
+Content-Type: application/json
+Content-Length: ###
+
+{
+  "requests": [
+    {
+      "id": "1",
+      "method": "post",
+      "url": "/service/Customers",
+      "body": <JSON representation of a new Customer entity>
+    },
+    {
+      "id": "2",
+      "dependsOn": [ "1" ]
+      "method": "post",
+      "url": "$1/Orders",
+      "body": <JSON representation of a new Order>
+    }
+  ]
+}

19.3 Referencing an ETag

-

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:

  • Get an Employee (with id = 1)
  • Update the salary only if the employee has not changed
-
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
+      }
+    }
+  ]
+}

19.4 Referencing Response Body Values

-

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:

  • Get an employee (with Content-ID = 1)
  • Get all employees residing in the same building
-
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"
+      }
+    }
+  ]
+}
@@ -2197,38 +2228,38 @@

19.6 B

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>
+    }
+  ]
+}

@@ -2237,32 +2268,11 @@

A batch request that specifies the 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> - } - ] -}

+ "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.

+
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
+    }
+  ]
+}

@@ -2327,20 +2358,20 @@

single primitive or collection value, the annotations for the value appear next to the 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 }
+    }
+  ]
+}

20.1 Annotate a JSON Object

@@ -2381,25 +2412,25 @@

21.1 E

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": {}
+    }
+  }
+}

@@ -2413,10 +2444,10 @@

21.2
  • 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"}]}

    diff --git a/docs/odata-json-format/odata-json-format.md b/docs/odata-json-format/odata-json-format.md index 67c52ea7..bf9c673a 100644 --- a/docs/odata-json-format/odata-json-format.md +++ b/docs/odata-json-format/odata-json-format.md @@ -217,8 +217,9 @@ Section | Feature / Change | Issue --------|------------------|------ [Section 4.5.1](#ControlInformationcontextodatacontext)| Fragment portion of Context URL is not percent-encoded| [368](https://github.com/oasis-tcs/odata-specs/issues/368) [Section 4.5.8](#ControlInformationidodataid)| Transient entities can be identifiable| [1928](https://github.com/oasis-tcs/odata-specs/issues/1928) -[Section 4.5.12](#ControlInformationmediaodatamedia)| `mediaContentType` can be `null`| [536](https://github.com/oasis-tcs/odata-specs/issues/536) +[Section 4.5.12](#ControlInformationmediaodatamedia)| `mediaContentType` can be `null`| [536](https://github.com/oasis-tcs/odata-specs/issues/536) [Section 7](#StructuralProperty), [Section A.2](#InformativeReferences)| Removed reference to obsolete version of GeoJSON| [456](https://github.com/oasis-tcs/odata-specs/issues/456) +[Section 18](#ActionInvocation)| Allow common expressions in action payloads| [341](https://github.com/oasis-tcs/odata-specs/issues/341) ## 1.2 Glossary @@ -3052,6 +3053,49 @@ properties, or just the [entity reference](#EntityReference), as appropriate to the action. Stream typed parameter values are represented following the same rules as inlined [stream properties](#StreamProperty). +Alternatively, values of non-binding parameters MAY be specified as common expressions +[OData-URL, section 5.1.1](#ODataURL). In the case of a bound action +these MAY contain path expressions [OData-URL, section 5.1.1.15](#ODataURL), 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 +Example 51: An employee requests leave from their manager for the next two weeks: +```json +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`: +```json +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](#ODataProtocol). + Non-binding parameters that are nullable or annotated with the term [`Core.OptionalParameter`](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Core.V1.md#OptionalParameter) defined in [OData-VocCore](#ODataVocCore) MAY be omitted from the request body. @@ -3065,7 +3109,7 @@ parameter is equivalent to being annotated as optional with a default value of `null`. ::: example -Example 51: +Example 52: ```json { "param1": 42, @@ -3211,7 +3255,7 @@ The request object and the `headers` object MUST NOT contain name/value pairs wi This is in conformance with [RFC7493](#rfc7493). ::: example -Example 52: a batch request that contains +Example 53: a batch request that contains the following individual requests in the order listed 1. A query request @@ -3274,7 +3318,7 @@ contains a relative URL, clients MUST be able to resolve it relative to the request's URL even if that contains such a reference. ::: example -Example 53: a batch request that contains the following operations in +Example 54: a batch request that contains the following operations in the order listed: - Insert a new entity (with `id = 1`) @@ -3309,7 +3353,7 @@ Content-Length: ### ## 19.3 Referencing an ETag ::: example -Example 54: a batch request that contains the following operations in +Example 55: a batch request that contains the following operations in the order listed: - Get an Employee (with `id` = 1) @@ -3352,7 +3396,7 @@ Content-Length: ### ## 19.4 Referencing Response Body Values ::: example -Example 55: a batch request that contains the following operations in +Example 56: a batch request that contains the following operations in the order listed: - Get an employee (with `Content-ID = 1`) @@ -3483,7 +3527,7 @@ request. Especially: URLs in responses MUST NOT contain `$`-prefixed request identifiers. ::: example -Example 56: referencing the batch request [example 52](#batchRequest) above, assume all +Example 57: referencing the batch request [example 53](#batchRequest) above, assume all the requests except the final query request succeed. In this case the response would be ```json @@ -3541,7 +3585,7 @@ to the next link MAY result in a `202 Accepted` response with a `location` header pointing to a new status monitor resource. ::: example -Example 57: referencing the [example 52](#batchRequest) above again, assume that the +Example 58: referencing the [example 53](#batchRequest) 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: ```json @@ -3631,7 +3675,7 @@ asynchronously executed individual request with a `status` of individual status monitor resource, and optionally a `retry-after` header. ::: example -Example 58: the first individual request is processed asynchronously, +Example 59: the first individual request is processed asynchronously, the second synchronously, the batch itself is processed synchronously ```json HTTP/1.1 200 OK @@ -3694,7 +3738,7 @@ the annotations for the value appear next to the `value` property and are not prefixed with a property name. ::: example -Example 59: +Example 60: ```json { "@context": "http://host/service/$metadata#Customers", @@ -3804,7 +3848,7 @@ Error responses MAY contain [annotations](#InstanceAnnotations) in any of its JSON objects. ::: example -Example 60: +Example 61: ```json { "error": { @@ -3853,7 +3897,7 @@ header-appropriate way: [RFC8259](#rfc8259), section 7) ::: example -Example 61: note that this is one HTTP header line without any line +Example 62: note that this is one HTTP header line without any line breaks or optional whitespace ```json OData-error: {"code":"err123","message":"Unsupported diff --git a/odata-json-format/1 Introduction.md b/odata-json-format/1 Introduction.md index 06a8a5ef..cc539025 100644 --- a/odata-json-format/1 Introduction.md +++ b/odata-json-format/1 Introduction.md @@ -28,11 +28,14 @@ Fragment portion of Context URL is not percent-encoded| Transient entities can be identifiable| [1928](https://github.com/oasis-tcs/odata-specs/issues/1928) [Section ##ControlInformationmediaodatamedia]| - `mediaContentType` can be `null`| +`mediaContentType` can be `null`| [536](https://github.com/oasis-tcs/odata-specs/issues/536) [Section ##StructuralProperty], [Section ##InformativeReferences]| Removed reference to obsolete version of GeoJSON| [456](https://github.com/oasis-tcs/odata-specs/issues/456) +[Section ##ActionInvocation]| +Allow common expressions in action payloads| +[341](https://github.com/oasis-tcs/odata-specs/issues/341) ## ##subsec Glossary diff --git a/odata-json-format/16 Bound Function.md b/odata-json-format/16 Bound Function.md index 539bf4b8..71e455d6 100644 --- a/odata-json-format/16 Bound Function.md +++ b/odata-json-format/16 Bound Function.md @@ -234,6 +234,49 @@ properties, or just the [entity reference](#EntityReference), as appropriate to the action. Stream typed parameter values are represented following the same rules as inlined [stream properties](#StreamProperty). +Alternatively, values of non-binding parameters MAY be specified as common expressions +[OData-URL, section 5.1.1](#ODataURL). In the case of a bound action +these MAY contain path expressions [OData-URL, section 5.1.1.15](#ODataURL), 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 +Example ##ex: An employee requests leave from their manager for the next two weeks: +```json +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`: +```json +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](#ODataProtocol). + Non-binding parameters that are nullable or annotated with the term [`Core.OptionalParameter`](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Core.V1.md#OptionalParameter) defined in [OData-VocCore](#ODataVocCore) MAY be omitted from the request body.