WSO2

How to easily create and deploy a microservice with Ballerina and Microgateway

15th October 2019

 

In current times, we don’t always need products as robust and stable as API Manager or Enterprise Integrator. We can instead focus more on lightweight platforms designed for simple cloud deployments.

With this in mind, WSO2 offers a couple of products that are ideal for this purpose:

  • API Microgateway, a tool based on API Manager, which allows us to maintain its reliability and integration experience. With it, we can also simplify the API creation and deployment process, maintaining the ability to perform routing, security and analytics operations.
  • Ballerina, a new programming language and platform that allows us to create microservices. It is highly oriented to cloud deployments.

 

How to deploy an API with Microgateway

To discuss this issue, on one hand, we will create an API to be deployed with Microgateway, and a backend service associated with the API, which will be developed and deployed using Ballerina. Since in this article we want to focus on simplicity in the creation and deployment of microservices, we will use as an example a very basic microservice without authentication that will let us create and obtain books via HTTP GET and POST.

Besides Ballerina and Microgateway, we will rely on other tools:

  • Microgateway Toolkit, which will help us create the API.
  • Docker, which we will use to deploy both the service and the Microgateway.

In order to do this, we will need to have Ballerina, Microgateway Toolkit and Docker properly installed on our machine.

 

Developing the service with Ballerina and Microgateway

The service project will have a very simple structure. It will be composed of the root folder, bookService, and the module with our source code, http. In order to initialize the project, we will have to execute the following command from the main folder.

ballerina init

Our service will be called HTTPService.bal and will look as follows.

 

