Tuesday, July 11, 2017

Automating container environments for testing microservices

Testing microservices is a fundamental task in a microservice oriented system and containerization offers a great opportunity for automating it. Containers can be created and connected on demand, thus they provide the perfect environment where performing tests because it can be created and then destroyed when the tests are terminated. Moreover, we could create a testing environment system which is the exact copy of the production one.

In my previous post I showed Jocker, a Jolie component able to interact with Docker by offering a subset of its functionalities as Jolie operations instead of REST ones. In this post I am going to exploit Jocker for automatizing a test on a simple Jolie microservice by orchestrating it from another jolie orchestrator. In order to do that I will use a simple example you can find in the jocker git repo under the folder: ExampleOrchestrator/TestingDBSystem

The system under test
The system under test is very simple and it is just represented by a microservice connected with a PostgreSQL database.



You can find the code of this simple Jolie microservice here. As you can see, this microservice has only one RequestResponse operation called getContent which is in charge to select the field of a row (field2) from table testTable of the DB depending on the value of column field1. Very simple.

Orchestrating the Test
Now, I'll show you how to test the microservice by checking if it properly returns the correct responses when some request messages are sent. In order to do so I use this simple orchestrator for interacting with Jocker which executes all the actions I need. In particular, the orchestrator performs three main activities:
  • Preparation of the testing environment
  • Test execution
  • Removal of the testing environment
Preparation of the testing environment
The main idea is to prepare the testing environment by creating a container for each basic component of the system. Here we have two basic components: the PostgreSQL database and the Jolie microservice.

The PostgreSQL Database container is obtained in the following way:
  1. pulling down the postgresql image from docker hub
  2. creating the corresponding container
  3. starting the container
  4. initializing the database we need by creating it from scratch
  5. initializing the required known data into the database
Steps 4 and 5 could be skipped if we consider to already have a postgresql test image with a pre-installed database initialized with the required data.

On the other hand, the Jolie microservice image can be built by following the same steps explained here. In particular:

  1. a temporary directory is created and all the content of the ServiceToTest folder is copied in. 
  2. a Dockerfile is dynamically created and added to the temporary folder
  3. a tar file of the temporary folder is created 
  4. a docker image of the microservice is created invoking Jocker
  5. a container is created starting from that image
  6. the container is started
The final environment is a system like the following one where the two basic components are now encapsulated within two different containers:




Test execution
The test execution is a very simple phase because the orchestrator just sends all the requests I want to test to the microservice inputPort and checks if the results are like expected. For the sake of this example there is only one request to test but, clearly, they can be hundreds depending on the operations to test and the variety of data to be considered.

Removal of the testing environment
When the test is done, I don't need the test environment any more and I can destroy it. In particular:
  1. I stop the two containers
  2. I remove the two containers 
  3. I remove the two images (in reality, as you can see in the code, I do not remove the postgresql image just because it takes time for pulling it down from the docker hub, but it is up to you).

Some interesting notes
  • In this example we do not exploit the possibility to create links among different docker containers but we directly call the container on the ports they provide. In order to do this, once a container is created we also query Jocker in order to get their info details for extracting the local IP assigned by Docker to them. We will use these IPs as reference hosts for connecting the microservice with the PostgreSQL database and the tests to the microservice.
  • In order to run the example it is sufficient to run the jocker container as described here and the run the orchestrator placed in the folder  ExampleOrchestrator/TestingDBSystem by using the following command

    jolie orchestrator.ol

Conclusions
I hope this post could be of inspirations for all those software engineers who are addressing testing issues with microservices and containers. Let me know if you have questions or doubts.













Thursday, July 6, 2017

Jocker: orchestrating Docker containers with Jolie

recently we spent time in integrating Jolie and Docker. Our idea was very simple: since Jolie is a very good language for orchestrating microservices in general, why not use it also for orchestrating docker containers??

