Outbound SMS Service

Introduction

in this article, we will build the Outbound SMS Service. This servicese provide a simple outbound SMS client that allows the application to send text messages. It is structurally similar to the OutboundEmailService created in the previous two articles. The primary differences between the two services exists in the REST controllers and the service class.

For this implementation, we will be using Twilio as our SMS service provider. They provide a free trial which gives you an opportunity to exercise the OutboundSMSService without spending any money.

Requirements

Before you get started, you will need the following:
  • Java
  • Maven
  • Docker
  • Docker-Compose
Refer to the Development Toolbox article if you do not have these installed locally.

Building the Outbound SMS Service

Since the OutboundSMSService is so similar to the OutboundEmailService, we will be focusing on just the REST controller, Message Queue Listener, OutboundSMSService interface, and the TwilioOutboundSmsServiceImpl components in this article. If you have not read the previous two articles detailing the OutboundEmailService, we strongly suggest reading them prior to this article.

The Source

Maven pom.xml

loading...

The major difference between the OutboundSMSService pom.xml and its OutboundEmailService is the addition of the Twilio dependency, and the removal of the spring-boot-starter-mail dependency

Configuration Files

bootstrap.yml

loading...

application.yml

loading...

As we did in the OutboundEmailService, we configure the message queue name ( cloud.stream.bindings.input.destination=SmsMessages) and the group name ( cloud.stream.bindings.input.group=smsMessagesGroup).

twilio.yml

loading...

Here we include the Twilio authID and accountSID configuration that is used by the TwilioOutboundSmsServiceImpl.

Outbound SMS models

Sms Request

loading...


MMS Request

loading...

Services

We start by defining the OutboundSmsService interface.

Outbound Sms Service

loading...

The interface defines two methods, a sendSmsMessage(...) and a sendMmsMessage(...).

Twilio Configuration Properties

We provide a separate configuration file specificially for the Twilio service implementation.

loading...

The class is annotated with @ConfigurationProperties to instruct the framework to load it when it loads the application configuration properties. The @PropertySource("classpath:twilio") instructs the framework where to load the configuration properties from.

Twilio Outbound Sms Service Impl

loading...

A class-level annotation ( @Service) is supplied to mark this as an implemention of the OutboundSmsService. We then @Autowire the TwilioConfigurationProperties. Both the sendSmsMessage(...) and the sendMmsMessage(...):
  • Call the initTwilio method to set the configuration AccountSID & authID
  • Call Twilio's Message.creator static method with appropriate values
  • Call the create() method which initiates sending the message.

  • External API

    The service API consists of a REST endpoint and a Message endpoint.

    REST controller

    loading...

    The OutboundSMSController provides a REST endpoint that is invoked to send SMS and MMS messages.

    Message Queue Listener

    loading...

    The SMSQueueListener binds to the SmsMessages.smsMessageGroup queue, and inspects incoming messages Type header for routing information. Messages containing the the Type header SMS and MMS messages are routed to the processSmsMessage and processMmsMessage methodmethods respectively.

    Metric Collection

    The Outbound Email Service collects to metrics:

    • outbound.sms.plain- Counts the number of email sent without attachments.
    • outbound.sms.attachment- Counts the number of email sent with attachments

    Docker-Compose

    We continue the process of extending our previous Docker-Compose file:

    loading...

    Here we add the outbound-sms-service and override any environment-specific configuration parameters.

    Outbound SMS Service in action

    We can copy the Docker-Compose file above to your local machine and run it from the command prompt:

    $ docker-compose -f ./dc-06-outbound-sms.yml up -d

    Exercising the Swagger Interface

    When all the services have started, navigate to the following url: http://localhost:6020/swagger-ui.html



    Click on the outbound-sms-controller option.



    Click on the /sendSMS option.



    The /sendSMS method accepts two parameters-
    • Accept-Language- this is an optional parameter that we can pass to instruct the service's I18N resolver to internationalize the service's error response. This field will set the request's Accept-Language header value. If no value is set, or the value is not a supported language code, the service will respond with its default values.
    • Request- This parameter is the JSON representation of the request model.
    Click the Try it out .



    Now the interface will display input fields where we can enter our test data. In the request field you will see an editable JSON template, and we can modify the values to suit our needs. The sourceNumber must be the number assigned to your Twilio account. The destinationNumber is the receiver of the text. If you are using a trial Twilio account, you can only send messages to a verified number that must be configured in the Twilio administration interface.

    Once we have edited the parameters we can click the Execute button which will call the REST endpoint.



    Once the call has completed, the Swagger UI will display the results of the request.

    Excercising the Message Listener from the RabbitMQ web admin console

    Now that we have demonstrated the REST endpoint, we can turn our attention to the message-driven interface. Of course we have to ask how can we test a message consumer when we haven't built a message producer? As luck would have it, we actually have a way to send a message to our OutboundSmsService. When we deployed the RabbitMQ service container, we configured it to provide access to its web-based administration tool. In addition to monitoring the message broker, the administration tool provides a mechanism for us to enqueue messages. We start by opening a browser window and navigating to http://localhost:15672/.





    We authenticate with the credentials we set in the application.yml or we pass in through our Docker-Compose file. The default username/password credentials for the reference implementation are think/microservices



    Once you have entered your credentials you should see the RabbitMQ administration tool's Overview tab.



    This tab provides the landing page for the administration tool. We won't stay here for long though. Click on the Queues tab.



    Unfortunately, since we don't have a message producer yet, we will have to create message queue manually.



    Fortunately, RabbitMQ makes this fairly trivial. We simply complete the Add a new queue form, entering SmsMessages.smsMessageGroup as the queue name, set Durability to Durable, and set Auto Delete to No, then press the Add Queue button.



    We now have a message queue that we can publish messages to, and our OutboundEmailService can consume from. Click on the EmailMessages.emailMessageGroup to view the queue details:



    From this page we can monitor the queue's activity, and more importantly, publish a message. Select the Publish message option to display the input form:



    To publish a message to the queue:

    • Set the Delivery mode to 1 - Non-persistent.
    • Set the Header field to type and its value to SMS
    • Then set the Payload with the JSON message in the format:

      {
          "sourceNumber": "xxxxxxxxxx",
          "destinationNumber": "yyyyyyyyyy",
          "message": "this is an outbound message"
      }
      
    • Now press the Publish Message several times in quick succession to enqueue several email messages.



    We can see the message publishing activity reflected in the Message rates chart above. To verify that the message was actually sent, you can either check the Twilio usage logs, or simply verify the message was received on the device associated with the destinationNumber.

    Metrics and Monitoring

    The Outbound SMS Service will also contain the following service-level metrics to:

    • outbound.sms.send.total
    • outbound.mms.send.total
    This will allow us to monitor the number of SMS/MMS messages that are being sent from the service.

    To visualize this data we will import the OutboundSMSDashboard.json file from the ThinkMicroservices Github Dashboards repository. The dashboard should appear as:

    Grafana Outbound SMS Dashboard

    Resources



    Coming Up

    We have now implemented two messaging mechanisms. One for email and one for SMS/MMS. In our next article we will build the Notification Service which exposes a REST endpoint facade over the two messaging mechanisms and queues the incoming messages rather than call the service directly.