Monday, February 27, 2017

How i got started with Ballerina

I am certain most of my friend's would click on the link to see me dancing :)

With the announcement of Ballerina, the new integration language. I thought of writing a quick summary on how i got started. 

Installation 

I downloaded Ballerina from here. Also i referred Installation-instructions to get started.

Writing an EIP

CBR as a very common EIP in the integration world was something i tried out with Ballerina. So here's how i did it.  




Creating a Mock Service in Ballerina




Something i was longing to try out in Ballerina is to be able to write a service which could be executed in the same runtime. So here's how i did it, 


Started the composer, and viola it provided a graphical view for me to represent the service and what it should do and all i had to do was drag and drop a few elements to the canvas. This was like drawing a floor chart. 


the service i created would accept an incoming http message and send a mock respond back. The source view showed the language syntax i could use, here's how that looked like.

import ballerina.lang.messages;

@http:BasePath("/gadgets")
service GadgetInventoryMockService {
@http:GET
resource inquire(message m) {
message response = {};
json payload = `{"inquire":"gadget","availability":"true"}`;
messages:setJsonPayload(response, payload);
reply response;
}
}

Similarly i managed to create both the services ("Widget Inventory" and "Gadget Inventory").

Routing with Ballerina

Just like creating a service i was able to drag an drop a set of elements from the graphical view and create the router




import ballerina.net.http;
import ballerina.lang.jsons;
import ballerina.lang.messages;

@http:BasePath("/route")
service ContentBasedRouter {
@http:POST
resource lookup(message m) {
http:ClientConnector widgetEP = create http:ClientConnector("http://localhost:9090/widgets");
http:ClientConnector gadgetEP = create http:ClientConnector("http://localhost:9090/gadgets");
json requestMessage = messages:getJsonPayload(m);
string inventoryType = jsons:getString(requestMessage, "$.type");
message response = {};
if (inventoryType == "gadget") {
response = http:ClientConnector.get(gadgetEP, "/", m);
}
else {
response = http:ClientConnector.get(widgetEP, "/", m);
}
reply response;
}
}

While looking back i realize, it was not only convenient to create the message flow, but it was also easier for me to describe the flow through the diagram. The way it was describing the connections, the message flow and the client as seperate entities (the picture was actually speaking 1000 words :) ). 

Running What I Wrote 


I was excited to see how this diagram, would look like when it's running.

This is all what i had to do,


ballerina run service ./gadgetInventoryMockService.bal ./widgetInventoryMockService.bal ./router.bal

where, gadgetInventoryMockService.bal and widgetInventoryMockService.bal were the mock services i wrote and router.bal is the routing logic. In this case i would've preferred to actually be able to bundle the whole project into one package instead of having to give each an individual file as arguments. I checked on this capability with the team and this will be supported in the near future by the composer. So i'll have my fingers crossed for this. As a result in my local machine each of the bal files were running as a service in the following URLs. The files i used could be found here.


Service
URL
Gadget Inventory Mock Service
http://localhost:9090/gadgets
Widget Inventory Mock Service
http://localhost:9090/widgets
Router
http://localhost:9090/route


So to practically experience how Ballerina routed the requests i did the following, using cURL client i sent the following request, 

curl -v http://localhost:9090/route -d '{"type" : "gadget"}'


The following response should be observed,

{"inquire":"gadget","availability":"true"}

Re executed the request with the following,
curl -v http://localhost:9090/route -d '{"type" : "widget"}'

Then the following response should be observed,
{"inquire":"widget","availability":"true"}


In general there're more components i.e fork-join capability which will be required to implement some of the EIPs i wanted to try out i.e scatter-gather, so tick tock for the next release. However, it was a great experience.