Thanks to Andrea Junior Berselli who started to work on this topic during his University degree at the University of Bologna, we can now say that a first component able to integrate Docker with Jolie exists! Its name is Jocker [github project]!

How does Jocker work?
Jocker is a jolie microservice which is able to call the REST API of Docker (we implemented only a subset so far) and it offers them as simple jolie operations thus avoiding to deal with all the details related to rest json calls. Here you can see the jolie interface of Jocker. The architecture is very simple:


Jocker must be executed in the same machine where docker server is running. It is communicating by exploiting localsocket //var/run/docker.sock and it will supply jolie operations in the default location localhost:8008 with protocol sodep.

Jocker container
The easy way for running jocker is to pulling down its container and then starting it. The Jocker image is available at jolielang section on Docker Hub and it can easily pulled down by using the followingcommand:

docker pull jolielang/jocker

When pulled down run the following command for executing it:

docker run -d -v /var/run/docker.sock:/var/run/docker.sock -p 8008:8008 jolielang/jocker

Jocker from sources
If you want to run Jocker from sources, you need some extra steps before continuining:
  • you need to install Jolie in your machine 
  • you need to install libmatthew Java libraries in order to enable localsockets.
Running Jocker is very simple, just go into the jocker folder and then type the followin command:

jolie dockerAPI.ol

Jocker listening location can be changed by editing file config.ini.

Jocker Clients
It is very easy to interact with Jocker, just create the following outputPort in your Jolie microservice and use it as usual:

outputPort DockerIn {
    Location: "socket://localhost:8008"
    Protocol: sodep
    Interfaces: InterfaceAPI
}


where InterfaceAPI can be downloaded from here. As an example you can request for the list of all the containers with the following client:

include "console.iol"
include "string_utils.iol"
include "InterfaceAPI.iol"

outputPort DockerIn {
    Location: "socket://localhost:8008"
    Protocol: sodep
    Interfaces: InterfaceAPI
}

main {
    rq.all = true;
    containers@DockerIn( rq )( response );
    valueToPrettyString@StringUtils( response )( s );
    println@Console( s )()
}


In the github repository of the project there are some sample clients you can use for testing Jocker.

Enjoy Jocker and, please, let us know comments and suggestions for improving it.

Wednesday, March 29, 2017

What is a microservice? (from a linguistic point of view)


As we described here, with Jolie we are pioneering the linguistic approach for dealing with microservices. Our idea is that microservices are introducing a new programming paradigm which can be crystallized within a programming language. The focus of this post is about the definition of microservice starting from our point of view: a linguistic point of view.

A service is the single unit of programmable software
In the last years the concept of service has been investigated in the area of Service Oriented Computing and several definitions have been provided for defining service contracts, service providers, service discovery and so on. All these definitions are quite abstract because services have been conceived to be technology agnostic both in the case of SOA and microservices. Such a fact means that it is possible to develop a service in any given technology. They say that services are technology agnostic.

Technology agnosticism is a very important feature which allows us to engineer a software system independently from any technology lock-in. But our purpose here is to give the definition of a service as a single unit of programmable software which cannot be fragmented in sub-parts. For this reason, you will find that all the definitions I am going to provide here are strongly related to a specific technology: Jolie. If you like to see how we chose to model the service oriented programming paradigm in a single language you can continue to read, otherwise you can skip this post. If we are wrong, or we are missing some points, or you know other technologies which match the definitions please write us your feedbacks. We are very exited to share ideas on this open topic.

As a starting point, let me explain the first assumption we made in the linguistic paradigm: the service is the single unit of programmable software. Usually, a service is always obtained by programming a server (it is not important if it is simple or not) joint with some business logic which represent the functionalities to serve:

                             SERVER + BUSINESS LOGIC = SERVICE

In a linguistic paradigm such an equation is not more valid just because servers do not exist. Only services exist. It is not possible to program a server because you can program only services. So, forget servers (do not confuse with serverless, it is a different approach). So, if there are no servers but only services, what is a service? As it happens for Object Orientation where classes are logical definitions and objects are the instances of classes in a running environment, let me call the logical definition of services with the term service and its running instance with the term microservice.

                                     SERVICE --> MICROSERVICE

For each service there could be more than one microservices, but each microservice is just the running instance of a service. The service is the single unit of programmable software. In the following I am going to build the definition of a service by giving some qualities it has to provide. At the end of this post I'll give the definition of service.

Services exchange messages
The only way for exchanging data among services are messages. There are no other way. A message is just a limited portion of data transmitted in a limited portion of time. A service can both receive messages and send messages. In a SOA a service which receives and sends messages is usually called orchestrator. Such a difference in the linguistic paradigm does not exist, an orchestrator is just a service. In particular, in Jolie message exchange is enabled by means of ports. Messages are received by means of inputPorts and they are sent by means of outputPorts. Similar constructs are used in WS-BPEL, they are called partnerLinkTypes.

Services can have a behaviour
The behaviour defines the business logic to be executed when a message is received.  In the behaviour it is possible to compute the received data and/or send messages to other services. In Jolie the behaviour is expressed in scope main. A behaviour can define different operations. Different business logics can be joint to different operations. In Jolie multiple operations can be expressed in the same behaviour by using the non deterministic operator:

main {
[ op1( req1 )( res1 ) {
    businessLogic1
}]  

[ op2( req2 )( res2 ) {
    businessLogic2
}]  

...

[ opn( reqn )( resn ) {
    businessLogicn
}]  
}

An operation must always express a finite computation in time. In other words, when triggered an operation must always reach an end state. I say that an operation is divergent if its behaviour defines an infinite computation. Jolie allows for the definition of divergent operations by defining infinite loops:

divergentOperation( request )( response ) {
    while( true ) {
           nullProcess 
    }
}

Divergent operations are deprecated in Jolie.

Services declare interfaces
The operations of the behaviour must be declared in a machine readable interface. The interface defines all the available operations of a given service. Interfaces are used as a concrete contract for interacting with a service. In Jolie interfaces are also equipped with message type declarations.

type MyRequestType: void {
    .msg: string
}

type MyResponseType: void {
    .resp_msg: string
}

interface myInterface {
RequestResponse:
     myOperation( MyRequestType )( MyResponseType )
}

Services execute sessions
Services execute sessions for serving requests. A session is a running instance of a service operation. Sessions are independently executed and their data are independently scoped. If we suppose to send three messages to a microservice which implements the following service we will receive three different messages for each request message.

main {
   test( request )( response ) {
      response = request
   }
}

if we concurrently send three request messages with content "1", "2", "3", we will receive three related reply messages with the same content.


A definition of service

Here I try to summarize a definition of service starting from the basic concepts highlighted above. Jolie provides more linguistic elements w.r.t. those highlighted here. Maybe more basic concepts could be added to the definition and other should be removed. This is just a starting point for trying to investigate microservices from a linguistic point of view. All the contributions are encouraged!

A service is a unit of programmable software able to exchange messages with other services whose behaviour is triggered by incoming messages and it is defined by a set of finite computation logics called operations which are declared within a machine readable interface. A running instance of a service is called microservice whose inner instances of triggered operations are called sessions. Sessions are executed independently and their variables are independently scoped.









Wednesday, October 12, 2016

Fast Jolie microservices deployment with Docker

Jolie is now available on Docker and now it is possible to develop and run a microservice inside a container.

But what about the deployment of a microservice in Docker? How can we build a deployable docker container which includes the microservice we are working on?

Actually, it is a very easy task. It is sufficient to develop the microservice by following some simple rules and your docker image will be ready in few seconds!

Rule 1 : you need a Dockerfile for building an image of your microservice
First of all, create a file named Dockerfile in your working directory and write the following lines:

FROM jolielang/jolie-docker-deployer
MAINTAINER SURNAME NAME


