Skip to content

Commit

Permalink
HZX-141: added error throwing content for v34
Browse files Browse the repository at this point in the history
  • Loading branch information
amandalindsay committed Oct 24, 2024
1 parent d3db543 commit 82cbf30
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 20 deletions.
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
* xref:query:mutations.adoc[Perform mutations]
* xref:query:queries-as-endpoints.adoc[Publish queries]
* xref:query:observability.adoc[Observe queries]
* xref:query:errors.adoc[Handle errors]
.Reference
* xref:glossary.adoc[Glossary]
Expand Down
40 changes: 20 additions & 20 deletions docs/modules/deploy/pages/data-policies.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

{short-product-name} supports defining data access policies against types, which are evaluated when running queries. This feature allows you to define data policies once and enforce them consistently across your organization, regardless of where data is served from.

## Overview
== Overview

Policies are first-class citizens within {short-product-name} and are defined in your project along with your types, models, and services. They can conditionally control the data that is returned (including filtering and obfuscating values) and determine which services and operations can be invoked.

## Get started - configure your JWT
== Get started - configure your JWT

Policies are often used as a form of authorization based on the user requesting the data. To use policies in this manner, you must first have configured xref:authentication.adoc[Authentication] with {short-product-name}.

### Expose user information
=== Expose user information

Policies access user information from the claims presented on your authentication token. Since each authentication provider is different, you need to define a {short-product-name} type that maps data from your token into data types you can use in your policies.

Expand Down Expand Up @@ -59,13 +59,13 @@ model UserInfo inherits com.flow.auth.AuthClaims {
}
```

### Verify your credentials
=== Verify your credentials

To verify that your credentials have been mapped correctly, the UI shows the details of the current user in the policy designer:

image:user-credentials.png[]

## Define policies
== Define policies

Policies are defined in Taxi files within a {short-product-name} project. Here's a simple example:

Expand All @@ -87,7 +87,7 @@ policy ExcludeYearReleased against Film {

The above policy will be invoked whenever data is returned from an operation that returns `Film` data.

### Inputs to policies
=== Inputs to policies
Policies can request data as an input, which can be referred to within the policy.
For example, this policy requests information about the user making the request:

Expand All @@ -102,7 +102,7 @@ Here, `UserInfo` is the type configured against the JWT token as xref:data-polic

You can request any data in the policy, including data loaded from additional services, as described below.

### Suppress data based on user properties
=== Suppress data based on user properties

You can create policies that behave differently based on user properties.

Expand All @@ -119,13 +119,13 @@ policy FilterSalary against Employee (userInfo : UserInfo) -> {
}
```

### Policies may not alter structure
=== Policies may not alter structure
Data policies can be used to xref:data-policies.adoc#obfuscate-data[obfuscate] and filter out properties, but they cannot drop fields entirely, as doing so
would cause parsing exceptions in downstream systems, and mean that responses violate their own contracts.

When data is filtered (for example, using a spread operator), the resulting object contains nulls.

### Policies and expressions
=== Policies and expressions
When models include an expression, the expression is evaluated using the input values after the relevant security policies have been applied.

This approach ensures that sensitive information is not inadvertently exposed (for example, by adjusting a policy-protected value using an expression such as: `EmployeeSalary + 1`).
Expand All @@ -134,7 +134,7 @@ As a result, the input values used in the expression may differ from the origina

If a policy causes an input value to become `null`, the expression will also evaluate to `null`.

### Throw errors from policies
=== Throw errors from policies

Policies can also throw errors to completely deny access to certain data based on conditions. For example:

Expand All @@ -149,7 +149,7 @@ policy OnlyManagers against EmployeeInfo (userInfo : UserInfo) -> {
}
```

### Obfuscate data
=== Obfuscate data

You can use policies to obfuscate data. The policies can be applied to nested types as well. For example, to partially obfuscate titles for non-admin users:

Expand All @@ -164,7 +164,7 @@ policy FilterFilmTitle against Title (userInfo : UserInfo) -> {
}
```

### Use external data in policy decisions
=== Use external data in policy decisions

Policies can load additional data from external services to make decisions. For example, to filter films based on whether the user has accepted terms and conditions:

Expand All @@ -187,7 +187,7 @@ policy AllAccessFilms against Film (userInfo : UserInfo, acceptedTerms: Accepted
}
```

### Projection and policy impact
=== Projection and policy impact

When a policy modifies a field that is used in a projection, the result is affected accordingly. For instance, if a policy suppresses the `title` field for non-admin users:

Expand All @@ -212,7 +212,7 @@ find { Film } as {

For non-admin users, this would return `name: null`.

## Understand when policies are applied
== Understand when policies are applied

Policies defined against types or models are applied to data returned from a service before it's made available in {short-product-name} (either for other service calls or to return to a caller). A policy is applied to the type **and all its subtypes**.

Expand Down Expand Up @@ -252,7 +252,7 @@ find { Film[]}",

```

## Use errors in policies
== Use errors in policies

Errors can be thrown in policies to prevent access entirely, returning an error code to the user. For example:

