2factor SMS in Spring Boot App

Upasana | July 11, 2020 | 3 min read | 87 views


Send 2factor transactional sms in Spring Boot application using Java 11 HttpClient, OkHttp Client and RestTemplate

First of all make sure that you have an active account at https://2factor.in and have SMS templates configured/approved for use. You need to get Api Key from 2factor in order to send SMS programmatically.

Perquisites

Creating Spring Boot project

We can quickly create a gradle based spring boot starter using https://start.spring.io/

build.gradle
plugins {
    id 'org.springframework.boot' version '2.3.0.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

test {
    useJUnitPlatform()
}

we will use three different clients to communicate to 2factor API in this tutorial:

  • Java 11 HttpClient

  • OkHttp Client

  • Spring restTemplate

Java 11 HttpClient

Java 11 ships inbuilt Java HttpClient that can be used for making remote service calls.

First of all we will create a single HttpClient bean which will be reused across components for making remote calls.

HttpClientConfig.java - Create a bean of type HttpClient
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.http.HttpClient;

@Configuration
public class HttpClientConfig {

    @Bean
    public HttpClient createClient() {
        HttpClient client = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_2)
                .followRedirects(HttpClient.Redirect.NORMAL)
                .build();
        return client;
    }
}

Now we will create a service that used HttpClient to send a transactional SMS using 2factor service provider.

Service.kt to send SMS
@Service
class Scratch (private val httpClient: HttpClient) {

    fun sendSms() {
        val apiKey = "<insert your api key here>"
        val data: MutableMap<String, String> = HashMap()
        data["To"] = "mobile"
        data["From"] = "SHUNYA"
        data["TemplateName"] = "TEMPLATE-NAME"
        data["VAR1"] = "1234"
        data["VAR2"] = "testhash"

        val request: HttpRequest = HttpRequest.newBuilder()
                .POST(ofFormData(data))
                .uri(URI.create("https://2factor.in/API/V1/$apiKey/ADDON_SERVICES/SEND/TSMS"))
                .header("User-Agent", "Java 11 HttpClient")
                .header("Content-Type", "application/x-www-form-urlencoded")
                .build()
        val response: HttpResponse<String> = httpClient.send(request, HttpResponse.BodyHandlers.ofString())

        println(response.statusCode())
        println(response.body())
    }

    fun ofFormData(data: Map<String, String>): BodyPublisher? {
        val builder = StringBuilder()
        for ((key, value) in data) {
            if (builder.isNotEmpty()) {
                builder.append("&")
            }
            builder.append(URLEncoder.encode(key, StandardCharsets.UTF_8))
            builder.append("=")
            builder.append(URLEncoder.encode(value, StandardCharsets.UTF_8))
        }
        return HttpRequest.BodyPublishers.ofString(builder.toString())
    }

}

OkHttpClient

We will create a OkHttpClient bean that will be used across the project wherever necessary, using dependency injection.

OkHttpConfig.kt
@Configuration
class OkHttpConfig {

    @Bean
    fun okHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .addInterceptor(HttpLoggingInterceptor())
                .build()
    }
}

Now in order to send SMS using 2factor service provider, we will develop a component that used OkHttpClient bean to make remote service call.

Scratch.kt - service to send sms
class Scratch (private val okHttpClient: OkHttpClient){

    fun sendSms() {
        try {
            val apiKey = "<insert API key here>"
            val build = MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("To", "mobile")
                    .addFormDataPart("From", "SHUNYA")
                    .addFormDataPart("TemplateName", "TEMPLATE-NAME")
                    .addFormDataPart("VAR1", otp)
                    .build()
            val request = Request.Builder()
                    .url("https://2factor.in/API/V1/$apiKey/ADDON_SERVICES/SEND/TSMS")
                    .post(build)
                    .build()

            okHttpClient.newCall(request).execute().use { response ->
                if (!response.isSuccessful) {
                    logger.warn("Error sending SMS {}", response.body?.string())
                    throw IOException("Unexpected code $response")
                }
                logger.info("SMS Status - {}", response.body?.string())
            }
        } catch (e: Exception) {
            logger.warn("Error sending SMS", e)
            throw e
        }
    }
}

RestTemplate

We will use RestTemplate to fetch balance of SMS from 2factor account.

Fetch promotional balance
fun getPromoBalance() {
    val restTemplate= RestTemplate()
    val responseEntity = restTemplate.exchange("http://2factor.in/API/V1/$apiKey/ADDON_SERVICES/BAL/PROMOTIONAL_SMS", HttpMethod.GET, HttpEntity.EMPTY, String::class.java)
    if (responseEntity.statusCode.is2xxSuccessful) {
        val body = responseEntity.body
        logger.info("Promotional SMS Balance is {}", body)
    }
}

Top articles in this category:
  1. Using Asciidoctor in Java and Spring Boot
  2. how to enable asciimath formula using mathjax in asciidoctorJ
  3. Asciidoc: How to use nofollow option in asciidoc document
  4. Reverting default shell to bash from Zsh in Mac OS Catalina
  5. Integrating PayUmoney with your Java Server Side
  6. Integrating PayUmoney Webhooks with your Java backend

Recommended books for interview preparation:

Find more on this topic: