-
Notifications
You must be signed in to change notification settings - Fork 221
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ed7f816
commit 6c43fb6
Showing
10 changed files
with
284 additions
and
251 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
## Authentication | ||
|
||
### Authorization with OAuth2 | ||
|
||
There is [finagle-oauth2](https://github.com/finagle/finagle-oauth2) server-side provider that is 100% compatible with | ||
Finch. | ||
|
||
### Basic HTTP Auth | ||
|
||
[Basic HTTP Auth](http://en.wikipedia.org/wiki/Basic_access_authentication) is supported out-of-the-box and implemented | ||
as `finch.io.auth.BasicallyAuthorize` filter. | ||
|
||
```scala | ||
object ProtectedEndpoint extends Endpoint[HttpRequest, HttpResponse] { | ||
def route = { | ||
case Method.Get -> Root / "users" => BasicallyAuthorize("user", "password") ! GetUsers | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
## Demo | ||
|
||
There is a single-file `demo` project , which is a complete REST API backend written with `finch-core` and `finch-json` | ||
modules. The source code of the demo project is altered with useful comments that explain how to use its building blocks | ||
such as `Endpoint`, `RequestReader`, `ResponseBuilder`, etc. The `demo` module is just a single Scala file Main.scala | ||
that is worth reading. | ||
|
||
The following command may be used to run the demo: | ||
|
||
```bash | ||
sbt 'project demo' 'run io.finch.demo.Main' | ||
``` | ||
|
||
---- | ||
**#** [Endpoints](endpoint.md) | [Table Of Contents](index.md#table-of-contents) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
## Endpoints | ||
|
||
One of the most powerful abstractions in Finch is an `Endpoint`, which is a composable router. At the high level | ||
it might be treated as a usual `PartialFunction` from request to service. Endpoints may be converted to Finagle services. | ||
And more importantly they can be composed with other building blocks like filters, services or endpoints itself. | ||
|
||
The core operator in Finch is _pipe_ (bang) `!` operator, which is like a Linux pipe exposes the data flow. Both | ||
requests and responses may be piped via chain building blocks (filters, services or endpoints) in exact way it has been | ||
written. | ||
|
||
The common sense of using the Finch library is to have an `Endpoint` representing the domain. For example, the typical | ||
use case would be to have an `Endpoint` from `OAuth2Request` (see [OAuth2 section](docs.md#authorization-with-oauth2)) | ||
to `Json` (see section [Json](docs.md#finch-json)). Since, all the endpoints have the same type (i.e., | ||
`Endpoint[OAuth2Request, Json]`) they may be composed together into a single entry point with either `Endpoint.join()` | ||
or `orElse` operators. The following example shows the discussed example in details: | ||
|
||
|
||
```scala | ||
val auth: Filter[HttpRequest, HttpResponse, OAuth2Request, HttpResponse] = ??? | ||
val users: Endpoint[OAuth2Request, Json] = ??? | ||
val groups: Endpoint[OAuth2Request, Json] = ??? | ||
val endpoint: Endpoint[OAuth2Request, HttpResponse] = (users orElse groups) ! TurnIntoHttp[Json] | ||
|
||
// An HTTP endpoint that may be served with `Httpx` | ||
val httpEndpoint: Endpoint[HttpRequest, HttpResponse] = auth ! endpoint | ||
``` | ||
|
||
The best practices on what to choose for data transformation are following: | ||
|
||
* Services should be used when the request is not required for the transformation. | ||
* Otherwise, pure Finagle filters should be used. | ||
|
||
An `Endpoint[Req, Rep]` may be implicitly converted into `Service[Req, Rep]` by importing the `io.finch._` object. Thus, | ||
the following code is correct. | ||
|
||
```scala | ||
val e: Endpoint[MyRequest, HttpResponse] = ??? | ||
// an endpoint `e` will be converted to service implicitly | ||
Httpx.serve(new InetSocketAddress(8081), e) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<p align="center"> | ||
<img src="https://raw.githubusercontent.com/finagle/finch/master/finch-logo.png" width="360px" /> | ||
</p> | ||
|
||
The Finch library provides an immutable layer of functions and types atop of [Finagle][1] for writing lightweight | ||
consuming HTTP services. It roughly contains three packages: [io.finch.route](route.md), [io.finch.request](request.md), | ||
[io.finch.response](response.md), which correspond to three simple steps to a robust REST/HTTP API: | ||
|
||
#### Step 1: Routing the HTTP requests to a `Service` | ||
|
||
The [Router](route.md#router) abstraction routes the requests depending on their path and method information. `Router` | ||
combinator provides a bunch of predefined routers handling separated parts of a route. `Router`s might be composed with | ||
either `/` (`flatMap`) or `/>` (`map`) operator. There is also `|` (`orElse`) operator that combines two routers in | ||
terms of the inclusive or operator. | ||
|
||
```scala | ||
val router: Endpoint[HttpRequest, HttpResponse] = Get / ("users" | "user") / int /> GetUser | ||
``` | ||
|
||
#### Step 2: Reading the HTTP requests in a `Service` | ||
|
||
The [RequestReader](request.md#request-reader) abstraction is responsible for reading any details form the HTTP request. | ||
`RequestReader` is composable in both ways: via the monadic API (using the for-comprehension, i.e., `flatMap`/`map`) and | ||
via the applicative API (using the `~` operator). These approaches define an unlimited number of readers out the plenty | ||
of predefined ones. | ||
|
||
```scala | ||
val pagination: RequestReader[(Int, Int)] = | ||
OptionalParam("offset").as[Int] ~ OptionalParam("limit").as[Int] map { | ||
case offset ~ limit => (offset.getOrElse(0), limit.getOrElse(100)) | ||
} | ||
``` | ||
|
||
#### Step 3: Building the HTTP responses in a `Service` | ||
|
||
The [ResponseBuilder](response.md#response-builder) abstraction provides a convenient way of building the HTTP responses | ||
of any type. In fact, `ResponseBuilder` is a function that takes some content and builds an HTTP response of a type | ||
depending on a content. There are plenty of predefined builders that might be used directly. | ||
|
||
```scala | ||
val ok: HttpResponse = Ok("Hello, world!") // plain/text HTTP response with status code 200 | ||
``` | ||
|
||
## Table of Contents | ||
|
||
* [Demo](demo.md) | ||
* [Endpoints](docs.md#endpoints) | ||
* [Requests](docs.md#requests) | ||
* [Custom Request Types](docs.md#custom-request-types) | ||
* [Request Reader](docs.md#request-reader) | ||
* [Overview](docs.md#overview) | ||
* [API](docs.md#api) | ||
* [Base Readers](docs.md#base-readers) | ||
* [Required and Optional Readers](docs.md#required-and-optional-readers) | ||
* [Multi-Value Parameters](docs.md#multi-value-parameters) | ||
* [Custom Readers](docs.md#custom-readers) | ||
* [Error Handling](docs.md#error-handling) | ||
* [Combining and Reusing Readers](docs.md#combining-and-reusing-readers) | ||
* [Applicative Syntax](docs.md#applicative-syntax) | ||
* [Monadic Syntax](docs.md#monadic-syntax) | ||
* [Type Conversion](docs.md#type-conversion) | ||
* [Built-in Decoders](docs.md#built-in-decoders) | ||
* [Custom Decoders](docs.md#custom-decoders) | ||
* [Integration with JSON Libraries](docs.md#integration-with-json-libraries) | ||
* [Validation](docs.md#validation) | ||
* [Inline Validation](docs.md#inline-validation) | ||
* [Reusable Rules](docs.md#reusable-validators) | ||
* [Built-in Rules](docs.md#built-in-rules) | ||
* [Responses](docs.md#responses) | ||
* [Response Builder](docs.md#response-builder) | ||
* [HTTP Redirects](docs.md#redirects) | ||
* [Authentication](docs.md#authentication) | ||
* [OAuth2](docs.md#authorization-with-oauth2) | ||
* [Basic Auth](docs.md#basic-http-auth) | ||
* [JSON](docs.md#json) | ||
* [Finch Json](docs.md#finch-json) | ||
* [Argonaut](docs.md#argonaut) | ||
* [Jawn](docs.md#jawn) | ||
|
||
[1]: http://twitter.github.io/finagle/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
## JSON | ||
|
||
### Finch-JSON | ||
|
||
The Finch library is shipped with an immutable JSON API: `finch-json`, an extremely lightweight and simple | ||
implementation of JSON: [Json.scala][3]. The usage looks as follows: | ||
|
||
```scala | ||
import io.finch.json._ | ||
import io.finch.request._ | ||
|
||
vaj j: Json = Json.obj("a" -> 10) | ||
val i: RequestReader[Json] = RequiredBody.as[Json] | ||
val o: HttpResponse = Ok(Json.arr("a", "b", "c") | ||
``` | ||
|
||
### Argonaut | ||
|
||
The `finch-argonaut` module provides the support for the [Argonaut][4] JSON library. | ||
|
||
### Jawn | ||
|
||
The `finch-jawn` module provides the support for [Jawn][5]. | ||
|
||
To decode a string with Jawn, you need to import `io.finch.jawn._` and define any Jawn `Facade` as an `implicit val`. | ||
Using either `RequiredJsonBody` or `OptionalJsonBody` will take care of the rest. | ||
|
||
To encode a value from the Jawn AST (specifically a `JValue`), you need only import `io.finch.jawn._` and | ||
the `Encoder` will be imported implicitly. | ||
|
||
### Jackson | ||
|
||
The `finch-jackson` module provides the support for the [Jackson][6] library. The library usage looks as follows: | ||
|
||
```scala | ||
import io.finch.jackson._ | ||
implicit val objectMapper: ObjectMapper = new ObjectMapper().registerModule(DefaultScalaModule) | ||
case class Foo(id: Int, s: String) | ||
|
||
val ok: HttpResponse = Ok(Foo(10, "foo")) // will be encoded as JSON | ||
val foo: RequestReader[Foo] = RequiredBody.as[Foo] // a request reader that reads Foo | ||
``` | ||
|
||
[3]: https://github.com/finagle/finch/blob/master/finch-json/src/main/scala/io/finch/json/Json.scala | ||
[4]: http://argonaut.io | ||
[5]: https://github.com/non/jawn | ||
[6]: http://jackson.codehaus.org/ |
Oops, something went wrong.