Expand All @@ -270,13 +270,13 @@ policy OnlyManagers against EmployeeInfo (userInfo : UserInfo) -> {
// AUTHORS NOTE - TO DO: once topic added, re-instate this xref
// Read more about [how to throw errors](/docs/querying/errors).

## Apply to streaming queries
== Apply to streaming queries
Data policies can also be applied to streaming queries, which are running continuously in the background.

Instead of executing with the requested user permissions (as request / response queries do), persistent
streaming queries execute with a system account - the Executor user.

### Configure the Executor user
=== Configure the Executor user
The Executor User is a standard system account defined by your Identity Provider (IDP). Assign roles as you would with
any other user, as discussed in our docs on xref:authentication.adoc[Authentication].

Expand All @@ -303,9 +303,9 @@ Example configuration:
--flow.security.openIdp.executorRoleClientSecret=AngelicaElizaAndPeggy
```

### Troubleshoot
=== Troubleshoot

#### IssuerUrl connectivity issues
=== IssuerUrl connectivity issues
The `issuerUrl` setting is used by both standard xref:authentication.adoc#open-id-connect-setup[Authentication] (to authenticate users logging in to {short-product-name}), as
well as by {short-product-name} to fetch user credentials for the Executor user.

Expand All @@ -318,7 +318,7 @@ or set Docker to use the https://docs.docker.com/engine/network/drivers/host/[Ho

This is generally not an issue in production (and the above workarounds are not suitable for production), as the network is normally more well defined.

### Observers vs Executors
=== Observers vs Executors
Persistent Streams are always executed under the permissions of the Executor user. However, these streams can also be observed by other users, through published xref:query:queries-as-endpoints.adoc#saved-streams[http or websocket endpoints].

In this scenario, policies are applied twice:
Expand Down
146 changes: 146 additions & 0 deletions docs/modules/query/pages/errors.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
= Handle errors
:description: Using errors to control process in {short-product-name}.

In {short-product-name} and Taxi, error handling is managed through a `throw` function that allows you to
control the response sent back to the user.

This includes setting the error code and the response payload. Note that currently, we do not support catching errors—
throwing an error is a fatal action. This will be addressed in a future release.

== Throw errors

Errors are thrown using the `throw` function. The syntax for throwing an error is:

```kotlin
throw((ErrorType) { errorPayload })
```

This is actually a casting operation which casts the payload value to the defined error type. This is
because Taxi does not have a concept of constructors, or object creation.

For example, given a `NotAuthorizedError`, defined as follows:

```taxi NotAuthorized.taxi
import com.flow.errors.Error

model NotAuthorizedError inherits Error {
message: ErrorMessage
}
```

This would be thrown as follows:

```taxi
throw((NotAuthorizedError) { message: "Authentication failed" })
```

Here, `(NotAuthorizedError)` is a casting statement.

=== Define errors

Errors are defined as models in Taxi. An error model must inherit from the base `Error` type (`com.flow.errors.Error`) and can include
annotations to control the HTTP response code and the response body. Below are examples of how to define and use error models.

=== Example: NotAuthorizedError

The `NotAuthorizedError` is provided out-of-the-box and is defined as follows:

```taxi
@ResponseCode(401)
model NotAuthorizedError inherits Error {
message: ErrorMessage
}
```

To throw this error with a custom message:

```taxi
throw((NotAuthorizedError) { message: "Authentication failed" })
```

== Response codes and payloads

When an error is thrown, users can control the HTTP response code and the response payload using annotations.

=== Example: Custom response code

If no response code is provided, the default response code is 400. To specify a custom response code, use the `@ResponseCode` annotation:

Note: Don't forget to include the import of `taxi.http.ResponseCode`

```taxi
import taxi.http.ResponseCode

@ResponseCode(403)
model NotAuthorizedError inherits Error {
message: ErrorMessage
}
```

=== Example: Custom response body

To customize the response body, use the `@ResponseBody` annotation:

Note: Don't forget to include the import of `taxi.http.ResponseBody`


```taxi
import taxi.http.ResponseBody

model BadPermissionsError inherits Error {
@ResponseBody
error: {
errorCode: String
message: String
}
}
```

Thrown as follows:

```taxi
throw( (BadPermissionsError)
{ error:
{ errorCode: 'E1234', message: "You didn't say the magic word" }
}
)
```

This would generate an error as follows:

```json
{
"errorCode" : "E1234",
"message" : "You didn't say the magic word"
}
```

== Built-in errors

As part of the release in 0.34, the following errors will be provided out-of-the-box.

// AUTHORS NOTE - is this missing the 401 not authorized error? And is bad request also a 400, same as client error?

|===
| Error Type | Description | HTTP Response Code

| *OperationFailedError*
| Thrown when an operation fails to be invoked (e.g., a server returned a 4xx/5xx error).
| 400 (Client Error)

| *ModelContractViolationError*
| Thrown when a model cannot be constructed, generally because data was missing.
| 422 (Unprocessable Entity)

| *ParseError*
| Thrown when source content could not be parsed (e.g., malformed JSON or CSV).
| 400 (Bad Request)

| *DataNotDiscoverableError*
| Thrown when the query asked for data, but no services could provide the requested data.
| 404 (Not Found)

| *NotAuthorizedError*
| Thrown to indicate that a requested data attribute or service call has been rejected.
| 403 (Forbidden)
|===

0 comments on commit 82cbf30

Please sign in to comment.