Overview:
In this tutorial, I would like to show you how we could use Spring WebFlux with Protobuf (Protocol Buffers) for your RESTful Microservices.
Protocol Buffers, in short Protobuf, are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data. You can take a look at this to learn more about this.
Spring WebFlux With Protobuf:
By default Spring Web/WebFlux modules use JSON for exchanging messages & the corresponding message converter. Spring also offers ProtobufHttpMessageConverter for us to use Protobuf if required.
Lets create a simple CRUD application with just GET and POST mappings to demo REST APIs using Spring WebFlux with Protobuf messages.
Sample Application:
We would create a simple Spring application is for managing persons with following dependencies.
Person Proto:
I define the Person proto as shown here.
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.vinsguru.models";
message Person {
string name = 1;
int32 age = 2;
}
Person Repository:
I use a Map as a database in this example and I create a PersonRepository as shown here.
@Service
public class PersonRepository {
private final AtomicInteger atomicInteger = new AtomicInteger(1);
private Map<Integer, Person> personMap;
@PostConstruct
private void init(){
this.personMap = new HashMap<>();
this.addPerson(Person.newBuilder().setName("vins").setAge(100).build());
}
public void addPerson(Person person){
this.personMap.put(atomicInteger.getAndIncrement(), person);
}
public Person getPerson(Integer id){
return this.personMap.getOrDefault(id, Person.getDefaultInstance());
}
}
Person Controller:
Lets expose REST APIs for the Person type created using Protobuf.
@RestController
@RequestMapping("person")
public class PersonController {
@Autowired
private PersonRepository personRepository;
@GetMapping("{id}")
public Person getPerson(@PathVariable int id){
return this.personRepository.getPerson(id);
}
@PostMapping
public void createPerson(@RequestBody Person person){
this.personRepository.addPerson(person);
}
}
That’s it! At this point, you can start your application which exposes REST API with Protobuf. (Do remember that Protobuf is NOT JSON or text format). You might not be able to test your APIs using browser as we do normally with JSON.
So I create a JUnit test and use WebClient to test the APIs as shown here.
@SpringBootTest
class RestAPIWithProtobufTest {
private WebClient webClient;
@BeforeAll
private void setWebClient(){
this.webClient = WebClient.builder()
.baseUrl("http://localhost:8080/person/")
.build();
}
@Test
void getPersonTest() {
StepVerifier.create(this.getPerson(1))
.expectNextCount(1)
.verifyComplete();
}
@Test
void savePersonTest() {
// create person
Person sam = Person.newBuilder()
.setName("sam")
.setAge(10)
.build();
// save
Mono<Void> mono = this.webClient.post()
.bodyValue(sam)
.retrieve()
.bodyToMono(Void.class);
// confirm if it saves
StepVerifier.create(mono)
.verifyComplete();
// retrieve and verify
StepVerifier.create(this.getPerson(2))
.expectNextMatches(p -> p.getAge() == 10)
.verifyComplete();
}
private Mono<Person> getPerson(int id){
return this.webClient.get()
.uri("{id}", id)
.retrieve()
.bodyToMono(Person.class)
.doOnNext(p -> System.out.println(p.toString()));
}
}
Summary:
We were able successfully demonstrate Spring WebFlux with Protobuf. I am able to GET Person object and POST a protobuf Person object successfully. Spring also allows to have both JSON and Protobuf messages in a same application which is interesting!
The source code is available here.
Learn more about WebFlux:
Happy coding 🙂