where SURNAME, NAME and EMAIL must be replaced with the maintainer's surname, name and email respectively. The Dockerfile will be used by Docker for building the image related to your microservice. As you can see, the image you are creating is layered upon a previously created image called jolielang/jolie-docker-deployer.
You can find this image in the docker hub of jolielang here. Such a docker image, is prepared for facilitating the deployment of a jolie microservice as a docker image. In order to use it in the right way, just follow the next rules. As an example, let me suppose to deploy the following microservice saved in file helloservice.ol:

interface HelloInterface {
RequestResponse:
     hello( string )( string )
}

execution{ concurrent }

inputPort Hello {
Location: "socket://localhost:8000"
Protocol: sodep
Interfaces: HelloInterface
}

main {
  hello( request )( response ) {
        response = request
  }
}


Rule 2 : EXPOSE inputPorts ports
Remember that all the inputPorts of your microservice must be reached from outside the container, thus you need to expose them in the Dockerfile.



In the example the inputPort is located at localhost:8000, thus we need to add EXPOSE 8000 in the Dockerfile. So, your Dockerfile now becomes like this:

FROM jolielang/jolie-docker-deployer
MAINTAINER SURNAME NAME

EXPOSE 8000

Rule 3 : COPY the files of your project and define the main.ol
Now, everything is quite done for preparing the image, we just need to copy the files of the project in the docker image. When doing this, pay attention to rename the file which must be run with the name main.ol.

FROM jolielang/jolie-docker-deployer
MAINTAINER SURNAME NAME

EXPOSE 8000
COPY helloservice.ol main.ol

Building your image

When the Dockerfile is ready we can build the docker image of the microservice. In order to do this you just need to run the following command within your working directory which also contains the Dockerfile.

docker build -t hello .

where hello is the name we give to the image. Once it is finished, you can easily check the presence of the image in the local registry by running the following command:

docker images

Running a container
Now, starting from the image, you can run all the containers you want. A container can be run by launching the following command:

docker run --name hello-cnt -p 8000:8000 hello

where hello-cnt is the name we give to the container. Note that the parameter -p allows you to map the microservice port (8000) to the port 8000 of your localhost. You can check that the container is running just launching the following command which lists all the running containers:

docker ps

Your microservice is now deployed and it is listening for requests at port 8000. You can just try to invoke it with a client like the following one. Remember to launch the client in a separate shell of your localhost!



include "console.iol"

interface HelloInterface {
RequestResponse:
     hello( string )( string )
}


outputPort Hello {
Location: "socket://localhost:8000"
Protocol: sodep
Interfaces: HelloInterface
}

main {
  hello@Hello( "hello" )( response );
  println@Console( response )() 
}



Advanced settings
So far, we have deployed a very simple service but, usually we deal with microservices that are more complicated than the hello service presented before. In particular, it is very common the case where some constants or outputPort locations must be defined at deploying time. In order to show this point, let me now consider the following service:

interface HelloPlusInterface {
RequestResponse:
     helloPlus( string )( string )
}

interface HelloInterface {
RequestResponse:
     hello( string )( string )
}

execution{ concurrent } 

constants {
   CUSTOM_MESSAGE = " :plus!"
} 

outputPort Hello {
Location: "socket://localhost:8000"
Protocol: sodep
Interfaces: HelloInterface
}

inputPort HelloPlus {
Location: "socket://localhost:8001"
Protocol: sodep
Interfaces: HelloPlusInterface 
}

main {
  helloPlus( request )( response ) {
        hello@Hello( request )( response );
        response = response + CUSTOM_MESSAGE
  }
} 

This is a very simple microservice which has a dependency on the previous one. Indeed, in order to implement its operation helloPlus, it requires to invoke the operation hello of the previously deployed microservice. Moreover, it uses a constants CUSTOM_MESSAGE for defining a string to be added to the response string.




