Send messages to an Amazon SQS queue using Spring Boot

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:

  1. Create a queue in Amazon SQS
  2. Set up a Spring Boot app with Amazon SQS
  3. Send messages to an Amazon SQS queue using Spring Boot
  4. 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.

Sending the message request to the queue with Postman
Postman POST Request to send a quote to the queue

To see the quote in AWS:

  1. Go to the SQS Management Console.
  2. Select the queue.
  3. Under Queue Actions select to View/Delete Messages.
  4. Click on Start Polling for Messages.
AWS SQS Management Console showing message in queue
Quote sent as seen on AWS SQS Management Console

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:

Running test using IntelliJ IDEA
Running test using IntelliJ IDEA

Code

The code for this application is available on GitHub.

Leave a Comment