Mulesoft: Twilio API Integration

mulesoft-logoplustwilio

Twilio is a cloud based communication company that enables users to use standard web languages to build voice, VoIP, and SMS apps via a web API. Twilio provides a simple hosted API and markup language for businesses to quickly build scalable, reliable and advanced voice and SMS communications applications. Twilio based telephony infrastructure enable web programmer to integrate real time phone call, SMS or VOIP to their application.

Mulesoft provides cloud connector to integrate Twilio Api within Mulesoft. Mulesoft Cloud connector provides a simple and easy way to integrate with these Twilio APIs, and then use them as services within Mulesoft. Mulesoft-Twilio connector provides a platform for developer to develop and integrate their application easily and quickly with Twilio.

Before start integration of Mulesoft with Twilio, create your Twilio account and get “ACCOUNT SID” and “AUTH TOKEN”.

twilio-account

Now download and install Twilio connector into Anypoint studio.

Anypoint Studio –>Help –>Install New Software

twilio-connector

Configure pom.xml to pull Twilio jar dependency in maven based project.

Add plugin in plugin section and dependency in pom.xml file. This section will also add into pom.xml file when Twilio connector drag into AnypointStudio canvas and use it into flow.

<plugin>
   <groupId>org.mule.tools.maven</groupId>
<artifactId>mule-app-maven-plugin</artifactId>
<version>${mule.tools.version}</version>
<extensions>true</extensions>
<configuration>
<copyToAppsDirectory>true</copyToAppsDirectory>
<inclusions>
<inclusion>
<groupId>org.mule.modules</groupId>
<artifactId>mule-module-apikit</artifactId>
</inclusion>
        <inclusion>
                   <groupId>org.mule.modules</groupId>
                   <artifactId>mule-module-twilio</artifactId>
         </inclusion>
     </inclusions>
</configuration>
</plugin>

Dependency tag

<dependency>
<groupId>org.mule.modules</groupId>
<artifactId>mule-module-twilio</artifactId>
<version>1.4</version>
</dependency>

Now configure Twilio Global Elements to connect your application with Twilio into Mule-config.xml file

<twilio:config name="Twilio" accountSid="${TwilioSID}" authToken="${TwilioAuthToken}" doc:name="Twilio">
<twilio:http-callback-config />
</twilio:config>

In above code TwilioSID and TwilioAuthToken are coming from Twilio account.

Mulesoft Twilio connector provides a  number of methods to integrate with your application. Below image show some of methods expose by Mulesoft-Twilio connector.

twilio-method

I am using “send SMS message” method form Mulesoft-Twilio connector for my example.

Now you can integrate Twilio to send SMS with your application. Here is example code.

<logger message="#[payload.recipientPhoneNumber]" level="INFO" doc:name="Logger"/>
<twilio:send-sms-message config-ref="Twilio" accountSid="${TwilioSID}" body="Hello World Sending SMS from Twilio" from="+15555555555" to="#[payload.recipientPhoneNumber]" doc:name="Twilio"/>

Twilio API does not support bulk SMS for recipient. So, to initiate messages to a list of recipients, you must make a request for each number to which you would like to send a message. The best way to do this is to build an array of the recipients and iterate through each phone number.

Here is small flow for Twilio integration.

twilio-flow

Code for this flow.

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:twilio="http://www.mulesoft.org/schema/mule/twilio" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/twilio http://www.mulesoft.org/schema/mule/twilio/current/mule-twilio.xsd">

<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
<twilio:config name="Twilio" accountSid="${TwilioSID}" authToken="${TwilioAuthToken}" doc:name="Twilio">
    <twilio:http-callback-config />
</twilio:config>
  <flow name="twilio-mulesoftFlow">
     <http:listener config-ref="HTTP_Listener_Configuration" path="/twilio" doc:name="HTTP"/>
     <set-payload value="" doc:name="Set Payload"/>
     <logger message="#[payload.recipientPhoneNumber]" level="INFO" doc:name="Logger"/>
     <twilio:send-sms-message config-ref="Twilio" acc#[payload.recipientPhoneNumber]: #339966;">${TwilioSID}" body="#[payload]" from="+15555555555" to="+12222222222" doc:name="Twilio"/>
  </flow>
</mule>

If you are getting exception, make sure twilio-mulesoft jar is in classpath and properly configured.

RAML:Schema Validation for APIs

Initially when REST was introduced there was always challenge to validate your request against prerequisite requirement. This was available in SOAP web services as XSD schema validation but it was not available in REST webservice. Architect and developer had to face the challeng to implement some kind of schema to validate their request.

