Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to consume protobuf parameters using Spring REST?

I'm trying to pass a protobuf parameter to a REST endpoint but I get

org.springframework.web.client.HttpServerErrorException: 500 null

each time I try. What I have now is something like this:

@RestController
public class TestTaskEndpoint {

    @PostMapping(value = "/testTask", consumes = "application/x-protobuf", produces = "application/x-protobuf")
    TestTaskComplete processTestTask(TestTask testTask) {
        // TestTask is a generated protobuf class
        return generateResult(testTask);
    }
}


@Configuration
public class AppConfiguration {

    @Bean
    ProtobufHttpMessageConverter protobufHttpMessageConverter() {
        return new ProtobufHttpMessageConverter();
    }

}

@SpringBootApplication
public class JavaConnectorApplication {

    public static void main(String[] args) {
        SpringApplication.run(JavaConnectorApplication.class, args);
    }
}

and my test looks like this:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@WebAppConfiguration
public class JavaConnectorApplicationTest {


    @Configuration
    public static class RestClientConfiguration {

        @Bean
        RestTemplate restTemplate(ProtobufHttpMessageConverter hmc) {
            return new RestTemplate(Arrays.asList(hmc));
        }

        @Bean
        ProtobufHttpMessageConverter protobufHttpMessageConverter() {
            return new ProtobufHttpMessageConverter();
        }
    }

    @Autowired
    private RestTemplate restTemplate;

    private int port = 8081;

    @Test
    public void contextLoaded() {

        TestTask testTask = generateTestTask();

        final String url = "http://127.0.0.1:" + port + "/testTask/";
        ResponseEntity<TestTaskComplete> customer = restTemplate.postForEntity(url, testTask, TestTaskComplete.class);

        // ...

    }
}

I'm sure that it is something with the parameters because if I create a variant which does not take a protobuf parameter but returns one it just works fine. I tried debugging the controller code but the execution does not reach the method so the problem is probably somewhere else. How do I correctly parametrize this REST method?

like image 874
Adam Arold Avatar asked Oct 13 '16 14:10

Adam Arold


People also ask

Can you use protobuf with rest?

Yes, you can absolutely combine Protobuf and REST. Protbuf specifies a way to encode data. REST specifies a way to interact with resources, but does not require any particular encoding for the resource bodies.

How do I send protobuf over HTTP?

You can certainly send even a binary payload with an HTTP request, or in an HTTP response. Just write the bytes of the protocol buffer directly into the request/response, and make sure to set the content type to "application/octet-stream". The client, and server, should be able to take care of the rest easily.

Is protobuf more efficient than JSON?

JSON is usually easier to debug (the serialized format is human-readable) and easier to work with (no need to define message types, compile them, install additional libraries, etc.). Protobuf, on the other hand, usually compresses data better and has built-in protocol documentation via the schema.

Should I use protobuf or JSON?

Protobuf is mostly useful for internal services whereas JSON is mostly useful for web applications. Prior knowledge of schema is essential in decoding Protobuf messages, whereas data can be easily decoded or parsed in JSON with knowing schemas in advance.


1 Answers

This is my first stack overflow answer but I was a lot to frustred from searching for working examples with protobuf over http and spring.

the answer https://stackoverflow.com/a/44592469/15705964 from Jorge is nearly correct. Like the comments mention: "This won't work in itself. You need to add a converter somewhere at least."

Do it like this:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    ProtobufHttpMessageConverter protobufHttpMessageConverter;

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(protobufHttpMessageConverter);
    }

}

The ProtobufHttpMessageConverter will do his job automatically and add the object to your controller methode

@RestController
public class ProtobufController {

    @PostMapping(consumes = "application/x-protobuf", produces = "application/x-protobuf")
    public ResponseEntity<TestMessage.Response> handlePost(@RequestBody TestMessage.Request protobuf) {

    TestMessage.Response response = TestMessage.Response.newBuilder().setQuery("This is a protobuf server Response")
            .build();

    return ResponseEntity.ok(response);
}

Working example with send and reseive with rest take a look: https://github.com/Chriz42/spring-boot_protobuf_example

like image 120
Christian Giebel Avatar answered Sep 29 '22 12:09

Christian Giebel