In this article we’ll use Spring Boot to create an endpoint that can send messages to an Amazon Simple Queue Service (SQS) queue. In our application messages will consist of famous quotes.
Amazon SQS and Spring Series
This article is part of a series:
- Create a queue in Amazon SQS
- Set up a Spring Boot app with Amazon SQS
- Send messages to an Amazon SQS queue using Spring Boot
- Receive messages from an Amazon SQS queue using Spring Boot
Create a class for the quote message
The following Data Transfer Object (DTO) defines the contents of the quote message. The text field is mandatory.
package com.makolyte.springsqsstarter.dto;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.NotNull;
public class Quote {
@NotNull
private final String text;
private final String author;
@JsonCreator
public Quote(@JsonProperty("text") String text, @JsonProperty("author") String author) {
this.text = text;
this.author = author;
}
public String getText() {
return text;
}
public String getAuthor() {
return author;
}
@Override
public String toString() {
return "Quote{" +
"text='" + text + '\'' +
", author='" + author + '\'' +
'}';
}
}
Code language: Java (java)
Configure the QueueMessagingTemplate
We’re going to utilize a QueueMessagingTemplate to send the quote. This class contains various methods for sending and receiving messages to/from an Amazon queue. Before using the class, we need to configure it, so it can connect to Amazon SQS.
package com.makolyte.springsqsstarter;
import com.amazonaws.services.sqs.AmazonSQSAsync;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.aws.core.env.ResourceIdResolver;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class SpringSqsStarterApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSqsStarterApplication.class, args);
}
@Bean
public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSQSAsync, ResourceIdResolver resourceIdResolver) {
return new QueueMessagingTemplate(amazonSQSAsync, resourceIdResolver);
}
}
Code language: Java (java)
We’re creating a bean in the main application class with the necessary configuration:
- The AmazonSQSAsync parameter is automatically created and passed based on the Amazon credentials defined in application.properties.
- Since our app is running inside a CloudFormation stack, we’re also passing a ResourceIdResolver to convert logical resource IDs (e.g. the queue name such as “QuoteQueue”) to physical resource IDs used by AWS to uniquely identify resources (e.g. 53DRALVWT774).
Create an endpoint to send messages
Next, we define a POST endpoint to send a quote. We’re adding @Valid so the quote is validated before it’s sent to the queue (e.g. it verifies the text field is present). We use the QueueMessagingTemplate class we configured previously to convert and send the message.
package com.makolyte.springsqsstarter.controller;
import com.makolyte.springsqsstarter.model.Quote;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping("/sqs")
public class SqsController {
private static final Logger LOG = LoggerFactory.getLogger(SqsController.class);
private final QueueMessagingTemplate queueMessagingTemplate;
public SqsController(QueueMessagingTemplate queueMessagingTemplate) {
this.queueMessagingTemplate = queueMessagingTemplate;
}
@PostMapping("/quotes")
@ResponseStatus(HttpStatus.CREATED)
public void sendQuote(@RequestBody @Valid Quote quote) {
LOG.info("Sending quote {} to SQS", quote);
this.queueMessagingTemplate.convertAndSend("QuoteQueue", quote);
}
}
Code language: Java (java)
Start the app and you can send a request to the new endpoint using a tool such as Postman.
To see the quote in AWS:
- Go to the SQS Management Console.
- Select the queue.
- Under Queue Actions select to View/Delete Messages.
- Click on Start Polling for Messages.
Add tests
We can write an integration test for the send quote endpoint using @WebMvcTest and MockMvc. I’m using @WebMvcTest because it instantiates only the web layer instead of the entire application context.
The following test verifies that we can call the endpoint passing in a quote and that we get a 201 (Created) status code back.
package com.makolyte.springsqsstarter.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.makolyte.springsqsstarter.dto.Quote;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest
class SqsControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private QueueMessagingTemplate queueMessagingTemplate;
@Test
public void sendQuoteToSqs() throws Exception {
ObjectMapper mapper = new ObjectMapper();
Quote q = new Quote(
"With the new day comes new strength and new thoughts.",
"Eleanor Roosevelt"
);
String json = mapper.writeValueAsString(q);
mockMvc.perform(post("/sqs/quotes")
.content(json)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isCreated());
}
}
Code language: Java (java)
You can run the test on the command line using Maven or in your IDE:
Code
The code for this application is available on GitHub.