YAML based RAML (Restful API modeling Language) was introduced in 2013. RAML gives flexibility to define schema to validation request/response. This breakthrough helps Architect and developer to define schema for REST API to validate request/response.

RAML schema validation can be defined in two formats.
1) XSD Based
2) Json Based.

Schema validation can be defined in two ways inside RAML
1) Inline schema definition
2) XSD or json schema definition file.

Schema definition can be defined in schema tag within RAML file.
“!Include” tag uses to include schema file for file based schema definition within RAML.
Json based schema definition

/car:
  post:
    description: Getting car info from Car Application
    body:
      application/json:
        schema: !include schemas/cars-schema-request.json 

XSD based schema definition

responses: 
      200:
        body:
          application/xml: 
              schema: !include schemas/vanrish-car-response.xsd

Inline definition of schema

/car:
  post:
    description: Getting car info from Car Application
    body:
      application/json:
        schema: |
	     {
             "type": "object",
             "$schema": "http://json-schema.org/draft-03/schema",
             "required": true,
             "properties": {              
              "vin": {
                  "type": "string",
                  "required": true
              },
              "model": {
                  "type": "string",
                  "required": true
              },
              "make": {
                  "type": "string",
                  "required": true              
              }
            }
          } 

Here are few tips to use json based schema validation.

1) If request/response is object based then in schema it is defined as type:Object .

"$schema": "http://json-schema.org/draft-03/schema",
"type": "object"

2) If request/response is list based then it is defined as

"$schema": "http://json-schema.org/draft-03/schema",
"type": "array",
"items": {

3) If request/response is list and it contain object, it is defined as

"items": {
  "type": "object",
  "properties": {
    "vin": {
      "type": "string"
}

4) Type of field for Object can be defined as string,integer, or boolean

"vin": {
  "type": "integer"
}

5) Field can be restricted for known value with defining enum

"isCdl": {
  "description": "State",
  "type": "string",
  "enum": [ "true", "false" ]
}

6) Field can be made mandatory by introducing required field

"name": {
  "type": "string",
  "required": true
}

7) Any field can be validated against regular expression by defining regex code

"deviceName": {
  "type": "string",
  "pattern": "^/dev/[^/]+(/[^/]+)*$"
}

8) Maximum and minimum field length can be validated with defining maxLength and minLength field

"id": {
  "description": "A three-letter id",
  "type": "string",
  "maxLength": 3,
  "minLength": 3
}

9) Reuse of validation by importing validated schema from different file system by defining like that

"credentials": { "$ref": "app-credential.json#/definitions/credential" }

10) anyOf, allOf, oneOf, not- these four keywords intend to bring logical processing primitives to Schema validation

{
  "anyOf": [
   { "type": [ "string", "boolean" ] },
   { "schema1": "#/definitions/nfs" },
   { "schema2": "#/definitions/pfs" }
 ]
}

Mulesoft Connector Devkit : Coding & Deployment

In my previous blog I explained configuration and setup for Mulesoft connector Devkit. In this blog I am going to explain how to write and deploy your connector. As I mentioned in my previous blog Devkit is a platform to develop Mulesoft connector. Devkit is very powerful tool to develop extreme complex connector or simple connector.

Here are few steps to develop Mulesoft connector.

1) Create project from anypoint studio

connector-project-create

2) Select SDK Based connector. This selection supports standalone java as well as REST based API. Once you select this selection below window will come. Name your connector project, select working directory and  then click next

connector-project-create-box

3)  Now next step you need to select maven Group Id and Artifact Id and click next.

4) Next step you need to select icon and logo for your connector then click finish.
connector-project-icon-select

After clicking finish connector project will generate.

Two java files are generated in your connector project. Here my project name is Vanrish, so it generated VanrishConnector.java and ConnectorConfig.java.

Generated VanrishConnector.java 


@Connector(name="vanrish", friendlyName="Vanrish")

public class VanrishConnector {
 
@Config
ConnectorConfig config;
 

In this code snippet annotation defines your connector name and display name. In above annotation “name” is for connector name and “friendlyName” will display connector name once you install this connector in Anypoint studio. This annotated class is main class for creating connector

In 2nd line we are initiating config class to add all configuration related with this connector.

If you are adding any method to execute this connector you need to define your method with  @Processor annotated method.


@Processor
public String getVehicleInfo(String deviceId) throws Exception {
return "Hello World"+deviceId;
}

Here is Full code snippet for this class


package org.mule.modules.vanrish;

import org.mule.api.annotations.Config;
import org.mule.api.annotations.Connector;
import org.mule.api.annotations.Processor;
import org.mule.api.annotations.lifecycle.Start;
import org.mule.api.annotations.oauth.OAuthProtected;
import org.mule.modules.vanrish.config.ConnectorConfig;

@Connector(name = "vanrish", friendlyName = "Vanrish")
public class VanrishConnector {

