skip to content

In an OData 4.01 JSON batch, how do atomicityGroup and dependsOn decide what runs together, in what order, and what fails?

level: seniorimportance: should knowfreq 9%

answer

  1. a generalised change set
  2. adjacent members, all or nothing
  3. no implicit order, only declared
  4. skipped dependents report 424

basics

~20 s

Requests sharing an atomicityGroup must be adjacent and succeed or fail together. dependsOn names earlier ids or groups that must succeed first; anything undeclared may run in any order or in parallel, and a dependent whose prerequisite failed gets 424.

solid answer

~50 s

OData 4.01 added a JSON batch: a `requests` array whose objects carry `id`, `method` and `url`, plus optional `atomicityGroup`, `dependsOn`, `if`, `headers` and `body`. An **atomicity group** generalises the multipart change set: requests with the same `atomicityGroup` value MUST be adjacent and MUST all succeed or all fail. **`dependsOn`** lists the ids or group names of *preceding* requests (no forward references), and a request that depends on a member of another group must list that group. The service MAY process requests in any order compatible with those dependencies, and requests without `dependsOn` may run in parallel, so array order alone guarantees nothing. If a prerequisite fails, the dependent is not executed and gets `424 Failed Dependency`, unless an `if` member sets a different condition. Responses come back in a `responses` array, possibly in any order, matched by `id`.

code

json · 14 lines
json
{
  "requests": [
    {"id": "1", "atomicityGroup": "order", "method": "post",
     "url": "Orders",
     "headers": {"content-type": "application/json"},
     "body": {"CustomerId": "C042", "Currency": "EUR"}},
    {"id": "2", "atomicityGroup": "order", "dependsOn": ["1"],
     "method": "post", "url": "$1/Items",
     "headers": {"content-type": "application/json"},
     "body": {"Sku": "TEA-250", "Quantity": 3}},
    {"id": "3", "dependsOn": ["order", "1"],
     "method": "get", "url": "$1/Items"}
  ]
}

go deeper

for a junior

Recall that OData 4.01 can send a batch as JSON, with a requests array whose objects carry id, method and url.

for a middle

Explain atomicityGroup as the JSON form of a change set and dependsOn as the only ordering the service must honour.

for a senior

Show you would declare every real dependency, list groups rather than members, and handle 424 for skipped work, since the service may parallelise everything undeclared.

for a principal

Weigh how much orchestration logic to push into batch dependencies and if expressions against a server-side action that owns the whole workflow.

## Why OData 4.01 added a JSON batch OData 4.0 defined only the multipart batch format, which the OASIS "What's New in OData 4.01" document calls somewhat hard to implement. OData 4.01 added a **JSON batch format** so that clients can compose batch requests and read batch responses with ordinary JSON libraries. The batch is still a `POST` to `$batch`, now with `Content-Type: application/json`. The body is one JSON object that MUST contain `requests` and MAY contain annotations; an individual request MUST NOT itself be a batch. The JSON format also allows richer dependencies than change sets ever could. ## The request object | Member | Required | Meaning | |---|---|---| | `id` | yes | the request identifier: unique in the batch and unlike every `atomicityGroup` value; it plays the role of the multipart `Content-ID` | | `method` | yes | one of the literals `delete`, `get`, `patch`, `post`, `put`, matched case-insensitively | | `url` | yes | an absolute path appended to the batch URL's scheme, host and port, or a relative path resolved against the batch URL; a first segment `$<id>` is replaced by the URL of the entity that request created or returned | | `atomicityGroup` | no | a label shared by requests that must succeed or fail together | | `dependsOn` | no | an array of `id` or `atomicityGroup` values of *preceding* request objects | | `if` | no | a Boolean URL expression that replaces the default run-only-on-success condition | | `headers` | no | an object of request headers, each name in lower case | | `body` | no | JSON for `application/json`, a string for `text/*`, base64url for anything else; never on `get` or `delete` | ## Atomicity groups An atomicity group is the JSON format's generalisation of the multipart change set. - All request objects with the same `atomicityGroup` value MUST be **adjacent** in the `requests` array. - Their requests are one change unit: the service MUST apply all of them or none. How it undoes partial work is up to the service implementation. - If any response within a group returns a failure code, every request in that group is considered failed, whatever its own status; the service MAY return `424 Failed Dependency` for the members that failed or were never attempted because of it. - A group's name follows the same syntax rule as request identifiers and MUST NOT equal any `id` in the batch. ## Dependencies and ordering The multipart format makes the service process top-level parts in the order received. The JSON format does not. The service MAY process requests and atomicity groups in **any order compatible with `dependsOn`**, and requests and groups that declare no `dependsOn` may be processed **in parallel**. Array position promises nothing. 1. **Declare what must happen first.** `dependsOn` lists the ids or group names of preceding request objects; forward references are not allowed. 2. **Name the group, not just the member.** If a request depends on a request that belongs to a different atomicity group, that group MUST be listed in `dependsOn`. 3. **Declare what you reference.** A request whose `url` starts with `$<id>` MUST list that `id` in `dependsOn`. 4. **Expect 424 for skipped work.** Without `if`, a dependent runs only if everything it depends on returned `2xx`. Otherwise it is not executed, and its response carries `424 Failed Dependency`. 5. **Use `if` for other conditions.** Its expression may use `$<id>/$succeeded`, `$<id>` for a response body or `$<id>/<path>` for part of one; services SHOULD advertise it with `RequestDependencyConditionsSupported` in the Capabilities `BatchSupport` annotation. A service that does not support request dependencies MUST fail the dependent request with `424`, and if that request sits in an atomicity group, the whole group fails with `424` and nothing applied. ## The response - The body is an object with a `responses` array, again with no context control information. - Each response object MUST contain `id` and `status`, MAY contain `headers` (lower-case names) and `body`, and echoes `atomicityGroup` when its request had one. - Response objects MAY appear **in any order**, so clients correlate by `id`. - A response MAY be partial, ending with `nextLink`, while the service keeps processing. - URLs in responses MUST NOT contain `$`-prefixed identifiers. ## Common misreadings - Assuming array order is execution order, so a closing `GET` reads data before the writes it was meant to see. - Leaving the group out of `dependsOn` and naming only one of its members. - Expecting `412 Precondition Failed` for a skipped dependent instead of `424`. - Scattering a group's members across the array.

  • How does the if member change dependency handling in an OData 4.01 JSON batch?
    Without `if`, a dependent runs only when every request it depends on returned `2xx`. The `if` member replaces that default with a Boolean URL expression that may use `$<id>/$succeeded`, `$<id>` for a response body or `$<id>/<path>` for part of one. Services SHOULD advertise support with `RequestDependencyConditionsSupported` in the Capabilities `BatchSupport` annotation.
  • How can an OData client tell whether a service accepts JSON batch requests at all?
    The Capabilities vocabulary's `BatchSupport` term on the entity container has a `SupportedFormats` property whose allowed values are `multipart/mixed` and `application/json`. A service that lists only `multipart/mixed` expects the 4.0-style format; a client should read that annotation before switching formats.

saying these in an interview costs you the question

  • JSON batch requests execute top to bottom, exactly like the multipart format.
  • dependsOn may point forward to a request later in the array.
  • A request skipped because its prerequisite failed reports 412 Precondition Failed.
  • Members of one atomicity group may be scattered through the requests array.
  • JSON batch responses come back in request order, so match them by position.