Chris Birchall
47 Degrees
import io.circe.generic.auto._
import io.circe.generic.semiauto._
(in Scala 2)
message HelloRequest {
string name = 1;
}
message HelloResponse {
string name = 1;
}
service Greeter {
rpc SayHello(HelloRequest)
returns (HelloResponse);
}
greeter.proto
case class HelloRequest(name: String)
case class HelloResponse(greeting: String)
@service(Protobuf)
trait Greeter[F[_]] {
def SayHello(req: HelloRequest): F[HelloResponse]
}
Greeter.scala
(in Scala 2)
@service(Protobuf)
trait Greeter[F[_]] {
def SayHello(req: HelloRequest): F[HelloResponse]
}
// Generated by macro annotation
object Greeter {
def toServerServiceDefinition[F: ConcurrentEffect](
service: Greeter[F]
): io.grpc.ServerServiceDefinition
def client[F: ConcurrentEffect](
host: String, port: Int
): Resource[F, Greeter[F]]
}
(in Scala 2)
Macro takes care of
Plan for Scala 3
trait GrpcServerSide[S[_[_]]] {
def [F[_]: ConcurrentEffect] (service: S[F])
.toServerServiceDefinition: io.grpc.ServerServiceDefinition
}
trait GrpcClientSide[S[_[_]]] {
def client[F: ConcurrentEffect](
host: String, port: Int
): Resource[F, S[F]]
}
(in Scala 3)
message HelloRequest {
string name = 1;
}
message HelloResponse {
string name = 1;
}
service Greeter {
rpc SayHello(HelloRequest)
returns (HelloResponse);
}
greeter.proto
case class HelloRequest(name: String)
case class HelloResponse(greeting: String)
@service(Protobuf)
trait Greeter[F[_]] derives GrpcServerSide, GrpcClientSide {
def SayHello(req: HelloRequest): F[HelloResponse]
}
Greeter.scala
(in Scala 3)
class MyGreeter[F[_]: Applicative] extends Greeter[F] {
def SayHello(req: HelloRequest): F[HelloResponse] =
HelloResponse(s"Hi, ${req.name}!").pure
}
val serverServiceDef =
new MyGreeter[IO].toServerServiceDefinition
val client =
summon[GrpcClientSide[Greeter]].client[IO]("localhost", 8080)
`derives` clause + `derived` method