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