Usually, we would like that some of these parameters can be defined at deploying time because they directly deal with the architectural context where the microservice will run. Thus, we would like to create an image which is configurable when it is run as a container. How can we achieve this?

Rule 4 : Prepare constants to be defined at deploying time
The image jolielang/jolie-docker-deployer we prepared for deploying microservice has been built with some specific scripts which are executed before running the main.ol. These scripts just read the environment variables passed to the docker container and transform them in a file of constants which must be read by your microservice. The most important facts we need to know here are:
  1. Only the environment variables prefixed with JDEP_ will be processed
  2. The processed environment variables will be collected in a file of constants  named dependencies.iol. If it exists it will be overwritten.
From these two points we change the microservice as it follows:
 

interface HelloPlusInterface {
RequestResponse:
     helloPlus( string )( string )
}

interface HelloInterface {
RequestResponse:
     hello( string )( string )
}

include "dependencies.iol"

execution{ concurrent } 

outputPort Hello {
Location: JDEP_HELLO_LOCATION
Protocol: sodep
Interfaces: HelloInterface
}

inputPort HelloPlus {
Location: "socket://localhost:8001"
Protocol: sodep
Interfaces: HelloPlusInterface 
}

main {
  helloPlus( request )( response ) {
        hello@Hello( request )( response );
        response = response + JDEP_CUSTOM_MESSAGE
  }
}

As you can notice here there are two constants JDEP_HELLO_LOCATION and JDEP_CUSTOM_MESSAGE which require to be defined at the start of the microservice. They must be defined in the file dependencies.iol which MUST BE included in your microservice. This file just contains the declaration of the two constants.

constants {
JDEP_HELLO_LOCATION = "socket://localhost:8000",
JDEP_CUSTOM_MESSAGE = " :plus!"
}

During the development keep this file in your project and collect here all the constants you want to define at deploying time. When the service will be run in the container this file will be overwritten thus, you don't need to copy it into the docker image.

The Dockerfile of the helloPlus service is very similar to the previous one:

FROM jolielang/jolie-docker-deployer
MAINTAINER SURNAME NAME

EXPOSE 8001
COPY helloservicePlus.ol main.ol
We can create the image with the same command used before, but where the name is hello-plus.

 docker build -t hello_plus .

Configuring the container
Now, we just need to know how to pass the constants to the running container and everything is done. Docker allows to pass environment variables with the parameter -e available for command run. Thus the command is:

docker run --name hello-plus-cnt -p 8001:8001 -e JDEP_HELLO_LOCATION="socket://172.17.0.4:8000" -e JDEP_CUSTOM_MESSAGE=" :plus!" hello_plus

where hello-plus-cnt is the name we give to the container. Note that the constant JDEP_HELLO_LOCATION is set to  "socket://172.17.0.4:8000" where the IP is set to 172.17.0.4. It is just an example, here you need to specify the IP that Docker assigned to the container hello-cnt which is executing the service hello.ol. You can retrieve it just launching the following command:

docker inspect --format '{{ .NetworkSettings.IPAddress }}' hello-cnt

Once the hello-plus-cnt container is running, you can simply invoke it with the following client:

include "console.iol"

interface HelloPlusInterface {
RequestResponse:
     helloPlus( string )( string )
}

outputPort HelloPlus {
Location: "socket://localhost:8001"
Protocol: sodep
Interfaces: HelloPlusInterface
}

main {
  helloPlus@HelloPlus( "hello" )( response );
  println@Console( response )()
}


Conclusion
In this post I show how it is possible to deploy a microservice developed with Jolie as a docker container. The procedure is very easy, just pay attention to inputPorts and the constants you want to configure at deploying time. For all the other things you can just rely on the Jolie language. Don't forget that you can also exploit embedding for packaging more microservices into one, thus deploying all of them inside the same container if necessary.

Enjoy!

Monday, September 5, 2016

An easy way to build microRESTservices with Jolie

