Build an API using Ballerina

Written by dhanushka | Published 2021/11/19
Tech Story Tags: cloud-native | api | programming | cloudservices | ballerina | ballerinalang | rest-api | http-requests

TLDRBallerina language is the latest cloud-native programming language that you can use to build backend applications. A simple way of representing services makes it programmers easy to build backend services with only a few lines of code. In this article, we will discuss, how to build a simple HTTP service with Ballerina language and how to input and output data from it.via the TL;DR App

You may be building full-stack software and found an easy way of building backend services already. Currently, there are multiple backend and frontend development software used to develop web applications. Frontend applications are mostly focused on giving more user experience for users. Backends are commonly written with APIs that allow frontend applications work with them. When it comes to backend application developments, developers are moving away from building everything from scratch to reusing components. The Backend implementation is no longer a single service that implements everything but rather a set of services that are connected together. Ballerina comes to fill this gap between integrating services.

Ballerina is a general-purpose programming language that was initially released in 2019. Ballerina was specially designed to build backend web services that are running on the cloud. Nowadays, developers are more and more focused on creating applications that are running on the cloud. If you choose the Ballerina language, it supports several cloud platforms and tools that you can easily work with. With Ballerina, you can deploy your applications on Docker and Kubernetes without writing any additional artifacts. Ballerina built-in Docker and Kubernetes lets you easily deploy a Ballerina program on a container platform. Ballerina also supports implementing a serverless function where you can create applications on Function as a Service(FaaS) platforms.

Before you go into developing a Ballerina application, you need to have some knowledge about basic programming syntaxes, program control flow, and the Ballerina type system. Most of these syntaxes are much similar to Java, Go, C programming languages. However, you can find more details about Ballerina syntaxes on the https://ballerina.io/learn/ Ballerina learn page. Here, you can find many details that you need to have a basic understanding of the language.

Starting up Development with the Ballerina Language

You can download and install Ballerina from the Ballerina website https://ballerina.io/downloads/. Once you download the installer, you can run the installer and install Ballerina on your computer. You can use Visual Studio Code as the code editing tool since the Ballerina VS Code plugin is also available to download.

Ballerina CLI tool lets you work with Ballerina development features. This tool can be used to create a new project, build and test the project. For example, you can create a new project with bal new package_path command. Here you can give a custom package name by replacing the package_path. Ballerina packages are the way Ballerina keeps source files that are related to a given project. For this example let's name this project hello_world. Therefore, your command would be bal new hello_world.

Once you create a new project, Ballerina CLI generates a directory with the package name and adds two files to it. Once file can be found as main.bal file and the other one is the Ballerina.toml file. The main.bal file is the main entry point of your application and the Ballerina.toml file contains package details. Since in this blog post we are focusing on building backend services, let's see how we can build a simple backend service with the Ballerina language. The following is a hello world backend REST application that responds to a plain text message back to the caller.

import ballerina/http;
service /hello on new http:Listener(9090) {
  resource function get greeting() returns string {
    return "Hello World!";
  }
}

Here, we have defined a service that starts on port 9090. Service is a collection of resources that provide some service to clients services. To identify the service, we can give a context URL for the service. The Listener is a Ballerina class that provides an interface to develop Ballerina HTTP services. As an input argument, we need to give the port where the service should be started. Here, we have given port 9090 as the service port. If you do not need to have a service context URL, you can keep "/" as the service context URL. This will change the service context URL that you need to access this service.

The next step is to include the resource methods inside the service. Here, we have defined a simple resource method with the "GET" method. The resource function name is greeting and it responds a plain text content back to the caller. The resource method definition template can be represented in the following format:

resource function <resource-method> <resource-method-name>() returns <return-type> {
   // resource content
}

You can define a custom method with the resource-method and resource method name with the resource-function-name placeholder. The return type is used to define the type of the response message to send back. This will automatically convert Ballerina datatypes to HTTP content type. Following are the content time mapping that is used to respond with each of the Ballerina return types:

  • (): (no body)
  • XML: application/xml
  • string: text/plain
  • byte[]: application/octet-stream
  • map<json>, table<map<json>>, (map<json>|table<map<json>>)[]: application/json
  • int, float, decimal, boolean: application/json

Since we have returned a string value, it will respond back with text/plain content type.

Next, we will build and run this Ballerina program. You can perform both build and run operations with the bal run hello_world command. This command builds the Ballerina runtime artifacts and starts executing those executables. Once you have started up, you can access the resource we have created over the 9090 TCP port. You can access this endpoint with the web browser using the http://localhost:9090/hello/greeting URL. You will get the response Hello World! as a text/plain content type. Let's discuss how we can respond with other content types in the Ballerina language.

If we add another resource method into the Ballerina program which returns a JSON as follows, It will respond to content as application/json:

resource function get greetingInJson() returns json {
  return {
    "message": "Hello World!"
  };
}

In the same way, you can return XML, integers, byte arrays, and so on with a resource method. This method is much easier since you don't need to specify what is the content type since the Ballerina is able to automatically identify and convert it.

