# OCAPI Resource States

A resource state represents the server-side state of a specific resource, for example, a basket or a customer. It’s a string token, baked on all the resource property information.

OCAPI exposes resource state information via the *\_resource_state* property in the response payload (body). The response contains either a single resource state or multiple resource states in case calling collection or search resources. In case of body-less responses (for example, HEAD) the resource state is exposed via *x-dw-resource-state* response header.

## What Is It Used For?

Resource states provide an OPTIONAL mechanism to implement *Optimistic Locking* in your client. They can be used to prevent collisions between concurrent requests, for example, to overcome the "lost update" problem.

## Resource State vs. Etag

A strong Etag covers not only the server-side resource state itself, but also the whole HTTP response on bit level. Means, it covers also the fact that compression (for example, gzip) is used or not. In scenarios where proxies are in between this might lead to unforeseen behaviours. E.g in case the client doesn't request compression, but there’s compression between the proxy and the server: Some proxies append "-gzip" to the Etag value, others absorb the Etag completely.

:::note
OCAPI uses the term "resource_state" to clearly differentiate the concept from Etags. OCAPI isn’t supporting Etags anymore.
:::

## How Does It Work?

To use the resource state for optimistic locking you have to include the resource state from the last server response in your next state changing (DELETE, PATCH, POST, PUT) request. You should always prefer to use the *\_resource_state* property in the body. In case the requested API doesn't have a body use the *x-dw-resource-state* header. Whenever a resource state is part of a client's request, OCAPI verifies it by comparing the given value with the server resource state. If both resource states are equal the operation is executed, otherwise an HTTP 409 *ResourceStateConflictException* fault is returned. In case of a create request (for example, with PUT) where the resource isn’t expected to be existing (with *not_exists* state), the returned fault is an HTTP 409 *ResourceAlreadyExistsException* instead.

:::note
Whenever your application performs state changing (DELETE, PATCH, POST, PUT) operations and there’s a likelihood of concurrent requests, we recommend leveraging optimistic locking on base of resource states.
:::

## Samples

OCAPI exposes the resource state as *\_resource_state* property in response body and as *x-dw-resource-state* header.

```txt
# Create a new basket in the Shop API:
REQUEST:
POST /dw/shop/v24_5/baskets
Host: example.com
Authorization:Bearer eyJfdiI6IjXXXXXX.eyJfdiI6IjEiLCJleHAXXXXXXX.-d5wQW4c4O4wt-Zkl7_fiEiALW1XXXX
Content-Type: application/json

# in case of success, response contains new created basket with the resource state in response
# header and also as single property in response body
RESPONSE:
HTTP/1.1 200 OK
Content-Length:124
x-dw-resource-state:ba4e84383e1790597e49eeee34b201633d80ed3f499992f5af11d639dd903a36
Content-Type:application/json;charset=UTF-8
{
   "_resource_state" : "ba4e84383e1790597e49eeee34b201633d80ed3f499992f5af11d639dd903a36",
   ...
   "basket_id" : "bczFTaOjgEqUkaaadkvHwbgrP5",
   ...
}

# Search for stores in the Data API:
REQUEST:
POST /s/-/dw/data/v24_5/sites/SiteGenesis/store_search HTTP/1.1
Host: example.com
Authorization: Bearer a5b6eb0d-8312-41a3-88f3-2c53c4507367
...

# in case of success, response contains multiple resource states - one per search hit
RESPONSE:
HTTP/1.1 200 OK
{
   ...
   "hits" : [{
      "_resource_state" : "12ab34cd",
      "id" : ...
   },{
      "_resource_state" : "ef56gh78",
      "id" : ...
   }]
}

```

A resource state can be passed to any state changing method (DELETE, PATCH, POST, PUT). If no resource state is passed, the resource is overwritten, updated, or deleted without any further notice on base of the default HTTP method behavior. If a resource state is passed, it’s verified against the server resource state. If both states don’t match, a *ResourceStateConflictException* or *ResourceAlreadyExistsException* fault is responded. When the API user expects a resource not to exist (for example, during resource creation), the resource state **not_exists** can be passed. This prevents existing resources from being accidentally overwritten.

For every writing operation on a resource, a resource state token can be passed, but doesn’t have to. If no token is passed, the resource is overwritten, updated, or deleted without any further notice. If a resource state is passed, it’s checked against the server state of the resource. If both states don’t match, a *409* status code is retrieved. When the API user expects a resource not to exist, a resource state **not_exists** must be passed (for a create request).

```txt
# add an item to the basket, the resource state from the response header is given as x-dw-resource-state
# header ...
REQUEST:
POST /dw/shop/v24_5/baskets/bczFTaOjgEqUkaaadkvHwbgrP5/items?client_id=af123-456....
Host: example.com
Authorization:Bearer eyJfdiI6IjXXXXXX.eyJfdiI6IjEiLCJleHAXXXXXXX.-d5wQW4c4O4wt-Zkl7_fiEiALW1XXXX
x-dw-resource-state:ba4e84383e1790597e49eeee34b201633d80ed3f499992f5af11d639dd903a36
Content-Type: application/json
{
...
}

# ... or as _resource_state property in the body

# Add an item to the basket, send resource state via body

REQUEST:
POST /dw/shop/v24_5/baskets/bczFTaOjgEqUkaaadkvHwbgrP5/items
Host: example.com
Authorization: Bearer eyJfdiI6IjXXXXXX.eyJfdiI6IjEiLCJleHAXXXXXXX.-d5wQW4c4O4wt-Zkl7_fiEiALW1XXXX
Content-Type: application/json
{
   "_resource_state" : "ba4e84383e1790597e49eeee34b201633d80ed3f499992f5af11d639dd903a36"
   ...
}

# in case of success, the next response header contains a new resource state
RESPONSE:
HTTP/1.1 200 OK
Content-Length:124
x-dw-resource-state: ba4e84383e1790597e49eeee34b201633d80ed3f499992f5af11d639dd903a36
Content-Type:application/json;charset=UTF-8
{
   "_resource_state" : "ba4e84383e1790597e49eeee34b201633d80ed3f499992f5af11d639dd903a36"
   ...
   "basket_id" : "bczFTaOjgEqUkaaadkvHwbgrP5",
   ...
}

# Delete an item from the basket, resource state is send via header

REQUEST:
DELETE /dw/shop/v24_5/baskets/bczFTaOjgEqUkaaadkvHwbgrP5/items/te352d63gdh62hd6hd
Host: example.com
Authorization: Bearer eyJfdiI6IjXXXXXX.eyJfdiI6IjEiLCJleHAXXXXXXX.-d5wQW4c4O4wt-Zkl7_fiEiALW1XXXX
x-dw-resource-state: 100001
Content-Length: 0

# in case of creating a not existent customer

REQUEST:
PUT /s/-/dw/data/v24_5/customer_lists/4711/customers/0815 HTTP/1.1
Host: example.com
Authorization: Bearer a5b6eb0d-8312-41a3-88f3-2c53c4507367
Content-Type: application/json; charset=UTF-8
{
   "_resource_state" : "not_exists",
   "email" : "dude@salesforce.com",
   ...
}

# when a customer with that ID already exists

RESPONSE:
HTTP/1.1 409 CONFLICT
Content-Type: application/json;charset=UTF-8
{
  "_v" : "24.5",
   "_type" : "fault",
  "fault" : {
    "type" : "ResourceAlreadyExistsException",
    "message" : "Resource already exists, state is 'ab12cd34'."
  }
}

```