import ballerina/http;
import ballerina/log;
import ballerinax/docker;
@docker:Expose {}
listener http:Listener bookEP = new(9091);
map<json> booksMap = {};
@docker:Config {
Registry:”com.chakray.example”, name:”example”, tag:”v1.0″
}
@http:ServiceConfig {
basePath: “/bookService”
}
service books on bookEP {
@http:ResourceConfig {
methods: [“GET”], path: “/book/{bookId}”
}
resource function getById(http:Caller caller, http:Request req, string bookId) {
json? payload = booksMap[bookId];
http:Response response = new;
if (payload == null) {
response.statusCode = 404;
payload = “Item Not Found”;
}
response.setJsonPayload(untaint payload);
var result = caller->respond(response);
if (result is error) {
log:printError(“Error sending response”, err = result);
}
}@http:ResourceConfig {
methods: [“POST”], path: “/book”
}
resource function addBook(http:Caller caller, http:Request req) {
http:Response response = new;
var bookReq = req.getJsonPayload();
if (bookReq is json) {
string bookId = bookReq.book.id.toString();
booksMap[bookId] = bookReq;
response.statusCode = 201;
response.setHeader(“Location”, “http://localhost:9091/bookService/book/” + bookId);
} else {
response.statusCode = 400;
response.setPayload(“Invalid payload received”);
}
var result = caller->respond(response);
if (result is error) {
log:printError(“Error sending response”, err = result);
}
}
}

 

Using this code as a reference, let’s focus on the key parts of this service:

  • We import the Ballerina utility libraries: docker, http and log.
  • We configure our service to listen to the requests arriving at port 9091 within the context of the /bookService URL.
  • We link two resources to the service: one that listens for the GET method which expects an identifier in the URL, and another one that listens for the POST method, which expects a JSON object as a message.
  • The GET method will return response code 200 and the object associated with the identifier posted in the URL, or 404 if the object is not found.
  • The POST method will store the JSON object in a map in the internal memory and respond 201 and a header containing the URL of our service if we want to retrieve the stored book.

 

How to deploy the service with Docker

In order to create an image linked to our service that is handled by Docker we will need to keep the following aspects of the code above in mind:

  • We have indicated the service port to expose to the outside world.
  • We have included the configuration of the image to be created.

In order to create the image we will need to execute the following command:

ballerina build HTTPService.bal

And we can start our service thanks to Docker using the following command:

docker run –name=dockerBookService –net=wso2_nw -d -p 9091:9091 com.chakray.example/example:v1.0

 

Developing the API with Microgateway

Just as with Ballerina in the previous step, Microgateway Toolkit will let us initialize the project and create a basic project structure. We can do this using the following command.

 

micro-gw init bookAPI

 

This project will have the following structure:

  • api_definitions: folder where we will include YAML files, which contain the definition of our APIs.
  • conf: folder that includes the Docker or Kubernetes configuration file.
  • extensions: folder with Microgateway functionality extensions.
  • interceptors: folder with Microgateway interceptors. Empty by default.
  • services: folder with predefined Microgateway services, such as those that allow us to obtain a token or revoke it, and work as a proxy of the Key Manager.
  • policies.yaml: folder with use policies, predefined by default.

 

The following step will be creating the API definition. Microgateway is compatible with the OpenAPI 3.0 specification, so we will build an API that is based on it, containing the following information.

 

openapi: 3.0.0
info:
versión: 1.0.0
title: Book API
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
tags:
– name: book
description: book tag description
x-wso2-basePath: /bookAPI/v1
x-wso2-production-endpoints:
urls:
– http://dockerBookService:9091/bookService
paths:
“/book/{bookId}”:
get:
tags:
– book
description: Returns a single book
operationId: getBookById
x-wso2-disable-security: true
parameters:
– name: bookId
in: path
description: ID of book to return
required: true
schema:
type: integer
format: int64
responses:
‘200’:
description: successful operation
‘404’:
description: Book not found
“/book”:
post:
tags:
– book
description: create a book
operationId: createBook
consumes:
– “application/json”
parameters:
– in: “body”
name: “body”
description: “Book object”
required: true
x-wso2-disable-security: true
responses:
‘201’:
description: created
‘400’:
description: Invalid payload received

 

As you can see, the code is quite self-explanatory. But let’s take a closer look at certain aspects:

  • x-wso2-basePath: OpenAPI extension that will let us inform Microgateway of the context of the URL associated with our API.
  • x-wso2-production-endpoints: Extension to indicate the backend linked to our API.
  • X-wso2-disable-security: Extension to indicate that we do not want to enable any kind of security in the resource where we enter the properties.

Microgateway has these and many more extensions that can let us have a greater degree of control than what is offered by default by OpenAPI.

In order to add security to an API, Microgateway accepts OAuth2 tokens (default option), JWT tokes or Basic authentication. But for both JWT and OAuth2 tokens we will need to associate a third application that will provide us with these tokens, such as the WSO2 Identity Server itself.

Once our API has been created as a YAML file and stored in the api_definitions folder, we will start building the project by executing the following command from the folder that contains it.

micro-gw build bookAPI

 

How to deploy the Docker

As we can see, this command will compile the files in the Ballerina format. This is because Microgateway is also based on this technology to implement the APIs.  Deploy the API with Docker

When using Docker, we will be able to make a fast deployment, without the need for manual binary downloads or extra configurations, offering a more modern approach and focusing our services on cloud deployments. For this, we will have to execute the following command:

 

docker run –net=wso2_nw –name=dockerBookAPI -d -v /temp/bookAPI/target:/home/exec/ -p 9095:9095 -p 9090:9090 -e project=”bookAPI”  wso2/wso2micro-gw:3.0.1

It is important to correctly enter the path where our compiled API is located, and the name of the project, which is that of the compiled file.

Once the two images have been obtained, all we have to do is verify that the two resources work correctly and that both the service and the Microgateway are doing their job. We can do this test with the following commands:

 

curl -X GET http://localhost:9090/bookAPI/v1/book/1

curl -X POST http://localhost:9090/bookAPI/v1/book -H ‘Content-Type: application/json’
-d ‘{“book”:{“id”:1,”name”:”WSO2 Developer´s Guide”,”author”:”Ramon Garrido, Fidel Prieto”}}’

 

Here we have seen a small example of how easy and simple it is to create microservices with WSO2 using bleeding edge technologies and facilitating the deployment to the cloud.

Daniel Blanco Chakray