8. Params (Reader Monad)
1 val user = for {
2 name <- RequiredParam("name")
3 age <- RequiredIntParam("age")
4 city <- OptionalParam("city")
5 } yield User(name, age, city.getOrElse("Novosibirsk"))
6
7 val service = new Service[HttpRequest, JsonResponse] {
8 def apply(req: HttpRequest) = for {
9 u <- user(req)
10 } yield JsonObject(
11 "name" -> u.name,
12 "age" -> u.age,
13 "city" -> u.city
14 )
15 }
16
17 val u: Future[User] = user(request) handle {
18 case e: ParamNotFound => BadRequest(e.param)
19 }
8
9. Case Study: Pagination
1 val pagination = {
2 val outerLimit = Config[Int]("limit", 15)
3
4 for {
5 offset <- OptionalIntParam("offset")
6 limit <- OptionalIntParam("limit")
7 } yield (
8 offset.getOrElse(0),
9 math.min(limit.getOrElse(outerLimit), outerLimit)
10 )
11 }
12
13 val a = new Service[HttpRequest, HttpResponse] {
14 def apply(req: HttpRequest) = for {
15 (offset, limit) <- pagination(req)
16 } yield Ok(s"offset $offset, limit $limit")
17 }
9
10. Multi-Value Params
1 val reader = for {
2 a <- RequiredIntParams("a")
3 b <- RequiredIntParams("b")
4 } yield (a, b)
5
6 // request("a=1,2,3&b=4&b=5")
7 val (a, b): (List[Int], List[Int]) = reader(request)
8 // a = List(1, 2, 3)
9 // b = List(4, 5)
10
11. Validation
1 val adult = for {
2 u <- user
3 _ <- ValidationRule("age", "should be greater then 18") { user.age >= 18 }
4 } yield u
5
6 val user: Future[User] = adult(request) handle {
7 case e: ParamNotFound =>
8 BadRequest(JsonObject("param" -> e.param))
9 case e: ValidationFailed =>
10 BadRequest(JsonObject("param" -> e.param, "rule" -> e.rule))
11 }
11
12. Responses
1 // an empty response with status 200
2 val a = Ok()
3
4 // 'plain/text' response with status 404
5 val b = NotFound("body")
6
7 // 'application/json' response with status 201
8 val c = Created(JsonObject("id" -> 42))
9
10 // 'plain/text' response of status 403 with custom header
11 val d = Forbidden.withHeaders("Some-Header-A" -> "a")("plain")
12
13. JSON
1 // a : {
2 // b : 10,
3 // c : 20,
4 // d : 30
5 // }
6 val a = JsonObject("a.b" -> 10, "a.c" -> 20, "a.d" -> 30)
7
8 // a : {
9 // a : 100,
10 // b : 200
11 // }
12 val b = JsonObject("a.a" -> 100, "a.b" -> 200)
13
14 // a : {
15 // a : 100
16 // b : 200,
17 // c : 20,
18 // d : 30
19 // }
20 val c = JsonObject.mergeRight(a, b)
13