Skip to content

Commit

Permalink
Update docs as per 0.9
Browse files Browse the repository at this point in the history
  • Loading branch information
vkostyukov committed Nov 9, 2015
1 parent 9906598 commit 903c9f0
Show file tree
Hide file tree
Showing 17 changed files with 438 additions and 582 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ FinagleJackson.postJsonObj:·gc.alloc.rate.norm avgt 10 376365652.800 ± 16

Demo
----
The [`petstore`](petstore) project implements the [Petstore](http://petstore.swagger.io/) Swagger example.
See very minimalistic [Finch application][todo] implementing an [HTTP backed][todobackend] for [TodoMVC][todomvc].

Documentation
-------------
* A comprehensive documentation may be found in the [`docs/`](docs/index.md) folder
* The latest Scaladoc is available at [http://finagle.github.io/finch/docs](http://finagle.github.io/finch/docs/#io.finch.package)
* The latest Scaladoc is available at [http://finagle.github.io/finch/docs][scaladoc]

Adopters
--------
Expand Down Expand Up @@ -141,3 +141,7 @@ limitations under the License.
[argonaut]: http://argonaut.io
[finagle-oauth2]: https://github.com/finagle/finagle-oauth2
[json4s]: http://json4s.org
[scaladoc]: http://finagle.github.io/finch/docs/#io.finch.package
[todo]: https://github.com/vkostyukov/finch-101/blob/master/src/main/scala/i/f/workshop/finch/Todo.scala
[todobackend]: http://www.todobackend.com/
[todomvc]: http://todomvc.com/
37 changes: 36 additions & 1 deletion core/src/main/scala/io/finch/Endpoint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,42 @@ import shapeless.ops.adjoin.Adjoin
import shapeless.ops.function.FnToProduct

/**
* An endpoint that is given an [[Input]], extracts some value of the type `A`, wrapped with [[Output]].
* An `Endpoint` represents the HTTP endpoint.
*
* I is well known and widely adopted in Finagle that "Your Server as a Function" (i.e., `Request => Future[Response]`.
* In a REST API setting this function may be viewed as `Request =1=> (A =2=> Future[B]) =3=> Future[Response]`, where
* transformation `1` is request decoding (deserialization), transformation `2` - is business logic and transformation
* `3` is- response encoding (serialization). The only interesting part here is transformation `2`
* (i.e., `A => Future[B]`), which represents a bossiness logic of an application.
*
* An `Endpoint` transformation (`map`, `embedFlatMap`, etc.) encodes the business logic, while the rest of Finch
* ecosystem takes care about both serialization and deserialization.
*
* A typical way to transform (or map) the `Endpoint` is to use [[Mapper]] and `Endpoint.apply` method, which, depending
* on the argument type, delegates the map operation to the underlying function.
*
* {{{
* case class Foo(i: Int)
* case class Bar(s: String)
*
* val foo: Endpoint[Foo] = get("foo") { Ok(Foo(42)) }
* val bar: Endpoint[Bar] = get("bar" / string) { s: String => Ok(Bar(s)) }
* }}}
*
* `Endpoint`s are also composable in terms of or-else combinator (or a space invader `:+:`) that takes two `Endpoint`s
* and gives a coproduct `Endpoint`.
*
* {{{
* val foobar: Endpoint[Foo :+: Bar :+: CNil] = foo :+: bar
* }}}
*
* An `Endpoint` might be converted into a Finagle [[Service]] with `Endpoint.toService` method so it can be served with
* Finagle HTTP.
*
* {{{
* Http.server.serve(foobar.toService)
* }}}
*
*/
trait Endpoint[A] { self =>
/**
Expand Down
15 changes: 13 additions & 2 deletions core/src/main/scala/io/finch/request/RequestReader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,19 @@ import shapeless.{HNil, Generic, ::, HList}
import scala.reflect.ClassTag

/**
* A polymorphic request reader (a reader monad) that reads a
* [[com.twitter.util.Future]] of `A` from the request of type `R`.
* A `RequestReader` (a reader monad) that reads a [[Future]] of `A` from the request of type `R`. `RequestReader`s
* might be composed with each other using either monadic API (`flatMap` method) or applicative API (`::` method).
* Regardless the API used for `RequestReader`s composition, the main idea behind it is to use primitive readers (i.e.,
* `param`, `paramOption`) in order to _compose_ them together and _map_ to the application domain data.
*
* {{{
* case class Complex(r: Double, i: Double)
* val complex: RequestReader[Complex] = (
* param("real").as[Double] ::
* paramOption("imaginary").as[Double].withDefault(0.0)
* ).as[Complex]
* }}}
*
*/
trait RequestReader[A] { self =>

Expand Down
13 changes: 11 additions & 2 deletions core/src/main/scala/io/finch/request/ValidationRule.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
package io.finch.request

/**
* A reusable validation rule that can be applied to any [[io.finch.request.RequestReader RequestReader]] with a
* matching type.
* A `ValidationRule` enables a reusable way of defining a validation rules in the application domain. It might be
* composed with [[RequestReader]]s using either should` or `shouldNot` methods and with other `ValidationRule`s using
* logical methods `and` and `or`.
*
* {{{
* case class User(name: String, age: Int)
* val user: RequestReader[User] = (
* param("name").should(beLongerThan(3)) ::
* param("age").as[Int].should(beGreaterThan(0) and beLessThan(120))
* ).as[User]
* }}}
*/
trait ValidationRule[A] { self =>

Expand Down
26 changes: 0 additions & 26 deletions core/src/main/scala/io/finch/request/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,6 @@ import com.twitter.io.Buf
* primitives allow both to _read_ the various request items (''query string param'', ''header'' and ''cookie'') using
* the [[io.finch.request.RequestReader RequestReader]] and _validate_ them using the
* [[io.finch.request.ValidationRule ValidationRule]].
*
* The cornerstone abstraction of this package is a `RequestReader`, which is responsible for reading any amount of data
* from the HTTP request. `RequestReader`s might be composed with each other using either monadic API (`flatMap` method)
* or applicative API (`::` method). Regardless the API used for `RequestReader`s composition, the main idea behind it
* is to use primitive readers (i.e., `param`, `paramOption`) in order to _compose_ them together and _map_ to
* the application domain data.
*
* {{{
* case class Complex(r: Double, i: Double)
* val complex: RequestReader[Complex] = (
* param("real").as[Double] ::
* paramOption("imaginary").as[Double].withDefault(0.0)
* ).as[Complex]
* }}}
*
* A `ValidationRule` enables a reusable way of defining a validation rules in the application domain. It might be
* composed with `RequestReader`s using either `should` or `shouldNot` methods and with other `ValidationRule`s using
* logical methods `and` and `or`.
*
* {{{
* case class User(name: String, age: Int)
* val user: RequestReader[User] = (
* param("name").should(beLongerThan(3)) ::
* param("age").as[Int].should(beGreaterThan(0) and beLessThan(120))
* ).as[User]
* }}}
*/
package object request {

Expand Down
45 changes: 33 additions & 12 deletions docs/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,46 @@

--

### Authorization with OAuth2
### Authentication with OAuth2

There is [finagle-oauth2](https://github.com/finagle/finagle-oauth2) server-side provider that is 100% compatible with
Finch. There is no Finch-specific abstractions available in Finch, but this work is [in progress][1].
There is [finagle-oauth2](https://github.com/finagle/finagle-oauth2) server-side provider that is supported in Finch via
`finch-oauth2` package:

### Basic HTTP Auth
*Authorize*
```scala
import com.twitter.finagle.oauth2._
import io.finch.oauth2._

val dataHandler: DataHandler[Int] = ???
val auth: RequestReader[AuthInfo[Int]] = authorize(dataHandler)
val e: Endpoint[Int] = get("user" ? auth) { ai: AuthInfo[Int] => Ok(ai.user) }
```

*Issue Access Token*
```scala
import com.twitter.finagle.oauth2._
import io.finch.oauth2._

[Basic HTTP Auth](http://en.wikipedia.org/wiki/Basic_access_authentication) is implemented as `basicAuth` combinator
available in `finch-core`. The `basicAuth` takes two param lists: 1) username and password and 2) a `Router` that has to
be authorized.
val token: RequestReader[GrandHandlerResult] = issueAccessToken(dataHandler)
val e: Endpoint[String] = get("token" ? token) { ghr: GrantHandlerResult =>
Ok(ghr.accessToken)
}
```

Note that both `token` and `authorize` may throw `com.twitter.finagle.oauth2.OAuthError` that should be explicitly
[handled](endpoint.md#error-handling) and converted into a `Output.Failure`.

### Authentication with Basic HTTP

[Basic HTTP Auth](http://en.wikipedia.org/wiki/Basic_access_authentication) is implemented as `BasicAuth` combinator
available in `finch-core`.

```scala
import io.finch.route._
import io.finch._

val router: Router[String] = Router.value("42")
val authRouter: Router[String] = basicAuth("username", "password")(router)
val basicAuth: BasicAuth = BasicAuth("user", "password")
val e: Endpoint[String] = basicAuth(Endpoint(Ok("secret place")))
```

--
Read Next: [JSON](json.md)

[1]: https://github.com/finagle/finch/issues/136
6 changes: 0 additions & 6 deletions docs/demo.md

This file was deleted.

Loading

0 comments on commit 903c9f0

Please sign in to comment.