Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Build a micro-services API

Avatar for Oli Oli
April 02, 2019

Build a micro-services API

This talk introduces Mu, a new FP library for building micro-services APIs. Mu offers code annotations for defining RPC or REST APIs, message types, and serialization formats, thus removing the dependency on protocol-specific declarations and enabling seamless changes between different implementations.

Avatar for Oli

Oli

April 02, 2019

Other Decks in Technology

Transcript

  1. © Vizualus. All Rights Reserved. 1 Build a micro- services

    API @oli_kitty Oli Makhasoeva, Solutions Architect, 47 Degrees
  2. 4 Macros val methodDescriptor: DefDef = q""" def $methodDescriptorName(implicit ReqM:

    …MethodDescriptor.Marshaller[$reqType], RespM: …MethodDescriptor.Marshaller[$respType] ): …MethodDescriptor[$reqType, $respType] = { …MethodDescriptor.newBuilder(ReqM, RespM) .setType($streamingMethodType) .setFullMethodName( …MethodDescriptor .generateFullMethodName( ${lit(serviceName)}, ${lit(methodName)} )) .build()} """
  3. 10 def transformAvro[A]: Trans[AvroF, MuF, A] = Trans { case

    AvroF.TBoolean() => TBoolean() case AvroF.TInt() => TInt() case AvroF.TDouble() => TDouble() case AvroF.TString() => TString() case AvroF.TArray(item) => TList(item) case AvroF.TRecord(name, _, _, _, fields) => TProduct(name, fields.map(f => Field(f.name, f.tpe))) … } Recursion schemes github.com/higherkindness/skeuomorph
  4. 11 @message case class SumRequest(a: Int, b: Int) @message case

    class SumResponse(sum: Int) @service(Protobuf) trait MathService[F[_]] { def sum(sumRequest: SumRequest): F[SumResponse] } Service implementation
  5. 12 @service(Protobuf) trait MathService[F[_]] { def sum(req: SumRequest): F[SumResponse] }

    Server side class MathServiceHandler[F[_]](implicit M: Applicative[F]) extends MathService[F] { override def sum(req: SumRequest): F[SumResponse] = SumResponse(req.a + req.b).pure[F] }
  6. 13 def main(args: Array[String]): Unit = { val grpcConfig: IO[List[GrpcConfig]]

    = List( MathService.bindService[IO].map(AddService) ).sequence } Server App
  7. 14 def main(args: Array[String]): Unit = { val grpcConfig: IO[List[GrpcConfig]]

    = ??? val runServer = for { c <- grpcConfig server <- BuildServerFromConfig[IO]( "rpc.server.port", c ) _ <- GrpcServer.server[IO](server) } yield () } Server App
  8. 15 def main(args: Array[String]): Unit = { val grpcConfig: IO[List[GrpcConfig]]

    = ??? val runServer = for { c <- grpcConfig server <- BuildServerFromConfig[IO](???) _ <- GrpcServer.server[IO](server) } yield () runServer.unsafeRunSync } Server App
  9. 17 Client Side val chFor: ChannelFor = ConfigForAddress[IO](“rpc.client.host", “rpc.client.port”) .unsafeRunSync()

    val grpcClient: Resource[IO, MathService[IO]] = MathService.client[IO](chFor)
  10. 18 Client Side val chFor: ChannelFor = ConfigForAddress[IO](“rpc.client.host", “rpc.client.port”) .unsafeRunSync()

    val grpcClient: Resource[IO, MathService[IO]] = MathService.client[IO](chFor) val ioClient: SumClientImpl[IO] = new SumClientImpl[IO](grpcClient)
  11. 19 object SumApp { def main(args: Array[String]): Unit = {

    sum[IO].unsafeRunSync() } def sum[F[_]](implicit client: SumClient[F]): F[Int] = client.sum(SumRequest(1, 2)) } Client App
  12. 20 def hi(req: Observable[HiRequest] ): Observable[HiResponse] MONIX def hi(req: Stream[F,

    HiRequest] ): Stream[F, HiResponse] FS2 Streaming rpc hi (stream HiRequest) returns (stream HiResponse); fs2.io monix.io
  13. 21 addSbtPlugin("io.higherkindness" % "sbt-mu-idlgen" % “0.17.1") idlType := "avro" srcGenSerializationType

    := "Avro" sourceGenerators in Compile += (srcGen in Compile).taskValue IDL generation
  14. © Vizualus. All Rights Reserved. 23 Thank you! Oli Makhasoeva,

    Solutions Architect, 47 Degrees @oli_kitty scala.love scalalaz.ru FUN[C] @fun_c_ higherkindness.io/mu 47deg.com