Passing Data to Ballerina Services

So far, we have only discussed building a simple HTTP service with the Ballerina program. Now, let's discuss how to pass data into a Ballerina HTTP service. There are multiple methods to send data to an HTTP service. The following are some of these:

  • Path parameters
  • Query parameters
  • Header parameters
  • Body payload

Let's go through each of these methods and how to use them with the Ballerina services.

Path Parameters

Path parameters use the URL itself to send parameters. Ballerina services let you define these parameters in the Ballerina service description. For an example, check the following Ballerina resource definition that read parameters from the URL as path parameters:

resource function get users/string username returns string{
  return "Username is: " + username;
}

In this resource definition, you can see that the resource method names as user/[string username]. Here, the resource context URL is given as the user and variable string value accepted in the URL. You can directly use this variable in your resource definition to access path parameters. This resource can be accessed with the http://localhost:9090/hello/users/dhanushka sample URL. You can define any custom template with different types of path parameter types. The ballerina path parameter is able to read integer and floating numbers as well.

Since URL itself is a way of defining some resources, path parameters are used to define some variable resources. For this example, the resource would be users and username is to refer to some particular user.

Query Parameters

Query parameters are also sent through the URL itself. Query parameters are attached at the end of the URL with the ? symbol. Query parameters can be passed as key-value pairs where each pair is separated by & symbol. Check the following sample code that uses query parameters to pass data into a Ballerina HTTP service:

resource function get users(string username, int age) returns json {
  return {
    "username ": username,
    "age": age
  };
}

Here, the Ballerina service read query parameters as the input argument for the resource method. This resource method only responds to the incoming query parameters from the caller in JSON format. If you tried to access this service with the sample URL http://localhost:9090/hello/users?username=dhanushka&age=29, it will respond the response as {"username": "dhanushka", "age": 29}. You can have many parameters with different types in the resource method input argument to collect query parameters.

Query parameters are widely used in filtering HTTP requests. In most of the scenarios, query parameters are used to send data related to paginations, search queries, and sorting.

Header Parameters

Here's another way of sending parameters to the HTTP service. All previous methods that we have discussed, used the URL itself to pass information to a Ballerina service. Let's look at another way of sending data to an HTTP service which is through the HTTP headers. In HTTP requests, you can send data into service as key-value pairs in HTTP headers. You may already know some of these standard headers such as Content-Type, Allow etc. Let's send a custom HTTP header to the Ballerina HTTP service and send back a JSON response. The following is the resource implementation:

resource function get userName(@http:Header {name: "username"} string username) returns string {
  return "Username is: " + username;
}

Here, we have defined a new resource method with the argument username which is a string.

To clarify, this variable should be initialized with the request header, we used @http:Header annotation. As in the previous example, we just respond with the header property back to the user. You can invoke this endpoint with the curl -X GET 'http://localhost:9090/hello/userName' -H 'username: dhanushka' curl command. This command will invoke the service with the given HTTP header values.

Header parameters are used when sending metadata to a backend service. This data contains some meta instructions about what the request does. These headers might contain, authentication data, request data types, cache data, and so on.

Body Payload

Same as we have used the HTTP header, we can use the HTTP body to send data to an HTTP service. HTTP headers define the metadata of your request. HTTP body payload contains the actual payload that needs to be sent to the backend service.

The body can have different input types. This type can be a simple string, JSON, or XML. The following is an example of reading a string payload and responding back to it:

resource function put users(@http:Payload string username) returns string {
  return "Username is: " + username;
}

In this code, we have read the username from the incoming HTTP request payload and used it inside the function. This resource can be accessed with the curl -X PUT 'http://localhost:9090/hello/user' -d 'dhanushka' curl command. This will respond to the data string that you have sent.

Now we can modify this resource method as follows to work with the JSON input format where you can send much more complicated data into an HTTP service:

resource function post users(@http:Payload json user) returns json {
  return {"user": user};
}

In this example, instead of a string, we send the request body as a JSON. Inside the resource method, we can perform calculations and respond to a result. You can use curl -X POST 'http://localhost:9090/hello/users' -d '{"name":"dhanushka","age":29}' command to invoke this service.

In the same way, you can read XML input and perform XML operation as well.

Summary

In this article, we have focused on building an HTTP service with the Ballerina language and how to send and retrieve data from a Ballerina service. As you have seen, it is super easy for developers to define input and output from and to an HTTP service. You don't need to use any code generation tools to generate these codes and it is quite straightforward to define HTTP service with the Ballerina language itself.

Other than defining these services manually, you can generate these implementations with an Open API specification as well. When you are developing a program with API first, then you can define the Open API spec first and generate resource definition automatically. You can find more information about the Ballerina Open API CLI tool in https://ballerina.io/learn/cli-documentation/openapi/.

You can find all the samples that are demonstrated in this article on the https://github.com/madushadhanushka/ballerina-samples/tree/master/ballerina_service GitHub repository. Feel free to send pull requests and raise issues to improve the code quality.

First published here


Published by HackerNoon on 2021/11/19