Computer Science
Algorithm
Data Processing
Digital Life
Distributed System
Distributed System Infrastructure
Machine Learning
Operating System
Android
Linux
Tizen
Windows
iOS
Programming Language
C++
Erlang
Go
Scala
Scheme
Type System
Software Engineering
Storage
UI
Flutter
Javascript
Virtualization
Life
Life in Guangzhou (2013)
Recent Works (2013)
东京之旅 (2014)
My 2017 Year in Review (2018)
My 2020 in Review (2021)
十三年前被隔离的经历 (2022)
A Travel to Montreal (2022)
My 2022 in Review (2023)
Travel Back to China (2024)
Projects
Bard
Blog
RSS Brain
Scala2grpc
A Library to Make It Easier to Use Scala with gRPC (2022)
Comment Everywhere (2013)
Fetch Popular Erlang Modules by Coffee Script (2013)
Psychology
耶鲁大学心理学导论 (2012)
Thoughts
Chinese
English

A Library to Make It Easier to Use Scala with gRPC

Posted on 02 May 2022, tagged ProgrammingScalagRPCbackend

This article describes why I created the library Scala2grpc.

gPRC is a Remote Procedure Call (RPC) framework made by Google. It uses a domain specific language (DSL) to define the APIs, and provides tools for lots of languages to generate code for both servers and clients. The generated code includes models and API interfaces. The developer can create a gRPC server by implementing the generated interfaces. There are lots of examples in the official document so I’ll not spend more time on the details.

It has lots of advantages compared to traditional HTTP APIs that encode payloads as JSON or XML. Just to name a few: it’s type safe so there are less places to make errors; it has a schema so causes less confusing when communicate APIs between developers; it’s more efficient on both serialization and translation. Because of the advantages and the big name behind it, it’s very popular, especially for mobile apps because of the good client support.

However, I feel the framework is very invasive: models are usually the foundations of a program. With gRPC, the models are generated by the framework, as well as the interfaces. This makes the whole program depends on the framework very heavily. Here is an example:

// ExampleService is generated by gRPC
class ExampleServiceImpl() extends ExampleService {
	// ExampleInput and ExampleOutput are both generated by gRPC.
	def exampleAPI(input ExampleInput): ExampleOut = {
		...
  }
}

It’s more invasive than most of the (non RPC) libraries: for most of other libraries, you can define the interface and use those libraries to fill in the implementations, so when you change a library you don’t need to change other parts of the code.

Maybe sometimes it doesn’t matter too much: say you are Google and this framework is so fundamental in the services that no one is gonna to change it. But if you don’t like it, a way to work around this is to define the business logic at another place, and invoke those native classes and methods in the implementation of the gRPC generated interfaces. The logic in these implementations should be as simple as possible, usually just the invoking of methods and the converting between gRPC models and native models. Here is an example of this approach:


// define natvie classes
case class MyInput(...)
case class MyOutput(...)

class MyService() {
	def myAPI(input MyInput): MyOutput = {
		...
	}
}


// implement gRPC interfaces
// ExampleService is generated by gRPC
class ExampleServiceImpl(val myService: MyService) extends ExampleService {

	// ExampleInput and ExampleOutput are both generated by gRPC.
	def exampleAPI(input ExampleInput): ExampleOut = {
		val myInput = convertFromGRPC(input)
		val myOutput = myService.myAPI(myInput)
		convertToGRPC(myOutput)
  }
}

// implement convertFromGRPC ...
// implement convertToGRPC ...

However, this results lots of repeated works, especially for the converting between gRPC models and native models.

So here is where the sbt plugin Scala2grpc I’ve written comes in: it will generate all the proto files from the native Scala classes, and also generates the classes to convert between native models and gPRC models, and the classes to implement the gPRC interfaces. For example, in the example above, you only needs to write the code for MyInput, MyOutput and MyService, the generation of the proto files are handled by Scala2grpc, as well as ExampleServiceImpl, convertFromGRPC and convertToGRPC.

Sounds interesting? Check out the Github page to see how to use it. Don’t forget to star it if you find it helpful!