/
PlayInstances.scala
78 lines (69 loc) · 2.18 KB
/
PlayInstances.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/*
* Copyright 2018 http4s.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.http4s.play
import cats.effect.Concurrent
import fs2.Chunk
import org.http4s.headers.`Content-Type`
import org.http4s.{
DecodeResult,
EntityDecoder,
EntityEncoder,
InvalidMessageBodyFailure,
MediaType,
Message,
Uri,
jawn
}
import org.http4s.play.Parser.facade
import play.api.libs.json._
trait PlayInstances {
def jsonOf[F[_]: Concurrent, A](implicit decoder: Reads[A]): EntityDecoder[F, A] =
jsonDecoder[F].flatMapR { json =>
decoder
.reads(json)
.fold(
_ =>
DecodeResult.failureT(InvalidMessageBodyFailure(s"Could not decode JSON: $json", None)),
DecodeResult.successT(_)
)
}
implicit def jsonDecoder[F[_]: Concurrent]: EntityDecoder[F, JsValue] =
jawn.jawnDecoder[F, JsValue]
def jsonEncoderOf[F[_], A: Writes]: EntityEncoder[F, A] =
jsonEncoder[F].contramap[A](Json.toJson(_))
implicit def jsonEncoder[F[_]]: EntityEncoder[F, JsValue] =
EntityEncoder[F, Chunk[Byte]]
.contramap[JsValue] { json =>
val bytes = json.toString.getBytes("UTF8")
Chunk.array(bytes)
}
.withContentType(`Content-Type`(MediaType.application.json))
implicit val writesUri: Writes[Uri] =
Writes.of[String].contramap(_.toString)
implicit val readsUri: Reads[Uri] =
Reads.of[String].flatMap { str =>
Uri
.fromString(str)
.fold(
_ => Reads(_ => JsError("Invalid uri")),
Reads.pure(_)
)
}
implicit class MessageSyntax[F[_]: Concurrent](self: Message[F]) {
def decodeJson[A: Reads]: F[A] =
self.as(implicitly, jsonOf[F, A])
}
}