 @Config
 ConnectorConfig config;

 @Start
 public void init() {
 }

 public ConnectorConfig getConfig() {
  return config;
 }

 public void setConfig(ConnectorConfig config) {
  this.config = config;
 }

 @Processor
 public String getVehicleInfo(String deviceId) throws Exception {
  return "Hello World" + deviceId;
 }
}

Now in 2nd class we define connector configuration. This class is annotated with @Configuration

In this class I defined couple of methods to access external REST api for this connector.

I define apiURL and their version to use inside my annotated method


@Configurable
@Optional
@Default("https://platform.vanrish.com/api")
private String apiUrl;

@Configurable
@Optional
@Default("v1")
private String apiVersion;

Here are annotation definition for connector
@Configurable — Allow to configure this field
@Optional —This field is not mandatory
@Default —This is providing default value for field

Here is full code snippet


package org.mule.modules.vanrish.config;

import org.mule.api.annotations.components.Configuration;
import org.mule.api.annotations.Configurable;
import org.mule.api.annotations.param.Default;
import org.mule.api.annotations.param.Optional;

@Configuration(friendlyName = "Configuration")
public class ConnectorConfig {

/**

* Vanrish API Url

*/

 @Configurable
 @Optional
 @Default("https://platform.vanrish.com/api")
 private String apiUrl;

 @Configurable
 @Optional
 @Default("v1")
 private String apiVersion;

 public String getApiUrl() {
  return apiUrl;
 }

 public void setApiUrl(String apiUrl) {
  this.apiUrl = apiUrl;
 }

 public String getApiVersion() {
  return apiVersion;
 }

 public void setApiVersion(String apiVersion) {
  this.apiVersion = apiVersion;
 }
}

In advance connector writing you can create client java class and use above apiURL and version to access api method and execute to get result.

Now to build this project in Anypoint studio, you need to select project and right click. This action will pop up option window. Here in this window you need to select Anypoint Connector then click Build connector.

Steps —  Right Click on project –>Anypoint Connector –> Build Connector
Here it is shown in the picture below
connector-project-build

This action will build your connector.

Follow the same steps to install your connector into Anypoint studio.
Steps — Right Click on project –> Anypoint Connector –> Install or Update
This action will install your connector into Anypoint studio.

After installing your connector,you can search your connector name into Anypoint studio.

vanrish-connector

Connector Testing
you can create small flow in Anypoint studio and test your connecotor.

Here is example to test my connector
vanrish-connector-flow

DataWeave:A New Era in Mulesoft

Dataweave is a new data mapping tool which comes with MuleSoft 3.7 run time. Before Mule 3.7 runtime, Datamapper was there for data mapping. Dataweave inherit some of the functionality from Datamapper but due to restriction of complex mapping in Datamapper, Dataweave emerged with Mulsesoft 3.7 runtime.
There are three section of Dataweave.
1) Input
2) Output
3) Data transformation language

Data transformation language is based on JSON like language. If you are familiar with JSON, it is very easy to write Dataweave transformation logic and maintain this logic.

Here are some tips to write and maintain Dataweave transformation logic.

1)   Default Output of Dataweave Transformation is set into payload. But you can easily     change from dropdown and set this output as variable or session variable
dataweave

2) Output of transformed data you can easily define in Dataweave. If you are transforming data into XML you just need to define as “ %output application/xml” without touching underline transformation logic. Same way if you are transforming your data into json or any other format you just need to define output like without touching underline transformation logic as “ %output application/json”, “ %output application/java”, “ %output application/csv”..

%dw 1.0
%output application/xml
%namespace ns0 http://schemas.vanrish.com/2010/01/ldaa

3)  Dataweave transformation logic gives leverage to skip any null field during data transformation. This is only declarative. Here is declaration to skipping null fields everywhere during transformation skipNullOn=”everywhere”

%dw 1.0
%output application/xml skipNullOn=”everywhere”
%namespace ns0 http://schemas.vanrish.com/2010/01/ldaa


4)  Dataweave transformation allows to access flowVars and sessionVars directly into transformation field.

