-
Notifications
You must be signed in to change notification settings - Fork 0
/
Service.scala
60 lines (48 loc) · 1.67 KB
/
Service.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
package exampleservice
import org.http4s.client.Client
import cats.effect.IOApp.Simple
import cats.effect.IO
import cats.effect.kernel.Async
import org.http4s.ember.client.EmberClientBuilder
import fs2.io.net.Network
import org.http4s.ember.server.EmberServerBuilder
import cats.syntax.all.*
import com.comcast.ip4s.*
import smithy4s.http4s.SimpleRestJsonBuilder
import org.http4s.Uri
import cats.effect.Concurrent
import org.http4s.EntityDecoder
import org.http4s.circe._
object Service extends Simple {
class AppImpl[F[_]](client: Client[F])(using F: Concurrent[F])
extends SimpleService[F] {
implicit val dec: EntityDecoder[F, Map[String, Double]] = jsonOf
override def imAlive(): F[ImAliveResp] = F.pure(ImAliveResp("I am alive"))
override def getFxRate(ccy0: Currency, ccy1: Currency): F[FxRate] =
F.fromEither(
Uri.fromString(
s"https://api.frankfurter.app/latest?from=$ccy0&to=$ccy1"
)
).flatMap(uri => client.expect[Map[String, Double]](uri))
.flatMap(rp =>
F.fromOption(
rp.values.toList.headOption.map(FxRate(_)),
new RuntimeException(s"Unable to get rate for $ccy0$ccy1")
)
)
}
def runImpl[F[_]: Network](using F: Async[F]): F[Unit] =
(for {
client <- EmberClientBuilder.default[F].build
httpRoutes <- SimpleRestJsonBuilder
.routes(new AppImpl[F](client))
.resource
server <- EmberServerBuilder
.default[F]
.withHost(host"localhost")
.withPort(port"8090")
.withHttpApp(httpRoutes.orNotFound)
.build
} yield server).use(_ => F.never)
override def run: IO[Unit] = runImpl[IO]
}