Skip to content

Commit

Permalink
Adds an error-handling example and client docs
Browse files Browse the repository at this point in the history
Signed-off-by: Elena Kolevska <[email protected]>
  • Loading branch information
elena-kolevska committed Jan 23, 2024
1 parent 7284b9b commit 1127b1b
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 0 deletions.
20 changes: 20 additions & 0 deletions daprdocs/content/en/python-sdk-docs/python-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@ If your Dapr instance is configured to require the `DAPR_API_TOKEN` environment
set it in the environment and the client will use it automatically.
You can read more about Dapr API token authentication [here](https://docs.dapr.io/operations/security/api-token/).

## Error handling
Initially, errors in Dapr followed the [Standard gRPC error model](https://grpc.io/docs/guides/error/#standard-error-model). However, to provide more detailed and informative error messages, in version 1.13 an enhanced error model has been introduced which aligns with the gRPC [Richer error model](https://grpc.io/docs/guides/error/#richer-error-model). In response, the Python SDK implemented `DaprGrpcError`, a custom exception class designed to improve the developer experience.
It's important to note that the transition to using `DaprGrpcError` for all gRPC status exceptions is a work in progress. As of now, not every API call in the SDK has been updated to leverage this custom exception. We are actively working on this enhancement and welcome contributions from the community.

Example of handling `DaprGrpcError` exceptions when using the Dapr python-SDK:

```python
try:
d.save_state(store_name=storeName, key=key, value=value)
except DaprGrpcError as err:
print(f'Status code: {err.code()}')
print(f"Message: {err.message()}")
print(f"Error code: {err.error_code()}")
print(f"Error info(reason): {err.error_info.reason}")
print(f"Resource info (resource type): {err.resource_info.resource_type}")
print(f"Resource info (resource name): {err.resource_info.resource_name}")
print(f"Bad request (field): {err.bad_request.field_violations[0].field}")
print(f"Bad request (description): {err.bad_request.field_violations[0].description}")
```


## Building blocks

Expand Down
55 changes: 55 additions & 0 deletions examples/error_handling/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Example - Error handling

This guide demonstrates handling `DaprGrpcError` errors when using the Dapr python-SDK. It's important to note that not all Dapr gRPC status errors are currently captured and transformed into a `DaprGrpcError` by the SDK. Efforts are ongoing to enhance this aspect, and contributions are welcome. For detailed information on error handling in Dapr, refer to the [official documentation](https://docs.dapr.io/reference/errors/).

The example involves creating a DaprClient and invoking the save_state method.
It uses the default configuration from Dapr init in [self-hosted mode](https://github.com/dapr/cli#install-dapr-on-your-local-machine-self-hosted).

## Pre-requisites

- [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started)
- [Install Python 3.8+](https://www.python.org/downloads/)

## Install Dapr python-SDK

<!-- Our CI/CD pipeline automatically installs the correct version, so we can skip this step in the automation -->

```bash
pip3 install dapr dapr-ext-grpc
```

## Run the example

To run this example, the following code can be used:

<!-- STEP
name: Run error handling example
expected_stdout_lines:
- "== APP == Status code: StatusCode.INVALID_ARGUMENT"
- "== APP == Message: input key/keyPrefix 'key||' can't contain '||'"
- "== APP == Error code: DAPR_STATE_ILLEGAL_KEY"
- "== APP == Error info(reason): DAPR_STATE_ILLEGAL_KEY"
- "== APP == Resource info (resource type): state"
- "== APP == Resource info (resource name): statestore"
- "== APP == Bad request (field): key||"
- "== APP == Bad request (description): input key/keyPrefix 'key||' can't contain '||'"
timeout_seconds: 5
-->

```bash
dapr run -- python3 error_handling.py
```
<!-- END_STEP -->

The output should be as follows:

```
== APP == Status code: StatusCode.INVALID_ARGUMENT
== APP == Message: input key/keyPrefix 'key||' can't contain '||'
== APP == Error code: DAPR_STATE_ILLEGAL_KEY
== APP == Error info(reason): DAPR_STATE_ILLEGAL_KEY
== APP == Resource info (resource type): state
== APP == Resource info (resource name): statestore
== APP == Bad request (field): key||
== APP == Bad request (description): input key/keyPrefix 'key||' can't contain '||'
```
25 changes: 25 additions & 0 deletions examples/error_handling/error_handling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

from dapr.clients import DaprClient
from dapr.clients.exceptions import DaprGrpcError

with DaprClient() as d:
storeName = 'statestore'

key = 'key||'
value = 'value_1'

# Wait for sidecar to be up within 5 seconds.
d.wait(5)

# Save single state.
try:
d.save_state(store_name=storeName, key=key, value=value)
except DaprGrpcError as err:
print(f'Status code: {err.code()}')
print(f"Message: {err.message()}")
print(f"Error code: {err.error_code()}")
print(f"Error info(reason): {err.error_info.reason}")
print(f"Resource info (resource type): {err.resource_info.resource_type}")
print(f"Resource info (resource name): {err.resource_info.resource_name}")
print(f"Bad request (field): {err.bad_request.field_violations[0].field}")
print(f"Bad request (description): {err.bad_request.field_violations[0].description}")

0 comments on commit 1127b1b

Please sign in to comment.