orderParameter:{
         name:“MINOR_LI_ID”,
         value:flowVars.payloadVar.minorLiId
}

5)  Dataweave transformation reads properties value directly from properties file. You can access properties value in Dataweave like you are accessing during flow.

teamName:“$($.teameName)${teamNameSuffice},
  teamNameSuffice is defined in properties file.

6)  Dataweave transformation allows implementing condition logic for each field. It is very easy to implement and transform your data based on these condition logic. Here is example to implement to condition logic for field partnershipType.

partnershipType:“NEW” when $.partnership-type==”NEW”
                            otherwise “USED” when $.partnership-type==”USED”
                            otherwise “EM” when $.partnership-type==”EM”
                            otherwise “PU” when $.partnership-type==”PU”
                            otherwise “PN” when $.partnership-type==”PN”
                            otherwise $.partnership-type,
Here is another example

creativeType:“GRAPHIC” when ($.creative-type == “GRAPHIC” or $.creative-type == null)
                         otherwise “TEMPLATED_AD” when $.creative-type == “TEMP_AD”
                         otherwise “AD_TAG” when $.creative-type == “AD_TAG”
                         otherwise “”,

7)  During Dataweave transformation logic you can call global function and transform your field based on these function output. This is one of the ways you can call java object into Dataweave transformation.

Here is example
global-functions is tag for mule-config file where you can define function for entire mule flow

<global-functions>

def toUUID() {
return java.util.UUID.randomUUID().toString()
}

def getImageType(imageName) {
return imageName.substring(imageName.lastIndexOf(‘.’)+1)
}

</global-functions>

Now you can call this function inside Dataweave transformation logic.

 imageType:getImageType($.origin-name as :string) when $.origin-name != null otherwise “”,

Mulesoft:Flow Execution Time

Mulesoft application is based on flows. Every flow has their own execution time. We can calculate this flow execution is couple of ways. But Mulesoft provides one of the easy way to calculate this flow execution time by using interceptor . Timer interceptor (<timer-interceptor/>) is one of the mule interceptor to calculate Mulesoft flow execution time.

Here is flow diagram for timer-interceptor

muleTimerInterceptorFlow

Here is code for timer-interceptor to implement in your application


<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"       xmlns:spring="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsdhttp://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">

<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" basePath="/demo" doc:name="HTTP Listener Configuration"/>

<flow name="muleTimerInterceptorFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>               <timer-interceptor/>
     <set-payload doc:name="Set Payload" value="Hello World"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
</flow>
</mule>

 <timer-interceptor/> tag display time in milliseconds.

You can customize flow execution time to replace <timer-interceptor/>  with  <custom-interceptor>.
In this custom interceptor you need to mention your custom interceptor java class.

<custom-interceptor class=”com.vanrish.interceptor.TimerInterceptor” />

Here is flow diagram for custom timer-interceptor

muleTimerCustomInterceptorFlow

Here is mule-config.xml  code for custom timer-interceptor


<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"       xmlns:spring="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">

<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" basePath="/demo" doc:name="HTTP Listener Configuration"/>

<flow name="muleTimerInterceptorFlow">

<http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>

 <custom-interceptor class="com.vanrish.interceptor.TimerInterceptor" />

<set-payload doc:name="Set Payload" value="Hello World"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
</flow>
</mule>

Java TimerInterceptor  code for custom timer-interceptor tag


package com.vanrish.interceptor;

 

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.interceptor.Interceptor;
import org.mule.processor.AbstractInterceptingMessageProcessor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* <code>TimerInterceptor</code> simply times and displays the time taken to
* process an event.

*/

public class TimerInterceptor extends AbstractInterceptingMessageProcessor

implements Interceptor {

/**

* logger used by this class

*/

private static Log logger = LogFactory.getLog(TimerInterceptor.class);

public MuleEvent process(MuleEvent event) throws MuleException {
long startTime = System.currentTimeMillis();
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date stdate = new Date();
String start = dateFormat.format(stdate);
System.out.println(start);

MuleEvent resultEvent = processNext(event);

Date enddate = new Date();
String end = dateFormat.format(enddate);

if (logger.isInfoEnabled()) {

long executionTime = System.currentTimeMillis() - startTime;
            logger.info("Custom Timer : "+resultEvent.getFlowConstruct().getName() + " Start at "+start+" and end at "+end +" it took " + executionTime + "ms to process event ["                   + resultEvent.getId() + "]");
}
return resultEvent;
}
}