Skip to content

Commit

Permalink
Add docs for ErrorResponseConfig (#2198) (#3175)
Browse files Browse the repository at this point in the history
  • Loading branch information
987Nabil authored Sep 27, 2024
1 parent fb96e3f commit c44912b
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 0 deletions.
11 changes: 11 additions & 0 deletions docs/reference/handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,17 @@ In this example, the type of the handler before applying the `sandbox` operator

Without the `sandbox` operator, the compiler would complain about the unhandled `Throwable` error.

By default, sandboxed errors will result in a `500 Internal Server Error` response without a body. If you want to have all information about the error in the response body you can use a different (`ErrorResponseConfig`)[response/response.md#failure-responses-with-details] like `ErrorResponseConfig.debug`:

```scala mdoc:compile-only
import zio.http._
import java.nio.file._

Routes(
Method.GET / "file" ->
Handler.fromFile(Paths.get("file.txt").toFile).sandbox,
) @@ ErrorResponseConfig.debug
```
### Converting a `Handler` to an `Routes`

The `Handler#toRoutes` operator, converts a handler to an `Routes` to be served by the `Server`. The following example, shows an HTTP application that serves a simple "Hello, World!" response for all types of incoming requests:
Expand Down
50 changes: 50 additions & 0 deletions docs/reference/response/response.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,56 @@ val failedHandler = Handler.fail(new IOException())
failedHandler.mapErrorCause(Response.fromCause)
```

#### Failure Responses with Details

By default, the `Response.fromThrowable` and `Response.fromCause` methods create a response with a status code only. If we want to include additional details in the response, we have to hand over a `ErrorResponseConfig`.

```scala
/**
* Configuration for the response generation
*
* @param withErrorBody
* if true, includes the error message in the response body
* @param withStackTrace
* if true, includes the stack trace in the response body
* @param maxStackTraceDepth
* maximum number of stack trace lines to include in the response body. Set to
* 0 to include all lines.
* @param errorFormat
* the preferred format for the error response.
* If the context in which the response is created has access to an Accept header,
* the header will be used preferably to determine the format.
*/
final case class ErrorResponseConfig(
withErrorBody: Boolean = false,
withStackTrace: Boolean = false,
maxStackTraceDepth: Int = 10,
errorFormat: ErrorResponseConfig.ErrorFormat = ErrorResponseConfig.ErrorFormat.Html,
)
```

This config can not only be used directly, but can also configure how ZIO-HTTP internally converts a `Cause` or `Throwable` to a `Response`.
You can configure error responses globally by providing a custom `ErrorResponseConfig` via layer for example in the bootstrap of your application.
Or you can apply the config locally to some routes via middleware.

```scala mdoc
import zio.http._

object MyHttpApp extends ZIOAppDefault {
// Provide a custom ErrorResponseConfig via layer
// Equivalent to: val bootstrap = ErrorResponseConfig.configLayer(ErrorResponseConfig.debugConfig)
override val bootstrap: ZLayer[ZIOAppArgs, Any, Any] = ErrorResponseConfig.debugLayer

// Apply the ErrorResponseConfig.debug middleware to routes
// Equivalent to: val myRoutes = Handler.ok.toRoutes @@ ErrorResponseConfig.withConfig(ErrorResponseConfig.debugConfig)
val myRoutes = Handler.ok.toRoutes @@ ErrorResponseConfig.debug

override def run = ???
}
```

The debug config will include the error message and full stack trace in the response body.

:::note
In many cases, it is more convenient to use the `sandbox` method to automatically convert all failures into a corresponding `Response`. But in some cases, to have more granular control over the error handling, we may want to use `Response.fromCause` and `Response.fromThrowable` directly.
:::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import zio._
* @param maxStackTraceDepth
* maximum number of stack trace lines to include in the response body. Set to
* 0 to include all lines.
* @param errorFormat
* the preferred format for the error response. If the context in which the
* response is created has access to an Accept header, the header will be used
* preferably to determine the format.
*/
final case class ErrorResponseConfig(
withErrorBody: Boolean = false,
Expand All @@ -38,6 +42,9 @@ object ErrorResponseConfig {
val debug: HandlerAspect[Any, Unit] =
Middleware.runBefore(setConfig(debugConfig))

val debugLayer: ULayer[Unit] =
ZLayer(setConfig(debugConfig))

def withConfig(config: ErrorResponseConfig): HandlerAspect[Any, Unit] =
Middleware.runBefore(setConfig(config))

Expand Down

0 comments on commit c44912b

Please sign in to comment.