Building a Client-Server Application using Docker/RabbitMQ and Java/Spring Boot - Part 2

##Part 2 ###Step 1 - The REST API

The first step is to build the basic App. Since this will connected to from a Node.js based front-end a REST API is the obvious choice plus the Spring Boot website has an easy tutorial and git repo that will get us started.

To start pull down the spring-boot repo with the following command:

git clone https://github.com/spring-guides/gs-rest-service.git

Note: you will need git installed for this command to work.

First things first. Create a test.

@Test
public void testVPSAPIRoute() throws Exception {
    this.mockMvc.perform(get("/api/1.0/vpsmanager/").param("test", "content"))
            .andDo(print()).andExpect(status().isOk());
}

Now that we have a test we need a route in the controller.

@RequestMapping("/api/1.0/vpsmanager")
public Greeting vpsmanager(@RequestParam(value="name", defaultValue="World") String name) {
    return new Greeting(counter.incrementAndGet(),
            String.format(template, name));
}

Assuming everything else is configured correctly the tests should now run.

###Step 2 - RabbitMQ

Next to create some tests for RabbitMQ connectivity.

package com.vpsmanager;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

import static org.junit.Assert.*;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class RabbitMQTests {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private Sender sender;

    @Autowired
    private Receiver receiver;

    @Test
    public void createQueueTest() {
        assertEquals(sender.createQueue(), "spring-boot");
        rabbitTemplate.receive("spring-boot", 1);
    }

    @Test
    public void publishToQueueAndRecieve() {
        assertEquals("success", sender.publishItem("myitem"));
        assertEquals("myitem" , receiver.getQueueItem());
    }

}

Now to write the code. I've split this up into a Sender and Reciever class. You can put these together however I prefer things a little cleaner. ###Sender Class

package com.vpsmanager;

import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class Sender {
    private String queueName = "spring-boot";

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Bean
    @Value("${this.queueName}")
    private Queue queue() {
        return new Queue(this.queueName);
    }

    public String createQueue() {
        Queue queueReturn = queue();
        return queueReturn.getName();
    }

    public String publishItem(String item) {
        Queue queue = new Queue(this.queueName);
        rabbitTemplate.convertAndSend(queue.getName(), item);
        return "success";
    }
}

###Reciever Class

package com.vpsmanager;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Receiver {
    private String queueName = "spring-boot";

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public String getQueueItem() {
        byte[] body = rabbitTemplate.receive(this.queueName).getBody();
        return new String(body);
    }
}

Next we will put them both together. And again we start with some more tests.

@Test
public void testVPSAPIRoute() throws Exception {
    this.mockMvc.perform(get("/api/1.0/vpsmanager/").param("test", "content"))
            .andDo(print()).andExpect(status().isOk());
}

@Test
public void testVPSAPIRouteWithRabbitReturn() throws Exception {
    this.mockMvc.perform(get("/api/1.0/addtoqueue/").param("queue", "spring-boot").param("value", "mytestpayload"))
            .andDo(print()).andExpect(status().isOk())
            .andExpect(jsonPath("$.content").value("success"));
    this.mockMvc.perform(get("/api/1.0/getrabbitresponse/").param("queue", "spring-boot"))
            .andDo(print()).andExpect(status().isOk())
            .andExpect(jsonPath("$.content").value("mytestpayload"));
}

And now the controller should look something like this.

package com.vpsmanager;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class VPSController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private Sender sender;

    @Autowired
    private Receiver receiver;

    @RequestMapping("/api/1.0/vpsmanager")
    public VPSManager vpsmanager(@RequestParam(value="name", defaultValue="World") String name) {
        return new VPSManager(1,"test");
    }

    @RequestMapping("/api/1.0/addtoqueue")
    public VPSManager vpsManager(@RequestParam(value="value", defaultValue = "spring-boot") String name) {
        return new VPSManager(1, sender.publishItem(name));
    }

    @RequestMapping("/api/1.0/getrabbitresponse")
    public VPSManager rabbitResponse(@RequestParam(value = "name", defaultValue = "RabbitMQ") String name) {
        return new VPSManager(1, receiver.getQueueItem());
    }
}

All done. You should now have a working API with RabbitMQ.

Copyright © 2020 | Ben Hutton