How to write a connector in Ballerina

Writing a Twitter client in Ballerina

Chanaka Lakmal
May 14, 2018 · 10 min read
Image for post
Image for post

NOTE: All the Ballerina codes in this article are tested and compatible with Ballerina version 1.2.0

TL; DR

We build a Twitter connector, which can be used to Tweet, Retweet etc. with the use of Ballerina programming language. Then we publish it to Ballerina Central using GitHub Actions and make our connector available to use by everyone.

GitHub Repository:

Connector in Ballerina Central:

Prerequisites

Before starting, you have to setup your machine with Ballerina. Please refer to Installing Ballerina guide.

Once you have successfully installed Ballerina, execute ballerina -v command to make sure it works. This should display the Ballerina version you installed.

Understanding the Ballerina Project & Module

Project is a directory, which atomically manages a collection of modules. Most importantly, a Ballerina project has:

  • A user-managed manifest file, Ballerina.toml
  • A src folder with collection of modules

You can create a project with the following command.

$ ballerina new <project-name>

This will create the Ballerina.toml file, and src folder.

Once the project is initialized, move inside the project ($ cd <project-name) and then, you can create a module using the following command.

$ ballerina add <module-name>

This will create a module inside src folder. Then, the final project structure will be as follows:

<project-name>
├── Ballerina.toml # Configuration, which defines project intent
├── .gitignore # List intentionally untracked files to ignore
└── src
└── <module-name>
├── main.bal # Contains the default main method
├── Module.md # Readme display at Ballerina Central
├── resources # Module-specific resources
└── tests
├── main_test.bal # The test file for main
└── resources # Resources for the tests

The folders tests/ and resources/ are reserved folder names within the module. The tests/ folder contains unit test files of the module and the resources/ folder contains the resources of the module that will be available at run-time.

Let’s Start

NOTE: To make this article simple and easy to understand, I will use Twitter as an example. So that, at the end of this article you will build a Twitter connector for Ballerina and you can Tweet with Ballerina!

Image for post
Image for post

The client is an object type of Ballerina, where it may have remote methods to send network messages to a remote process according to some protocol. So, this can be used to connect to external systems by handling security and everything which are required by external system. So that, end user does not need to worry about protocol complexities. Simply, this is a wrapper of external system.

Here we create a Twitter Client which is used to call Twitter REST API.

We implement the client and related files in the src/ folder added when creating the module.

<project-name>/src/<module-name>/twitter_client.bal

The following code sample demonstrates a simple Twitter Client followed by the explanation. To make this code sample, easy to understand, I have removed all the documentations.

When initializing the Twitter Client object, we use a set of configurations as a record called Configuration. This record will be initialized by the end user inputs and will get passed to the constructor of the Twitter Client object. These configurations are used to call the actual REST API inside the remote function. This may have authn/authz configurations, proxy configurations etc. which are needed to connect the actual REST API.

The remote functions which calls the actual REST API are defined as follows:

public remote function foo() returns bar {
// Remote function implementation goes here.
}

The remote function implementation should do the followings:

  • Build the HTTP Request with the authentication information required by the REST API.
  • Call the REST API with Ballerina HTTP client.
  • Get the result of the API invocation.
  • If the API invocation is success return the success status/result, else, return a meaningful error.

Writing test cases is a best practice when developing a connector. For this, we use Testerina, which is the built-in test framework of Ballerina.

To test Twitter Client, first we must obtain API keys and tokens to from Twitter. If you have already obtained the values needed to initialize theConfiguration record we created previously, please ignore this step.

  1. Create a Twitter account, if you don’t have any.
  2. Visit https://apps.twitter.com/app/new and sign in.
  3. Provide the required information about the application.
  4. Agree to the Developer Agreement and click “Create your Twitter application”.
  5. After creating your Twitter application, your “Consumer Key” and “Consumer Secret” will be displayed in the “Keys and tokens” tab of your app on Twitter.
  6. Click the “Keys and tokens” tab, and then enable your Twitter account to use this application by clicking the “Create my access token” button.
  7. Copy the Consumer key (API key), Consumer Secret (API secret key), Access Token, and Access Token Secret from the screen.

NOTE: For more information, refer to the Getting started guide.

We implement the test cases in the tests/ folder added when creating the module.

<project-name>/src/<module-name>/tests/twitter_client_test.bal

Now, you can initialize the Twitter Client by passing the Configuration record with obtained values and then you call the remote actions you have implemented.

The following code sample demonstrates a test case for the Twitter Client.

Now, execute the following command from your <project-name> folder

$ ballerina test <module-name>

If your credentials are valid, the program should print the test status/result. But if there are any compile errors, you need to fix them first.

This is a sample of the complete output for the above command. You should get something like this. It shows the status of your test cases as well.

Compiling source
ldclakmal/twitter:1.0.0
Creating balos
target/balo/twitter-2020r1-any-1.0.0.balo
Running Tests
ldclakmal/twitter:1.0.0
createdAt=Fri May 01 14:23:54 +0000 2020 id=1256227851508101125 text=Welcome to Ballerina Twitter Connector! source=<a href="https://central.ballerina.io/ldclakmal/twitter" rel="nofollow">Ballerina Twitter Client</a> truncated=false favorited=false retweeted=false favoriteCount=0 retweetCount=0 lang=en
[pass] testTweet 1 passing
0 failing
0 skipped

Congratulations! Now you have implemented a Ballerina connector and tested it successfully. It is simple as that.

Please, refer the following guide to learn how to test ballerina code further.

Please refer this GitHub Project for the full implementation of Twitter Connector for Ballerina.

