Skip to content

Commit

Permalink
Update docs as 0.9.2
Browse files Browse the repository at this point in the history
  • Loading branch information
vkostyukov committed Dec 5, 2015
1 parent 01e8b79 commit 0b63234
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 130 deletions.
28 changes: 20 additions & 8 deletions docs/endpoint.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,27 +192,35 @@ into an HTTP response. There are two cases of `Output`: `Output.Payload` represe
defined as payloads while the rest of outputs as failures.

`Output.Payload` carries an actual _value_ that will be serialized into a response body, while `Output.Failure` carries
just an failure message represented as `Map[String, String]`. A simplified version of this ADS is shown bellow.
an `Exception` cased this failure. A simplified version of this ADT is shown below.

```scala
sealed trait Output[A]
case class Payload[A](value: A) extends Output[A]
case class Failure(message: Map[String, String]) extends Output[Nothing]
case class Failure(cause: Exception) extends Output[Nothing]
```

Having an `Output` defined as an ADT allows to return both payloads and failures from the same endpoint depending on the
condition result.

```scala
val divOrFail: Endpoint[Int] = post("div" / a / b) { (a: Int, b: Int) =>
if (b == 0) BadRequest("err" -> "Can not divide by zero.")
if (b == 0) BadRequest(new ArithmeticException("Can not divide by 0"))
else Ok(a / b)
}
```

Please note that since `Output.Failure` contains the error message (i.e., `Map[String, String]`), when converting any
endpoint into a Finagle service it's also required to have an instance to `EncodeResponse[Map[String, String]]` in the
scope.
Payloads and failures are symmetric in terms of serializing `Output` into an HTTP response. With that said, in order to
convert an `Endpoint` into a Finagle service, there is should be an implicit instance of `EncodeResponse[Exception]`
available in the scope. For example, it might be defined in terms of Circe's `Encoder`:

```scala
implicit val encodeException: Encoder[Exception] = Encoder.instance(e =>
Json.obj("message" -> Json.string(e.getMessage)))
```

By default, all the exception are converted into `plain/text` HTTP response containing the exception message in their
bodies.

### Error Handling

Expand All @@ -222,16 +230,20 @@ similarly named methods:
- `Endpoint[A].handle[B >: A](Throwable => Output[B]): Endpoint[B]`
- `Endpoint[A].rescue[B >: A](Throwable => Future[Output[B]]): Endpoint[B]`

The following example handles the `ArithmeticExceptions` propagated from `a / b`.
The following example handles the `ArithmeticException` propagated from `a / b`.

```scala
val divOrFail: Endpoint[Int] = post("div" / a / b) { (a: Int, b: Int) =>
Ok(a / b)
} handle {
case _: ArithmeticExceptions => BadRequest("err" -> "Can not divide by zero.")
case e: ArithmeticExceptions => BadRequest(e)
}
```

All the unhandled exceptions are converted into very basic 500 responses that don't carry any payload. Only Finch's
errors (i.e., `io.finch.Error`) are treated in a special way and converted into 400 responses with their messages
serialized according to the rules defined in the `EncodeResponse[Exception]` instance.

--
Read Next: [RequestReaders](request.md)

Expand Down
1 change: 0 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ object Main extends App {

* [Endpoints](endpoint.md)
* [RequestReaders](request.md)
* [ResponseBuilders](response.md) **deprecated since 0.9.0**
* [Authentication](auth.md)
* [JSON](json.md)
* [Best Practices](best-practices.md)
Expand Down
18 changes: 18 additions & 0 deletions docs/json.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ import io.finch.circe._
import io.circe.generic.auto._
```

It's also possible to import the Circe configuration that uses a pretty printer configured with `dropNullKeys = true`.
Use the following imports instead:

```scala
import io.finch.circe.dropNullKeys._
import io.circe.generic.auto._
```

### Argonaut

* Bring the dependency to the `finch-argonaut` module.
Expand All @@ -43,6 +51,16 @@ implicit val e: EncodeJson[_] = ???
implicit val d: DecodeJson[_] = ???
```

In addition to the very basic Argonaut pretty printer (available via `import io.finch.argonaut._`), there are three
additional configurations available out of the box:

* `import io.finch.argonaut.dropNullKeys._` - brings both decoder and encoder (uses pretty printer that drops null keys)
in the scope
* `import io.finch.argonaut.preserveOrder._` - brings both decoder and encoder (uses pretty printer that preserves
fields order) in the scope
* `import io.finch.argonaut.preserveOrderAndDropNullKeys._` - brings both decoder and encoder (uses pretty printer that
preserves fields order as well as drop null keys) in the scope

### Jackson

* Bring the dependency to the `finch-jackson` module.
Expand Down
10 changes: 5 additions & 5 deletions docs/request.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ operations in the `for`-comprehension will be performed.
A typical `RequestReader` might look like this:

```scala
import io.finch.request._
import io.finch._

case class User(name: String, age: Int, city: String)

Expand Down Expand Up @@ -148,7 +148,7 @@ def as[A](implicit gen: Generic.Aux[A, L]): RequestReader[A]
```

The following sections cover all these features in more detail. All sample code assumes that you have imported
`io.finch.request._`.
`io.finch._`.

Finally, `RequestReader`s that return `Option` values have a couple of additional useful methods:
`withDefault(value: A)` and `orElse(alternative: Option[A])`.
Expand Down Expand Up @@ -227,16 +227,16 @@ The exceptions from a request reader might be handled just like other failed fut

```scala
val user: Future[Json] = service(...) handle {
case NotFound(ParamItem(param)) =>
case Error.NotFound(ParamItem(param)) =>
Json.obj("error" -> "param_not_found", "param" -> param)
case NotValid(ParamItem(param), rule) =>
case Error.NotValid(ParamItem(param), rule) =>
Json.obj("error" -> "validation_failed", "param" -> param, "rule" -> rule)
}
```

All the exceptions thrown by `RequestReader` are case classes. Therefore pattern matching may be used to handle them.

These are all error types produced by Finch (note that all extend `RequestError`):
These are all error types produced by Finch (note that all extend `io.finch.Error`):

```scala
// when multiple request items were invalid or missing
Expand Down
116 changes: 0 additions & 116 deletions docs/response.md

This file was deleted.

0 comments on commit 0b63234

Please sign in to comment.