This post is about a couple of tools [https://github.com/jolie/jester] we developed for facilitating the programming of REST microservices with Jolie. Personally I am not a big supporter of REST services, but I think that a technology which aims at being a reference in the area of microservices like Jolie must have some tools for supporting REST services programming. Why? Because REST services are widely adopted and we cannot ignore such a big evidence.

Ideally, Jolie as a language is already well equipped for supporting API programming also using http, but REST approach is so deep coupled with the usage of the HTTP protocol that it introduces some strong limitations in the service programming paradigm. Which ones? The most evident one is that a REST service only exploits four basic operations: GET, POST, PUT and DELETE. The consequence of such a strong limitation on the possible actions is that the resulting programming style must provide expressiveness on data. This is why the idea of resources has been introduced in REST! Since we cannot programming actions we can only program resources.

Ok,  let's go with REST services!

...But,
...here we have a language, Jolie, that is more expressive than REST because the programmer is free to develop all the operations she wants. From a theoretical point of view, in Jolie she can program infinite actions instead of only four!

…

- Houston we have a problem! We need to put infinite operations inside just four!!!

- Why only four when we can have infinite?

- This does not matter now Houston, we have to do it!

…

Ok no problem! Follow our instructions!
First of all, take note that here we want to preserve all the benefits of using Jolie, thus the possibility to develop all the operations we want, but finally publish the microservice as a REST service. We achieve such a result by exploiting a specific microservice architetcure which is a composition of a router and the target microservice we want to publish as a REST one. The router, as described in Fabrizio's paper [https://arxiv.org/abs/1410.3712], is in charge to transform REST calls into standard Jolie calls.



Ok, in order to exaplain how to proceed, let us consider as a target microservice the demo one reported in the jester project [https://github.com/jolie/jester/tree/master/src/jolie/tools/demo]. It is a very simple service which emulates a manager of orders which supplies four operations: getOrders, getOrdersByItem, putOrder, deleteOrders.

Ok, there are four operations but it is just an example, we could have more than four operations :-). The main question now is:

What we have to do for transforming these operations in REST operations?
We need to use the jolie2rest.ol tool you can find the jester project. Such a tool analyzes the interface of the demo service and it extracts a descriptor for the router which enables it to publish the demo service as a REST service.

Very simple! But before running the tool we need to know something more. We need to define how to convert the single operations of the demo microservice will be tranformed into the REST one. In particular, fro each target operations we need to specify if we want a GET operation, a POST operation, a PUT operation or a DELETE operation. It is possible to provide these instructions, directly into the interface of the demo service by exploting the annotation @Rest into the documentation comments. As an example let us consider the operation getOrders:

/**! @Rest: method=get, template=/orders/{userId}?maxItems={maxItems}; */
getOrders( GetOrdersRequest )( GetOrdersResponse )


The annotation defines that the operation getOrders it must be transformed into a GET http method and the URL template that must be adopted is /orders/{userId}?maxItems={maxItems}. What is the template URL?
Since the REST services deal with resources, the URL is used as a means for expressing the resource we want to access. Here we use the template as the means for transforming a call to an operation of the target service into a resource. In particular, the parameters between curly brackets will be directly filled by using the corresponding values of the request message node which is defined in the GetOrdersRequest type:

type GetOrdersRequest: void {
    .userId: string
    .maxItems: int
}


Now, we can proceed by running the following command:

jolie jolie2rest.ol localhost:8080 swagger_enable=true

where localhost:8080 is the location where the router is deployed and the parameter swagger_enable specifies if we want to enable the creation of the swagger json descriptor file.
Note: the file service_list.txt contains the list of the target microservices to be transformed and the related inputPorts to be converted (more instructions can be found here: ref).

As a result the tool will generate two files:
  • router_import.ol
  • swagger_DEMO.json
The former file must be copied in the router folder and it contains the script which enables the router to transform the REST calls into the operations call of the target service. The latter is just the swagger descriptor to be provided in input into a SwaggerUI. You don't have a local SwaggerUI available? Follow these instructions to have it locally, otherwise go to point 6:



  1. Prepare the web server of the SwaggerUI application by downloading Leonardo from here [https://github.com/jolie/leonardo]
  2. Go to this SwaggerUI URL [https://github.com/swagger-api/swagger-ui/archive/v2.2.3.zip] and download the related web application project. 
  3. Copy the content of the folder dist of the SwaggerUI project inside the folder www of Leonardo.
  4. Open a shell and run jolie leonardo.ol
  5. Open a browser at the url http://localhost:8000, the SwaggerUI web application should appear.
  6. Copy the swagger_DEMO.json file into the folder where it is reachable from the SwaggerUI, in the Leonardo scenario put it inside the www folder.
  7. Write in the explorer bar of the SwaggerUI the URL for reaching the swagger descriptor, in the Leonardo case write: http://localhost:8000/swagger_DEMO.json
After this step, you should see the Swagger definition of your target demo service transformed into a REST one. In particular, you should see something like this:







As you can see the four operations of the target service have been transformed in the four different types of REST operations. Have a look to the interface annotations of the demo service for finding the matches with the Swagger interface!

Nice, but what happen if I want to transform more than one Jolie microservices instead of a single one?
This question is dealing with an architecture like the following one where the router is connected with several microservices:



There are no particular problems in achieving such a result. It is sufficient to list all the target microservices with the related input ports in the file service_list.txt and re-launch the jolie2rest tool!

Ok Houston! Here we are! But is it possible to avoid the usage of the router?
Yes, it is possible. But only if you accept to not completely adhere to the REST approach. A jolie microservice can be directly published by using a http inputPort with message format set to json [http://docs.jolie-lang.org/#!documentation/protocols/http.html#http-parameters]. In this case the microservice will be able to serve the http requests without requiring any router or proxy in the middle. If you want this, change the inputPort protocol of the demo service to a http one and then use the jolie2rest tool with the parameter easy_interface set to true.

jolie jolie2rest.ol localhost:8080 swagger_enable=true easy_interface=true

In such a case the router_import.ol file is not generated but only the swagger_DEMO.json one. The operations are all converted in POST methods and the URLs do not follow the templates but the request json messages must be entirely defined in the body of the message. Try to replace the file swagger_DEMO.json in the SwaggerUI and perform some calls.

Generating client stubs from an existing Swagger definition:
A last tool which can be very useful when integrating existing REST services in a Jolie architecture, is jolie_stubs_from_swagger.ol. Such a tool takes in input an existing Swagger definition and generates a Jolie client for each published api.

As an example you could try it by generating the clients for the petstore example supplied by the Swagger project [http://petstore.swagger.io/v2/swagger.json]. In order to do it, create a target folder where you want to store all the generated clients (for example petstoreFolder) and then run the following command:

jolie jolie_stubs_from_swagger.ol http://petstore.swagger.io/v2/swagger.json petstoreService petstoreFolder

where petstoreService is the token that will be used for generating the Jolie outputPort name of the petstore service inside the clients. As a result, in folder petstoreFolder you will find a list of Jolie clients. In particular, you will have a client for each api defined in the petstore swagger definition.

If you want to try to send a request just open one of them and create the request message. For example open the getOrderById.ol and prepare the request message by adding the following jolie code:

with( request ) {
.orderId = 8
};

then run the client as a usual jolie script:

jolie getOrderById.ol


the result should be printed out on the console!

You can exploit these clients inside your existing jolie microservices. Just note that the generated file outputPort.iol defines all the information necessary to declare the outputPort to be used. Thus just include it in your microservice project and then make the calls when is more useful for you!

Conclusion
Houston, everything is clear now! :-) With the REST tools described in this article we want to improve the Jolie language providing the possibility to publish Jolie microservices as REST services and giving an easy way for generating clients from existing REST services. We hope this could be useful for your  projects and, please, do not forget to send us your feedbacks and improvements!