Publish your connector to the World!

This is the next step you should do to make your connector available for everyone to use. All the Ballerina connectors are hosted in Ballerina Central. So that any interested developer can pull and use your connector. Hence it is important to write the Module.md file properly. That is the guide, that you display on Ballerina Central, instructing the users, how to use it. Please refer the Module.md of sample connector as an example.

Image for post
Image for post

First, you need to create an account in Ballerina Central. You can sign up with you “Google account” or “GitHub account” as you wish. Then you must create an organization at User Dashboard.

Now, you can get your “Ballerina Central access token” from the dashboard. Before you push your module, you must enter your “Ballerina Central access token” in Settings.toml file in your home repository (<USER_HOME>/.ballerina/).

Finally, you should update the Ballerina.toml file of your project. This file is automatically created when you create a new project.

<project-name>/Ballerina.toml

The content of the file will be as follows. Most importantly, the name of the organization you created at Ballerina Central, should matched to the org-name given at Ballerina.toml file.

[project]
org-name = "ldclakmal"
version = "1.0.0"
license = ["Apache-2.0"]
authors = ["Chanaka Lakmal"]
repository = "https://github.com/ldclakmal/ballerina-twitter-module"
keywords = ["ballerina", "twitter", "connector", "integration"]

NOTE: When you push a module to Ballerina Central, the runtime validates organizations for the user against the org-name defined in your module’s Ballerina.toml file. Therefore, when you have more than one organization in Ballerina Central, be sure to pick the organization name that you intend to push the module into and set that as the org-name in the Ballerina.toml file inside the project directory.

Now, you can push your connector to Ballerina Central. For that, there are 2 options that you can follow.

  1. Ballerina CLI commands
  2. GitHub actions

This is a straightforward method. You must go to the <project-name> folder and execute the following commands in order.

The first command will build your module with all the test cases and generate executable.

$ ballerina build <module-name>

The second command will push your module to Ballerina Central.

$ ballerina push <module-name>

NOTE: If there are any errors when building your connector, which is because of the program errors you have. You need to fix this. But, if you have successfully tested in the previous step, there can’t be errors when building a module.

Congratulations! Now you have published your connector in Ballerina Central successfully. It is simple as that.

Now, it should be displayed in Ballerina Central.

This is an automated process where you can use push your connector to Ballerina Central when you do a release on GitHub. If you are not familiar with GitHub releases, please refer to the following article.

For this, you have a create a configuration file (YAML file) in following path. Let’s name it release.yml file.

<project-name>/.github/workflows/

When you configure a GitHub workflow, there are few things you need to know. For more information, please refer to following documentation.

For this sample, let’s create our release.yml file with following configurations.

Here, you can see there are 2 stages.

  1. Ballerina Build
  2. Ballerina Push

At the first stage, we set 4 environmental variables which are used to test the connector while building the connector.

env:
CONSUMER_KEY: ${{ secrets.CONSUMER_KEY }}
CONSUMER_SECRET: ${{ secrets.CONSUMER_SECRET }}
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
ACCESS_TOKEN_SECRET: ${{ secrets.ACCESS_TOKEN_SECRET }}

At the second stage, we set another environmental variable which is used to push the connector to Ballerina Central.

env:
BALLERINA_CENTRAL_ACCESS_TOKEN: ${{ secrets.BALLERINA_CENTRAL_ACCESS_TOKEN }}

You already know what are the values that should be used to this. Since those are sensitive informations, it is recommended to store them as encrypted secretes in GitHub. You can do it via the UI of your GitHub repository.

Image for post
Image for post

NOTE: When you store the secrets, the key-name of the secret value should be matched to the key-name set at the release.yml.

Please refer to following article for more information on how to store secrets.

Now, all the configurations are done. You can start a release from GitHub UI. Go to, “Actions” tab of the GitHub repository. You can see, the progress of the workflow. Here is an example of successful workflow of my connector. You can refer to it with link given.

Image for post
Image for post

Congratulations again! Now you have published your connector in Ballerina Central successfully. It is simple as that.

Now, it should be displayed in Ballerina Central.

How to use Ballerina connector

Now, it is time to see, how to use your connector as a developer who is interested to use the Twitter services without worrying about its REST API.

You can create a new Ballerina project and follow the steps below. But to make this easy to understand, let’s create a .bal file called twitter-test.bal and follow the steps.

First, import your connector with import <org-name>/<module-name> pattern.

import ldclakmal/twitter;

Now initialize the Twitter Client with the obtained tokens.

twitter:Configuration twitterConfig = {
consumerKey: "Twitter App Consumer Key",
consumerSecret: "Twitter App Consumer Secret",
accessToken: "Twitter App Access Token",
accessTokenSecret: "Twitter App Access Token Secret",
};
twitter:Client twitterClient = new(twitterConfig);

Now, in the main function, you have to call the connector functions implemented. For this example, let’s use tweet API, which sends a Tweet message.

public function main() {
string status = "Welcome to Ballerina Twitter Connector!";
var tweetResponse = twitterClient->tweet(status);

if (tweetResponse is twitter:Status) {
io:println(tweetResponse);
} else {
log:printError("Failed to tweet: " + <string>tweetResponse.detail()["message"]);
}
}

Now, you must try and see. Execute the following commands to run your .bal file. You should get the details of your Twitter response printed on your terminal. Also, you can view your tweet from Twitter app as well.

$ ballerina run twitter-test.bal

You are done! It is as simple as that.

Happy coding with Ballerina!

Ballerina-Techblog

The Ballerina Tech Blog

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store