mirror of https://github.com/dapr/docs.git
709 lines
19 KiB
Markdown
709 lines
19 KiB
Markdown
---
|
|
type: docs
|
|
title: "State management API reference"
|
|
linkTitle: "State management API"
|
|
description: "Detailed documentation on the state management API"
|
|
weight: 400
|
|
---
|
|
|
|
## Component file
|
|
|
|
A Dapr `statestore.yaml` component file has the following structure:
|
|
|
|
```yaml
|
|
apiVersion: dapr.io/v1alpha1
|
|
kind: Component
|
|
metadata:
|
|
name: <NAME>
|
|
namespace: <NAMESPACE>
|
|
spec:
|
|
type: state.<TYPE>
|
|
version: v1
|
|
metadata:
|
|
- name:<KEY>
|
|
value:<VALUE>
|
|
- name: <KEY>
|
|
value: <VALUE>
|
|
```
|
|
|
|
| Setting | Description |
|
|
| ------- | ----------- |
|
|
| `metadata.name` | The name of the state store. |
|
|
| `spec/metadata` | An open key value pair metadata that allows a binding to define connection properties. |
|
|
|
|
## Key scheme
|
|
|
|
Dapr state stores are key/value stores. To ensure data compatibility, Dapr requires these data stores follow a fixed key scheme. For general states, the key format is:
|
|
|
|
```
|
|
<App ID>||<state key>
|
|
```
|
|
|
|
For Actor states, the key format is:
|
|
|
|
```
|
|
<App ID>||<Actor type>||<Actor id>||<state key>
|
|
```
|
|
|
|
## Save state
|
|
|
|
This endpoint lets you save an array of state objects.
|
|
|
|
### HTTP Request
|
|
|
|
```
|
|
POST http://localhost:<daprPort>/v1.0/state/<storename>
|
|
```
|
|
|
|
#### URL Parameters
|
|
|
|
Parameter | Description
|
|
--------- | -----------
|
|
`daprPort` | The Dapr port
|
|
`storename` | The `metadata.name` field in the user-configured `statestore.yaml` component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
|
|
|
|
The optional request metadata is passed via URL query parameters. For example,
|
|
```
|
|
POST http://localhost:3500/v1.0/state/myStore?metadata.contentType=application/json
|
|
```
|
|
> All URL parameters are case-sensitive.
|
|
|
|
> Since `||` is a reserved string it cannot be used in the `<state key>`
|
|
> field.
|
|
|
|
#### Request Body
|
|
|
|
A JSON array of state objects. Each state object is comprised with the following fields:
|
|
|
|
Field | Description
|
|
---- | -----------
|
|
`key` | State key
|
|
`value` | State value, which can be any byte array
|
|
`etag` | (optional) State ETag
|
|
`metadata` | (optional) Additional key-value pairs to be passed to the state store
|
|
`options` | (optional) State operation options; see [state operation options](#optional-behaviors)
|
|
|
|
> **ETag format:** Dapr runtime treats ETags as opaque strings. The exact ETag format is defined by the corresponding data store.
|
|
|
|
#### Metadata
|
|
|
|
Metadata can be sent via query parameters in the request's URL. It must be prefixed with `metadata.`, as shown below.
|
|
|
|
Parameter | Description
|
|
--------- | -----------
|
|
`metadata.ttlInSeconds` | The number of seconds for the message to expire, as [described here]({{< ref state-store-ttl.md >}})
|
|
|
|
> **TTL:** Only certain state stores support the TTL option, according the [supported state stores]({{< ref supported-state-stores.md >}}).
|
|
|
|
### HTTP Response
|
|
|
|
#### Response Codes
|
|
|
|
Code | Description
|
|
---- | -----------
|
|
`204` | State saved
|
|
`400` | State store is missing or misconfigured or malformed request
|
|
`500` | Failed to save state
|
|
|
|
#### Response Body
|
|
|
|
None.
|
|
|
|
### Example
|
|
|
|
```shell
|
|
curl -X POST http://localhost:3500/v1.0/state/starwars?metadata.contentType=application/json \
|
|
-H "Content-Type: application/json" \
|
|
-d '[
|
|
{
|
|
"key": "weapon",
|
|
"value": "DeathStar",
|
|
"etag": "1234"
|
|
},
|
|
{
|
|
"key": "planet",
|
|
"value": {
|
|
"name": "Tatooine"
|
|
}
|
|
}
|
|
]'
|
|
```
|
|
|
|
## Get state
|
|
|
|
This endpoint lets you get the state for a specific key.
|
|
|
|
### HTTP Request
|
|
|
|
```
|
|
GET http://localhost:<daprPort>/v1.0/state/<storename>/<key>
|
|
```
|
|
|
|
#### URL Parameters
|
|
|
|
Parameter | Description
|
|
--------- | -----------
|
|
`daprPort` | The Dapr port
|
|
`storename` | `metadata.name` field in the user-configured statestore.yaml component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
|
|
`key` | The key of the desired state
|
|
`consistency` | (optional) Read consistency mode; see [state operation options](#optional-behaviors)
|
|
`metadata` | (optional) Metadata as query parameters to the state store
|
|
|
|
The optional request metadata is passed via URL query parameters. For example,
|
|
```
|
|
GET http://localhost:3500/v1.0/state/myStore/myKey?metadata.contentType=application/json
|
|
```
|
|
|
|
> Note, all URL parameters are case-sensitive.
|
|
|
|
### HTTP Response
|
|
|
|
#### Response Codes
|
|
|
|
Code | Description
|
|
---- | -----------
|
|
`200` | Get state successful
|
|
`204` | Key is not found
|
|
`400` | State store is missing or misconfigured
|
|
`500` | Get state failed
|
|
|
|
#### Response Headers
|
|
|
|
Header | Description
|
|
--------- | -----------
|
|
`ETag` | ETag of returned value
|
|
|
|
#### Response Body
|
|
|
|
JSON-encoded value
|
|
|
|
### Example
|
|
|
|
```shell
|
|
curl http://localhost:3500/v1.0/state/starwars/planet?metadata.contentType=application/json
|
|
```
|
|
|
|
> The above command returns the state:
|
|
|
|
```json
|
|
{
|
|
"name": "Tatooine"
|
|
}
|
|
```
|
|
|
|
To pass metadata as query parameter:
|
|
|
|
```
|
|
GET http://localhost:3500/v1.0/state/starwars/planet?metadata.partitionKey=mypartitionKey&metadata.contentType=application/json
|
|
```
|
|
|
|
## Get bulk state
|
|
|
|
This endpoint lets you get a list of values for a given list of keys.
|
|
|
|
### HTTP Request
|
|
|
|
```
|
|
POST/PUT http://localhost:<daprPort>/v1.0/state/<storename>/bulk
|
|
```
|
|
|
|
#### URL Parameters
|
|
|
|
Parameter | Description
|
|
--------- | -----------
|
|
`daprPort` | The Dapr port
|
|
`storename` | `metadata.name` field in the user-configured statestore.yaml component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
|
|
`metadata` | (optional) Metadata as query parameters to the state store
|
|
|
|
The optional request metadata is passed via URL query parameters. For example,
|
|
```
|
|
POST/PUT http://localhost:3500/v1.0/state/myStore/bulk?metadata.partitionKey=mypartitionKey
|
|
```
|
|
|
|
> Note, all URL parameters are case-sensitive.
|
|
|
|
### HTTP Response
|
|
|
|
#### Response Codes
|
|
|
|
Code | Description
|
|
---- | -----------
|
|
`200` | Get state successful
|
|
`400` | State store is missing or misconfigured
|
|
`500` | Get bulk state failed
|
|
|
|
#### Response Body
|
|
|
|
An array of JSON-encoded values
|
|
|
|
### Example
|
|
|
|
```shell
|
|
curl http://localhost:3500/v1.0/state/myRedisStore/bulk \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"keys": [ "key1", "key2" ],
|
|
"parallelism": 10
|
|
}'
|
|
```
|
|
|
|
> The above command returns an array of key/value objects:
|
|
|
|
```json
|
|
[
|
|
{
|
|
"key": "key1",
|
|
"value": "value1",
|
|
"etag": "1"
|
|
},
|
|
{
|
|
"key": "key2",
|
|
"value": "value2",
|
|
"etag": "1"
|
|
}
|
|
]
|
|
```
|
|
|
|
To pass metadata as query parameter:
|
|
|
|
```
|
|
POST http://localhost:3500/v1.0/state/myRedisStore/bulk?metadata.partitionKey=mypartitionKey
|
|
```
|
|
|
|
## Delete state
|
|
|
|
This endpoint lets you delete the state for a specific key.
|
|
|
|
### HTTP Request
|
|
|
|
```
|
|
DELETE http://localhost:<daprPort>/v1.0/state/<storename>/<key>
|
|
```
|
|
|
|
#### URL Parameters
|
|
|
|
Parameter | Description
|
|
--------- | -----------
|
|
`daprPort` | The Dapr port
|
|
`storename` | `metadata.name` field in the user-configured statestore.yaml component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
|
|
`key` | The key of the desired state
|
|
`concurrency` | (optional) Either *first-write* or *last-write*; see [state operation options](#optional-behaviors)
|
|
`consistency` | (optional) Either *strong* or *eventual*; see [state operation options](#optional-behaviors)
|
|
|
|
The optional request metadata is passed via URL query parameters. For example,
|
|
```
|
|
DELETE http://localhost:3500/v1.0/state/myStore/myKey?metadata.contentType=application/json
|
|
```
|
|
|
|
> Note, all URL parameters are case-sensitive.
|
|
|
|
#### Request Headers
|
|
|
|
Header | Description
|
|
--------- | -----------
|
|
If-Match | (Optional) ETag associated with the key to be deleted
|
|
|
|
### HTTP Response
|
|
|
|
#### Response Codes
|
|
|
|
Code | Description
|
|
---- | -----------
|
|
`204` | Delete state successful
|
|
`400` | State store is missing or misconfigured
|
|
`500` | Delete state failed
|
|
|
|
#### Response Body
|
|
|
|
None.
|
|
|
|
### Example
|
|
|
|
```shell
|
|
curl -X DELETE http://localhost:3500/v1.0/state/starwars/planet -H "If-Match: xxxxxxx"
|
|
```
|
|
|
|
## Query state
|
|
|
|
This endpoint lets you query the key/value state.
|
|
|
|
{{% alert title="alpha" color="warning" %}}
|
|
This API is in alpha stage.
|
|
{{% /alert %}}
|
|
|
|
### HTTP Request
|
|
|
|
```
|
|
POST/PUT http://localhost:<daprPort>/v1.0-alpha1/state/<storename>/query
|
|
```
|
|
|
|
#### URL Parameters
|
|
|
|
Parameter | Description
|
|
--------- | -----------
|
|
`daprPort` | The Dapr port
|
|
`storename` | `metadata.name` field in the user-configured statestore.yaml component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
|
|
`metadata` | (optional) Metadata as query parameters to the state store
|
|
|
|
The optional request metadata is passed via URL query parameters. For example,
|
|
```
|
|
POST http://localhost:3500/v1.0-alpha1/state/myStore/query?metadata.contentType=application/json
|
|
```
|
|
|
|
> Note, all URL parameters are case-sensitive.
|
|
|
|
#### Response Codes
|
|
|
|
Code | Description
|
|
---- | -----------
|
|
`200` | State query successful
|
|
`400` | State store is missing or misconfigured
|
|
`500` | State query failed
|
|
|
|
#### Response Body
|
|
|
|
An array of JSON-encoded values
|
|
|
|
### Example
|
|
|
|
```shell
|
|
curl -X POST http://localhost:3500/v1.0-alpha1/state/myStore/query?metadata.contentType=application/json \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"filter": {
|
|
"OR": [
|
|
{
|
|
"EQ": { "person.org": "Dev Ops" }
|
|
},
|
|
{
|
|
"AND": [
|
|
{
|
|
"EQ": { "person.org": "Finance" }
|
|
},
|
|
{
|
|
"IN": { "state": [ "CA", "WA" ] }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"sort": [
|
|
{
|
|
"key": "state",
|
|
"order": "DESC"
|
|
},
|
|
{
|
|
"key": "person.id"
|
|
}
|
|
],
|
|
"page": {
|
|
"limit": 3
|
|
}
|
|
}'
|
|
```
|
|
|
|
> The above command returns an array of objects along with a token:
|
|
|
|
```json
|
|
{
|
|
"results": [
|
|
{
|
|
"key": "1",
|
|
"data": {
|
|
"person": {
|
|
"org": "Dev Ops",
|
|
"id": 1036
|
|
},
|
|
"city": "Seattle",
|
|
"state": "WA"
|
|
},
|
|
"etag": "6f54ad94-dfb9-46f0-a371-e42d550adb7d"
|
|
},
|
|
{
|
|
"key": "4",
|
|
"data": {
|
|
"person": {
|
|
"org": "Dev Ops",
|
|
"id": 1042
|
|
},
|
|
"city": "Spokane",
|
|
"state": "WA"
|
|
},
|
|
"etag": "7415707b-82ce-44d0-bf15-6dc6305af3b1"
|
|
},
|
|
{
|
|
"key": "10",
|
|
"data": {
|
|
"person": {
|
|
"org": "Dev Ops",
|
|
"id": 1054
|
|
},
|
|
"city": "New York",
|
|
"state": "NY"
|
|
},
|
|
"etag": "26bbba88-9461-48d1-8a35-db07c374e5aa"
|
|
}
|
|
],
|
|
"token": "3"
|
|
}
|
|
```
|
|
|
|
To pass metadata as query parameter:
|
|
|
|
```
|
|
POST http://localhost:3500/v1.0-alpha1/state/myStore/query?metadata.partitionKey=mypartitionKey
|
|
```
|
|
|
|
## State transactions
|
|
|
|
Persists the changes to the state store as a [transactional operation]({{< ref "state-management-overview.md#transactional-operations" >}}).
|
|
|
|
> This API depends on a state store component that supports transactions.
|
|
|
|
Refer to the [state store component spec]({{< ref "supported-state-stores.md" >}}) for a full, current list of state stores that support transactions.
|
|
|
|
#### HTTP Request
|
|
|
|
```
|
|
POST/PUT http://localhost:<daprPort>/v1.0/state/<storename>/transaction
|
|
```
|
|
|
|
#### HTTP Response Codes
|
|
|
|
Code | Description
|
|
---- | -----------
|
|
`204` | Request successful
|
|
`400` | State store is missing or misconfigured or malformed request
|
|
`500` | Request failed
|
|
|
|
#### URL Parameters
|
|
|
|
Parameter | Description
|
|
--------- | -----------
|
|
`daprPort` | The Dapr port
|
|
`storename` | `metadata.name` field in the user-configured statestore.yaml component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
|
|
|
|
The optional request metadata is passed via URL query parameters. For example,
|
|
```
|
|
POST http://localhost:3500/v1.0/state/myStore/transaction?metadata.contentType=application/json
|
|
```
|
|
|
|
> Note, all URL parameters are case-sensitive.
|
|
|
|
#### Request Body
|
|
|
|
Field | Description
|
|
---- | -----------
|
|
`operations` | A JSON array of state `operation`
|
|
`metadata` | (optional) The `metadata` for the transaction that applies to all operations
|
|
|
|
All transactional databases implement the following required operations:
|
|
|
|
Operation | Description
|
|
--------- | -----------
|
|
`upsert` | Adds or updates the value
|
|
`delete` | Deletes the value
|
|
|
|
Each operation has an associated `request` that is comprised of the following fields:
|
|
|
|
Request | Description
|
|
---- | -----------
|
|
`key` | State key
|
|
`value` | State value, which can be any byte array
|
|
`etag` | (optional) State ETag
|
|
`metadata` | (optional) Additional key-value pairs to be passed to the state store that apply for this operation
|
|
`options` | (optional) State operation options; see [state operation options](#optional-behaviors)
|
|
|
|
#### Examples
|
|
The example below shows an `upsert` operation for `key1` and a `delete` operation for `key2`. This is applied to the partition named 'planet' in the state store. Both operations either succeed or fail in the transaction.
|
|
|
|
```shell
|
|
curl -X POST http://localhost:3500/v1.0/state/starwars/transaction \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"operations": [
|
|
{
|
|
"operation": "upsert",
|
|
"request": {
|
|
"key": "key1",
|
|
"value": "myData"
|
|
}
|
|
},
|
|
{
|
|
"operation": "delete",
|
|
"request": {
|
|
"key": "key2"
|
|
}
|
|
}
|
|
],
|
|
"metadata": {
|
|
"partitionKey": "planet"
|
|
}
|
|
}'
|
|
```
|
|
|
|
## Configuring state store for actors
|
|
|
|
Actors don't support multiple state stores and require a transactional state store to be used with Dapr. [View which services currently implement the transactional state store interface]({{< ref "supported-state-stores.md" >}}).
|
|
|
|
Specify which state store to be used for actors with a `true` value for the property `actorStateStore` in the metadata section of the `statestore.yaml` component file.
|
|
For example, the following components yaml will configure Redis to be used as the state store for Actors.
|
|
|
|
```yaml
|
|
apiVersion: dapr.io/v1alpha1
|
|
kind: Component
|
|
metadata:
|
|
name: statestore
|
|
spec:
|
|
type: state.redis
|
|
version: v1
|
|
metadata:
|
|
- name: redisHost
|
|
value: <redis host>
|
|
- name: redisPassword
|
|
value: ""
|
|
- name: actorStateStore
|
|
value: "true"
|
|
|
|
```
|
|
|
|
## Optional behaviors
|
|
|
|
### Key scheme
|
|
|
|
A Dapr-compatible state store shall use the following key scheme:
|
|
|
|
* *\<App ID>||\<state key>* key format for general states
|
|
* *\<App ID>||\<Actor type>||\<Actor id>||\<state key>* key format for Actor states.
|
|
|
|
### Concurrency
|
|
|
|
Dapr uses Optimized Concurrency Control (OCC) with ETags. Dapr makes the following requirements optional on state stores:
|
|
|
|
* A Dapr-compatible state store may support optimistic concurrency control using ETags. The store allows the update when an ETag:
|
|
* Is associated with an *save* or *delete* request.
|
|
* Matches the latest ETag in the database.
|
|
* When ETag is missing in the write requests, the state store shall handle the requests in a *last-write-wins* fashion. This allows optimizations for high-throughput write scenarios, in which data contingency is low or has no negative effects.
|
|
* A store shall *always* return ETags when returning states to callers.
|
|
|
|
### Consistency
|
|
|
|
Dapr allows clients to attach a consistency hint to *get*, *set*, and *delete* operation. Dapr supports two consistency levels: **strong** and **eventual**.
|
|
|
|
#### Eventual Consistency
|
|
|
|
Dapr assumes data stores are eventually consistent by default. A state should:
|
|
|
|
* For *read* requests, return data from any of the replicas.
|
|
* For *write* requests, asynchronously replicate updates to configured quorum after acknowledging the update request.
|
|
|
|
#### Strong Consistency
|
|
|
|
When a strong consistency hint is attached, a state store should:
|
|
|
|
* For *read* requests, return the most up-to-date data consistently across replicas.
|
|
* For *write*/*delete* requests, synchronously replicate updated data to configured quorum before completing the write request.
|
|
|
|
### Example: Complete options request example
|
|
|
|
The following is an example *set* request with a complete `options` definition:
|
|
|
|
```shell
|
|
curl -X POST http://localhost:3500/v1.0/state/starwars \
|
|
-H "Content-Type: application/json" \
|
|
-d '[
|
|
{
|
|
"key": "weapon",
|
|
"value": "DeathStar",
|
|
"etag": "xxxxx",
|
|
"options": {
|
|
"concurrency": "first-write",
|
|
"consistency": "strong"
|
|
}
|
|
}
|
|
]'
|
|
```
|
|
|
|
### Example: Working with ETags
|
|
|
|
The following is an example walk-through of an ETag usage when *setting*/*deleting* an object in a compatible state store. This sample defines Redis as `statestore`.
|
|
|
|
1. Store an object in a state store:
|
|
|
|
```shell
|
|
curl -X POST http://localhost:3500/v1.0/state/statestore \
|
|
-H "Content-Type: application/json" \
|
|
-d '[
|
|
{
|
|
"key": "sampleData",
|
|
"value": "1"
|
|
}
|
|
]'
|
|
```
|
|
|
|
1. Get the object to find the ETag set automatically by the state store:
|
|
|
|
```shell
|
|
curl http://localhost:3500/v1.0/state/statestore/sampleData -v
|
|
* Connected to localhost (127.0.0.1) port 3500 (#0)
|
|
> GET /v1.0/state/statestore/sampleData HTTP/1.1
|
|
> Host: localhost:3500
|
|
> User-Agent: curl/7.64.1
|
|
> Accept: */*
|
|
>
|
|
< HTTP/1.1 200 OK
|
|
< Server: fasthttp
|
|
< Date: Sun, 14 Feb 2021 04:51:50 GMT
|
|
< Content-Type: application/json
|
|
< Content-Length: 3
|
|
< Etag: 1
|
|
< Traceparent: 00-3452582897d134dc9793a244025256b1-b58d8d773e4d661d-01
|
|
<
|
|
* Connection #0 to host localhost left intact
|
|
"1"* Closing connection 0
|
|
```
|
|
|
|
The returned ETag above was 1. If you send a new request to update or delete the data with the wrong ETag, it will return an error. Omitting the ETag will allow the request.
|
|
|
|
```shell
|
|
# Update
|
|
curl -X POST http://localhost:3500/v1.0/state/statestore \
|
|
-H "Content-Type: application/json" \
|
|
-d '[
|
|
{
|
|
"key": "sampleData",
|
|
"value": "2",
|
|
"etag": "2"
|
|
}
|
|
]'
|
|
{"errorCode":"ERR_STATE_SAVE","message":"failed saving state in state store statestore: possible etag mismatch. error from state store: ERR Error running script (call to f_83e03ec05d6a3b6fb48483accf5e594597b6058f): @user_script:1: user_script:1: failed to set key nodeapp||sampleData"}
|
|
|
|
# Delete
|
|
curl -X DELETE -H 'If-Match: 5' http://localhost:3500/v1.0/state/statestore/sampleData
|
|
{"errorCode":"ERR_STATE_DELETE","message":"failed deleting state with key sampleData: possible etag mismatch. error from state store: ERR Error running script (call to f_9b5da7354cb61e2ca9faff50f6c43b81c73c0b94): @user_script:1: user_script:1: failed to delete node
|
|
app||sampleData"}
|
|
```
|
|
|
|
1. Update or delete the object by simply matching the ETag in either the request body (update) or the `If-Match` header (delete). When the state is updated, it receives a new ETag that future updates or deletes will need to use.
|
|
|
|
```shell
|
|
# Update
|
|
curl -X POST http://localhost:3500/v1.0/state/statestore \
|
|
-H "Content-Type: application/json" \
|
|
-d '[
|
|
{
|
|
"key": "sampleData",
|
|
"value": "2",
|
|
"etag": "1"
|
|
}
|
|
]'
|
|
|
|
# Delete
|
|
curl -X DELETE -H 'If-Match: 1' http://localhost:3500/v1.0/state/statestore/sampleData
|
|
```
|
|
|
|
## Next Steps
|
|
|
|
- [State management overview]({{< ref state-management-overview.md >}})
|
|
- [How-To: Save & get state]({{< ref howto-get-save-state.md >}})
|