Ballerina Programming Language - best practices guide

Welcome to the best practices guide of Ballerina programming language!

Ballerina is an open-source programming language for the cloud that makes it easier to use, combine, and create network services.

This is a collection of best practices on using various Ballerina concepts and functionalities. This guide is opinionated and not Ballerina's official documentation. You won't find a list of every Ballerina syntax and standard library usage help here. Rather, you'll find a concise list of highly recommended options. The list is growing!

Let’s begin coding effectively in Ballerina.

If you are interested in contributing to this book, check out the contribution guidelines.

Project best practices

How to use Ballerina's features to create clean, effective code organized properly in the file system.

Language best practices

List of common Ballerina language best practices to follow.

Optionality and nil values

Values and types

Functions and parameters

Error handling

Records

Objects

Working with constants and strings

Conditionals

Query expressions

Common best practices guide

These are common some best practices which are common for any language.

Resources

Ballerina FAQ

Ballerina library samples

Project best practices

How to use Ballerina's features to create clean, effective code organized properly in the file system.

Structure your code

Well-organized code is very important for the maintainability of the project.

The goal is to best leverage Ballerina features to create clean, effective code. In practical terms, the proper structure makes clean code whose logic and dependencies are clear, as well as how the files and folders are organized in the filesystem.

The nomenclature

Single .bal file

  • Smallest unit of compilation in the Ballerina build system.
  • Can be used for simple applications and is not recommended for larger applications.

Package

  • Ballerina code is organized in a single shareable unit called a package.
  • A package is a collection of modules.
  • A package should contain at least one module called the default module.
  • It is common in small projects to have only one (default) module in a package. As a result, the default module’s content is placed directly in the root of the package director

Module

  • Module is a collection of Ballerina source files, test files, and resources.
  • Each module has its own directory, which organizes source files, test files, and resources.

Some signs of a poorly structured project

  • Doing everything on a single .bal file without leveraging the Ballerina packages/modules.
  • Having lots of unrelated components in the default module of the package without breaking them into multiple modules.
  • Lengthy .bal files without breaking the logic into meaningful files.
  • Heavy usage of global state or context, which is not needed.

Best practices to follow

Project Structure

  • Decide on the logical separation of your components and structure the project with modules accordingly.
  • Depending on the complexity and use case, break the code into multiple .bal files.

Naming and versioning

  • Use a proper org name and package name for your project in Ballerina.toml file.
  • When choosing an organization name, consider the restrictions for the organization name of a package when publishing to Ballerina Central. Organization names can only contain alphanumeric values with lowercase letters and cannot start with numeric values.
  • Follow Semantic Versioning when version the package.

Documentation

  • Properly document public APIs and functions exposed via the package.
  • Add up-to-date and meaningful overview of the package and modules in Package.md and Module.md files, as that will give a great overview for the users of your package.

See Also:

Naming conventions

Following are the naming conventions used in various Ballerina constructs. Some are opinionated rules but ensure consistency.

Organizations

  • Organization names can only contain alphanumeric values with lowercase letters and cannot start with numeric values.
  • Organization names starting with ballerina (e.g., ballerina, ballerinax, ballerinai, etc.) are reserved for system use, and you cannot publish any packages starting with the ballerina prefix to Ballerina Central.

Bad Names

7eleven
Google
ballerinac

Good Names

wso2
google

Packages and modules

  • Names can only contain alphanumerics, underscores, and periods and the maximum length is 256 characters.
  • Names can contain alphanumeric characters, including dots. Dots in a module name has no meaning other than the last segment after the final dot is used as a default alias within the source code.
  • When a package provides multiple functionalities, it is better to split it into multiple packages. For scenarios like this, you can give a hierarchical name to the package by using a dot (.).

Bad Names

Auth
HTTP
aws_s3

Good Names

auth
http
aws.s3

Files

  • Ballerina source files should have the extension .bal always.
  • Ballerina file names should all be simple.
  • Has to start with a character, and if the file name has multiple words, those words should be separated by an underscore (_).

Bad Names

StockQuoteService.bal
stockQuoteService.bal

Good Names

listner.bal
stock_quote_service.bal

Functions

  • Function names must be verbs in camel case, starting with a lowercase letter (i.e., lowerCamelCase).
  • Function parameters must be in camel case starting with a lowercase letter (i.e., lowerCamelCase).
  • Abbreviations and acronyms must not be uppercase when used in function names.

Bad Names

function TotalWidth()
function AddStudent( int age, string FullName)
function buildRSAPublicKey()

Good Names

function computeTotalWidth()
function addStudent( int age, string fullName)
function buildRsaPublicKey()

Variables

  • Variable names must be in camel case, starting with a lowercase letter (i.e., lowerCamelCase).

Bad Names

int Count;
string accountname;
string account_name;

Good Names

int count;
string accountName;

Constants

  • Constants must be all uppercase, using underscore to separate words.

Bad Names

const MAXSIZE = 1000;
const maxSize = 1000;

Good Names

const MAX_SIZE = 1000;

Objects and records

  • All object and record names must be nouns in camel case starting with an uppercase letter.
  • All object and record fields must follow normal variable naming rules.

Bad Names

public type Employee_Data record {|
    string first_Name;
    string LastName;
    int age;
|};

Good Names

public type Employee record {|
    string firstName;
    string lastName;
    int age;
|};

Clients

  • Name it to reflect the type of the client.
  • Avoid unnecesary repetitive words such as Client.

Bad Names

twilio:Client myClient = check new ({twilioAuth: {accountSId, authToken}});
twilio:Client c = check new ({twilioAuth: {accountSId, authToken}});
twilio:Client twilioClient = check new ({twilioAuth: {accountSId, authToken}});

Good Names

twilio:Client twilio = check new ({twilioAuth: {accountSId, authToken}});

Names with Abbrevations

  • When using abbreviations in names, treat the abbreviation as another word.

Bad Names

public function hashMD5(byte[] input) {

}
type LLMModel record {|
    
|};
string originalSHAValue;

Good Names

public function hashMd5(byte[] input) {

}
type LlmModel record {|
    
|};
string originalShaValue;

REST Service and resource paths

  • The service path represents the absolute path to the service. If the service path is omitted, then it defaults to /. Use meaningful grouping name if it is not omitting.
  • Use lowercase letters.
  • Try to use simple single words, but when it is needed to have multiple words use dashes instead of underscore.

Bad Names

service /MusicStore on new http:Listener(9090) {

}
service "/music_store" on new http:Listener(9090) {

}

Good Names

service "/store" on new http:Listener(9090) {

}
service "/music-store" on new http:Listener(9090) {

}

OR the same can be done as follows.

service /music\-store on new http:Listener(9090) {

}
  • Use nouns instead of verbs for resource function names. Verbs should not be used in endpoint paths.

Bad Names

service / on new http:Listener(9090) {

    resource function get getAlbums() returns Album[] {

    }
}

Good Names

service / on new http:Listener(9090) {

    resource function get albums() returns Album[] {

    }
}
  • Use plural resource nouns.

Use the plural form for resource nouns, because this fits all types of endpoints.

Bad Names

service / on new http:Listener(9090) {

    resource function get albums() returns Album[] {
        return [{title: "title1", artist: "artist1"}, {title: "title2", artist: "artist2"}];
    }

    resource function get album/[string title]() returns Album {
        return {title: "title1", artist: "artist1"};
    }
}

Good Names

service / on new http:Listener(9090) {

    resource function get albums() returns Album[] {
        return [{title: "title1", artist: "artist1"}, {title: "title2", artist: "artist2"}];
    }

    resource function get albums/[string title]() returns Album {
        return {title: "title1", artist: "artist1"};
    }
}

Format the code

Ballerina has an opiniated style guide. See Coding conventions

Those coding conventions are followed by the Ballerina formatting tool.

Use one of the following ways to format the source files.

  • Use bal format command - Formats the Ballerina source files. Formatting can be performed on a Ballerina package, module, or source file.

  • Use VSCode plugin formatting. Can use the following options.

    • Right-click on the source file and use the Format Document option.
    • Use format on save feature.

Order of the imports in a .bal file

The sorting makes it simple to browse the list when there are many imports.

  • First import the modules from same package.
  • Second comes modules from the ballerina/ and ballerinax/ organizations.
  • Third import the modules from 3rd party organizations.
  • Seperate each group by an extra line. And each group has their imports in alphabetical order.
import bar;
import foo;

import ballerina/log;
import ballerina/time;
import ballerinax/jdbc;
import ballerinax/oracledb;

import abc/bar;
import abc/baz;
import cde/abz;

See Also:

Logging

The Ballerina log module has four log levels with their priority in descending order as follows.

  1. ERROR
  2. WARN
  3. INFO
  4. DEBUG By default, all logs of the application that are INFO level and above are logged to the console.

Logging or Printing?

The io:println is a better option than logging when the goal is to display a help statement for a command line application.

  • Logs contain readily available diagnostic information, such as the time, module name, etc., of the logging event.
  • Logging can be selectively silenced by using the proper log levels.
  • Can set up log analytics.

Logging Best Practices

Set proper log level based on the application requirements.

Can have different log levels for different modules in the same package as well.

Suppose you want to set DEBUG level to the foo module, the ERROR level to the bar module, and WARN level to the rest of the modules in the package. You can achieve this by updating the Config.toml file as follows.

[ballerina.log]
level = "WARN"


[[ballerina.log.modules]]
name = "myorgname/mypackagename.foo"
level = "DEBUG"


[[ballerina.log.modules]]
name = "myorg/mypackagename.bar"
level = "ERROR"

Make use of string templates if the values need to be concatenated

Bad Code

int delay = 15;
int timeout = 30;
log:printInfo("Application started with delay " + delay.toString() + " seconds and timeout " + timeout.toString() + "seconds" );

Good Code

int delay = 15;
int timeout = 30;
log:printInfo(string `Application started with delay ${delay} seconds and timeout ${timeout} seconds`);

Make use of key-value pairs when logging

Even better log outputs can be generated if the key-value pairs are used.

Good Code

int delay = 15;
int timeout = 30;
log:printInfo("Application started", Delay = delay, Timeout = timeout);

Make use of function pointers to improve the performance

Bad Code

  • Suppose the current log level is INFO and there is a DEBUG log that logs a value returned from a function with heavy computations.
  • Since DEBUG level logs are not printed due to log level; ideally, the function with heavy computations should not be executed.
  • But in the below code, still, the getDuration function is executed even though the debug log line is printed.
import ballerina/log;
import ballerina/random;

public function main() {
    float duration = getDutration();
    log:printDebug("Checking the duration", duration = duration);
}

function getDutration() returns float {
    log:printInfo("Calculating duration");
    return random:createDecimal() * 100.0;
}

Good Code

  • Can avoid this by passing a pointer to the function as a value in a key/value pair like follows.
import ballerina/log;
import ballerina/random;

public function main() {
    log:printDebug("Checking the duration", duration = isolated function() returns float {
                       log:printInfo("Calculating duration optimally");
                       return random:createDecimal() * 100.0;});
}

See Also:

Documenting the source code

The Ballerina documentation framework allows developers to write the documentation in line with the Ballerina source code using the lightweight markdown markup language.

  • Always document all public constructs in your module.
  • As the best practice, document non-public constructs where necessary for better understandability.
  • Add meaningful and useful documentation without just repeating the construct name.
  • Add code snippets to make the usage clearer.

Documenting functions

Always add a period (.) at the end of a function description. However, for the parameter and return type descriptions, omit the period if you have only one sentence. If there are multiple sentences, add the period at the end of each sentence. For example,

# Description of the function.
#
# + i - One sentence only
# + s - Sentence one. Sentence two.
# + return - Return description
public function foo(int i, string s) returns boolean {
    return true;
}

Documenting records

Use the following approach to document the record and its fields.

# Fields of the Date record.
type DateFields record {
    # Year as an integer
    int year;
    # Month as an integer (1 <= month <= 12)
    int month;
    # Day as an integer (1 <= day <= 31)
    int day;
};

Documenting packages and modules

Ballerina documentation design and usage is aligned with the package and module semantics of Ballerina.

Use Package.md and Module.md files wisely to give the required information to the users.

Package.md

  • Displayed at the package landing page in the Ballerina central.
  • Must introduce and explain the package. If package has multiple modules, can give a summary on each module.
  • This is the place where you can market your package for more user visibility in the central. So add more meaningful content to package users.

Module.md

  • Displayed with the module API documentation
  • Must explain the functionality of the module

See Also:

Configuration management

Handle sensitive configurations

  • Configuration values containing passwords or secrets should not be passed with the normal configuration.
  • Sensitive data can be passed to runtime using a different TOML file, and we can prioritize it higher than the normal configuration by prefixing the file path in the BAL_CONFIG_FILES environment variable.
  • If Config.toml has sensitive configs, add Config.toml file into .gitignore to avoid accidental commits of those.
  • Avoid having default values for sensitive configurable values.

Have default values

When the project grows, there can be a large number of configurable variables. Without default values, it will be hard to deal with all. So have sensible default values for all non-security sensitive variables.

Bad Code

configurable int maxActiveConnections = ?;
configurable int maxIdleConnections = ?;

Good Code

configurable int maxActiveConnections = -1;
configurable int maxIdleConnections = 100;

Use descriptive names

Since the configuration variables are used to customize the program behavior, they should have unambiguous and descriptive names.

Bad Code

configurable int maxActive = -1;
configurable int maxIdle = 100;

Good Code

configurable int maxActiveConnections = -1;
configurable int maxIdleConnections = 100;

See Also:

Dependency management

Test with local repository

  • If you are a Ballerina library package developer, always use the local repository to test the package before pushing it to Central. Refer Use dependencies from the local repository. Once the package is published to Central, it cannot be deleted.

Dependency version resolution

  • By default, the compiler always looks up the latest compatible versions of the dependencies in the repositories when building a package. The latest patch version of the locked dependencies in Dependencies.toml will be automatically resolved.

    E.g. ballerina/io 1.0.0 is locked, 1.1.0 and 1.0.1 has been released. The compiler will pick 1.0.1 in the next build and will update the Dependencies.toml.

  • Dependencies.toml will be created if it is not available. The Dependencies.toml will always resolve to the latest compatible versions for the distribution you are using to build the project.

  • Updating to a compatible minor version is the user’s call. Specify the preferred minor version of the dependency in Ballerina.toml

Have reproducible builds vs getting latest dependency versions

  • However, if you need to achieve reproducible builds, use offline and sticky modes. Using the --offline flag along with the --sticky flag will ensure a predictable build with optimal time for compilation. It will stick to the exact versions locked in the Dependencies.toml.

  • If you need to make sure anyone who is working on the source code uses the latest versions of dependencies in their builds, do not commit the Dependencies.toml file to the source code repos. Since any dependency that you have used can be released with a new major version (which can contain incompatible changes), and when this dependency is resolved it would break your existing code.

Using platform-specific library libraries

  • When it is needed to package JAR files with the archives, maintain Java libraries inside the package. You can store the JAR files anywhere in your file system. As a best practice, maintain Java libraries inside the package. The platform-specific library information needs to be specified in the Ballerina.toml file.

    [[platform.java11.dependency]]
    # Absolute or relative path of the JAR file.
    path = "<path-to-jar-file-1>"
    # An optional comma-separated list of Ballerina module names (to restrict the usage of this JAR).
    modules = ["<ballerina-module-1>"]
    
  • Alternatively, you can also specify Maven dependencies as platform-specific libraries. These specified dependencies get resolved into the target/platform-libs directory when building the package.

    [[platform.java11.dependency]]
    # An optional comma-separated list of Ballerina module names (to restrict the usage of this JAR).
    modules = ["<ballerina-module-1>"]
    groupId = "<group-id>"
    artifactId = "<artifact-id>"
    version = "<version>"
    

See Also:

Language best practices

List of common Ballerina language best practices to follow.

Optionality and nil values

Values and types

Functions and parameters

Error handling

Records

Objects

Working with constants and strings

Conditionals

Query expressions

Represent optionality

Use nil (i.e. ()) to represent optional values.

Note: Use () instead of null unless it’s in a json context.

Example 1:

Use nil to indicate the unavailability of value.

Bad Code

type Employee record {
   string middleName = ""; //middleName is not specified
};

Good Code

type Employee record {
   string? middleName = ();
};

Example 2:

Return nil to indicate the unavailability of value.

Bad Code

function getMarks(string name) returns int {
    if marks.hasKey(name) {
        return marks.get(name);
    }
    return -1;
}

Good Code

function getMarks(string name) returns int? {
    if marks.hasKey(name) {
        return marks.get(name);
    }
    return ();
}

See Also:

Handle Nil values

Use the Elvis operator with proper default values or use errors when returning.

Elvis operator is a conditional operator that can be used to handle nil values. It evaluates an expression and, if the value is nil, executes the second expression. The Elvis operator takes two operands and uses the ?: symbol to form them.

Example 1:

Bad Code

int? age = ();
int validAge = <int>age;

Good Code

int? age = ();
int validAge = age ?: 0;

Example 2:

Bad Code

string? name = ();
string validName = name.toString();

Good Code

string? name = ();
string validName = name ?: "";

Example 3:

Bad Code

function getUsers() returns string[] {
    string[]? users = loadUsers();
    if users is string[] {
        return users;
    }
    return [];
}

function loadUsers() returns string[]? {
    //loading user code from DB or file etc
}

Good Code

Refer to the following options. We can use the elvis operator or can return error by explicitly checking for nil. Checking for nil is better than returning unrealistic default value in most cases.

Option 1:

function getUsers() returns string[] {
    string[]? users = loadUsers();
    return users ?: [];
}

Option 1:

function getUsers() returns string[]|error {
    string[]? users = loadUsers();
    if users is () {
        return error("Error in loading users");
    }
    return users;
}

See Also:

Use precise types

Using precise types will

  • Improve type checking at compile-time
  • Reduces the need for is checks and casts
  • Improve tooling experience: e.g., completion

Avoid overuse of var

Type inference allows the program to infer the actual data type of variables.

The use of var is a convenient way to use a generic type for a local variable and helps avoid repeated type declarations.

Code is usually more readable and maintainable when the type is declared explicitly. Therefore var should be used sparingly for variables used within a very limited scope, like in a foreach loop. Overusing it makes the code harder to understand.

Overuse of var

var name = "Alice";
var age = 30;
addUser(name, age);

Good Code

string name = "Alice";
int age = 30;
addUser(name, age);

Use application-defined types

Always use more application-defined type instead of json, any, anydata when you have more to do with that data.

Bad Code

http:Client httpClient = check new ("http://localhost:9090");
json albums = check httpClient->/albums;

Good Code

type Album readonly & record {|
    string title;
    string artist;
|};

http:Client httpClient = check new ("http://localhost:9090");
Album[] albums = check httpClient->/albums;

See Also:

Work with value ranges

Use range expressions.

Bad Code

function processData(string[] data) {
    int index = 0;
    foreach var val in data {
        index += 1;
        if (index == 1) {
            continue; // Need to skip the first value in array
        }
        io:println(val);
    }
}
  • Need to maintain a separate index.
  • Need to check whether the value equals to 1 in each iteration.

Good Code

function processData(string[] data) {
    foreach int lineNo in 1 ..< data.length() {
        io:println(data[lineNo]);
    }
}

See Also:

Avoid unnecessary type casts

  • Type casts result in panics if the cast fails.
  • Type casts may also get in the way of identifying certain incompatibilities that could be detected at compile-time.
  • Conditional type narrowing can be used to narrow the type of a variable, instead of using a cast.

Bad Code

import ballerina/io;

public function main() {
    int|string value = "10";
    io:println(increment(value)); //Will panic
}

function increment(int|string value) returns int {
    return <int>value + 1;
}

Good Code

import ballerina/io;

public function main() {
    int|string value = "10";
    io:println(increment(value));
}

function increment(int|string value) returns int|error {
    if value is int {
        // Type of `value` is narrowed to `int`
        return value + 1;
    }
    // Type of `value` is narrowed to `string`
    return check int:fromString(value) + 1;
}
  • Never use a cast when the cast can actually panic. Use value:ensureType which is similar to a type cast, but returns an error instead of panicking.

Good Code

import ballerina/io;

public function main() {
    int|string value = "10";
    io:println(increment(value)); //Will return error instead of panic
}

function increment(int|string value) returns int|error {
    return check value.ensureType(int) + 1;
}

See Also:

ensureType function

Using included record parameters

Including record fields as named arguments in a function provides a consistent experience to the caller.

Without included record parameters

The function register() has an int parameter admissionYear and a record parameter of the Student record type. This function can be called by directly passing a value of the Student record type as follows.

import ballerina/io;

type Student record {|
    string firstName;
    string? middleName = ();
    int age;
|};

public function main() {
    register(2005, {firstName: "John", age: 14});
}

function register(int admissionYear, Student student) {
    io:println(string `Registering ${student.firstName} for the year ${admissionYear}`);
    //Other logic..
}

Better approach

Alternatively, to pass individual named arguments for the different fields, it is possible to use an included record parameter. Note the * before the type.

Refer to the sample code to see different ways of passing parameters.

This way of including record fields as named arguments in a function provides a consistent experience to the caller.

import ballerina/io;

type Student record {|
    string firstName;
    string? middleName = ();
    int age;
|};

public function main() {
    register(admissionYear = 2023, firstName = "John", age = 14);
    register(2023, firstName = "Anne", age = 12);
    register(2024, {firstName: "Mary", age: 11});
}

function register(int admissionYear, *Student student) {
    io:println(string `Registering ${student.firstName} for the year ${admissionYear}`);
    //Other logic..
}

See Also:

Use expression-bodied functions

Expression-bodied functions can be used when the body is just a return statement.

Bad Code

function isValid(string username) returns boolean {
    return matchesCrieteria(username) && isAvailable(username);
}

Good Code

function isValid(string username) returns boolean 
    => matchesCrieteria(username) && isAvailable(username);

See Also:

Use tuples to return multiple values

The tuple type is a structured type which creates a list of values like arrays. The main difference between the arrays and the tuples is in a tuple type, you can individually specify the types for each member.

Bad Code

If the Product record is only used to return the values from the function it is not that useful.

type Product record {|
    int id;
    string name;
    float price;
|};

function getProductData() returns Product => {id: 1, name: "Ballerina", price: 99.9};

public function main() {
    Product product = getProductData();
}

Good Code

function getProductData() returns [int, string, float] => [1, "Product 1", 10.0];

public function main() {
    var [id, name, price] = getProductData();
    // id is int
    // name is string
    // price is float
}

Return errors and use the check

Do not return invalid values when an error occurs; instead return the error. As much as possible, avoid the use of T|error in variable declarations. Instead, use check and add error to the return type

Bad Code

function getStudentYear(int id) returns int {
    string|error name = getName(id);
    if name is error {
        return -1;
    } else {
        int|error ret = getYear(name);
        if ret is error {
            return -1;
        } else {
            return ret;
        }
    }
}

//Helper functions
function getName(int id) returns string|error {
    return error("Student not found");
}

function getYear(string name) returns int|error {
    return error("Student year not found");
}

Good Code

function getStudentYear(int id) returns int|error {
    string name = check getName(id);
    return getYear(name);
}

//Helper functions
function getName(int id) returns string|error {
    return error("Student not found");
}

function getYear(string name) returns int|error {
    return error("Student year not found");
}

See Also:

Avoid unnecessary usage of panic

  • An error value can also result in abrupt termination via panic if used in a panic statement.

  • Panicking is done via panic and checkpanic

  • Panic causes the worker/program to terminate unless trapped by the caller

  • It is OK for code to intentionally panic in a situation where a bug in the program's logic has been detected, which should be an extremely rare case. e.g.:

    • programming bug
    • division by zero
    • out of memory
  • Business logic-related errors would usually be returned.

Usage of checkpanic

  • checkpanic may be used if you want to terminate the program when a particular expression (or action) evaluates to an error.
  • It should be extremely rare to use checkpanic.

See Also:

Use open vs closed records

Definitions

Open records

The record {} is an inclusive record type-descriptor that allows any anydata field in addition to those explicitly specified in the record type-descriptor.That means it allows fields other than the explicitly specified fields.

type Person record {
    string name;
    string address;
    int age;
};

This defines a record type that will always have the three fields name, address, and age. Also in addition it may also contain any number of other fields that belong to the type anydata.

This record type is equivalent to explicitly specifying the rest descriptor as follows.

type Person record {
    string name;
    string address;
    int age;
    anydata...;
};

With the above definition any of the following is allowed.

Person p1 = {name: "Anne", address: "TX", age: 30};
Person f2 = {name: "Anne", address: "TX", age: 30, "country": "USA"};

Similarly, you can control the type of the other fields by specifying the type in the rest descriptor.

type Person record {|
    string name;
    string address;
    int age;
    int...; // Extra fields have to be ints
|};

To access these extra (rest) fields, you cannot use field access like p.id. Instead it is required to access as follows. anydata id = res["id"];

Closed records

The record {||} is an exclusive record type-descriptor. It will allow only the specified fields, and an attempt to convert a JSON object that has extra fields to a value of this type will fail.

type Person record {|
    string name;
    string address;
    int age;
|};

Usage

One of the key best practices for creating robust services is embodied in the so called Postels Law (or Robustness Principle). It states that any protocol implementation should

be conservative in what you send, be liberal in what you accept.

Good Code

import ballerina/http;

//Represent the incoming payload, so using open record
type ITunesResponse record {
    int resultCount;
    ITunesItem[] results;
};

type ITunesItem record {
    string collectionName;
    string trackName;
    string releaseDate;
    int trackTimeMillis;
};

//Represent the returned payload, so using closed record
type Track record {|
    string collection;
    string name;
    string releaseDate;
    int time;
|};

service /store on new http:Listener(8080) {

    resource function get tracks/[string track]() returns Track[]|error {
        http:Client iTunesClient = check new ("https://itunes.apple.com");
        ITunesResponse iTunesResponse = check iTunesClient->get("/search?entity=musicTrack&term="+track);
        return from ITunesItem i in iTunesResponse.results
        select {collection: i.collectionName, name: i.trackName, releaseDate: i.releaseDate, time:i.trackTimeMillis/1000};

    }
}

See Also

Simplify mapping constructor

If the variable name is equal to the key of the mapping constructor, we can simplify code {k: k} to {k}.

Bad Code

type Student record {|
    string name;
    int age;
    string city;
|};

function registerStudent(string name, int age) {
    Student s = {name: name, age: age, city: "London"};
    //...
}

Good Code

type Student record {|
    string name;
    int age;
    string city;
|};

function registerStudent(string name, int age) {
    Student s = {name, age, city: "London"};
    //...
}

Avoid unnecessary objects

Ballerina is an data oriented programming language, but it has support for classes and objects. Avoid unncessary usage of classes and objects.

Bad Code

import ballerina/http;

type Album readonly & record {|
    string title;
    string artist;
|};

service /store on new http:Listener(9090) {
    private final BookStore store;

    function init() {
        self.store = new BookStore();
    }

    resource function get albums(string title) returns Album|error {
        return self.store.getAlbums(title);
    }
}

class BookStore {

    private table<Album> key(title) albums;

    function init() {
        self.albums = table [
            {title: "Blue Train", artist: "John Coltrane"},
            {title: "Jeru", artist: "Gerry Mulligan"}
        ];
    }

    public function getAlbums(string title) returns Album|error {
        Album? album = self.albums[title];
        if album is () {
            return error("Album not found");
        }
        return album;
    }
}

Good Code

type Album readonly & record {|
    string title;
    string artist;
|};

service /store on new http:Listener(9090) {

    private table<Album> key(title) albums;

    function init() {
        self.albums = table [
            {title: "Blue Train", artist: "John Coltrane"},
            {title: "Jeru", artist: "Gerry Mulligan"}
        ];
    }

    resource function get albums(string title) returns Album|error {
        Album? album = self.albums[title];
        if album is () {
            return error("Album not found");
        }
        return album;
    }
}

See Also:

Using constants

The type is not required for constants.

Bad Code

const int MAX_SIZE = 1000;
const string FILE_NAME_PREFIX = "Summary";

Good Code

const MAX_SIZE = 1000;
const FILE_NAME_PREFIX = "Summary";

See Also:

Handle unions of string constants

Use enums, unions of singletons, or unions of constants. Enum seems to be a better option out of those three.

Let's say we have a string variable named department, which can only be Finance, Engineering, or HR.

Bad Code

type Employee record {|
   string name;
   string department;
|};
 
Employee e = {name: "John Doe", department: "HR"};
  • No idea what are the possible department types
  • Users can specify any string value as the department. It is syntactically correct but incorrect from the scenario point of view.

Good Code

Option 1: Usage of enums
enum Department {
   Finance,
   Engineering,
   HR
}
 
type Employee record {|
   string name;
   Department department;
|};
 
Employee e = {name: "John Doe", department: HR};

Note: Ballerina doesn't allow numeric enums.

Option 2: Unions of singletons
type Department "Finance"|"Engineering"|"HR";
 
type Employee record {|
   string name;
   Department department;
|};
 
Employee e = {name: "John Doe", department: "HR"};
Option 3: Unions of constants
const Eng = "Engineering";
const Fin = "Finance";
const HR = "HR";
 
type Department Eng|Fin|HR;
 
type Employee record {|
   string name;
   Department department;
|};
 
Employee e = {name: "John Doe", department: HR};

Conclusion

  • In all three approaches, the User can't specify anything other than specified values which is good.
  • Option 1: Enums is a better choice if we consider the readability and simplicity of the code.

See Also

Handle unions of integer constants

Use unions of singletons or unions of constants. Unions of constants seem to be a better option out of those three.

Let's say we have an int variable named priority which can only be 1, 2, or 3 where 1 is the highest priority.

Bad Code

type Issue record {|
   string title;
   int priority;
|};
 
Issue issue = {title: "Incorrect input parameters", priority: 1};
  • No idea what are the possible priority values
  • By looking at the issue value, we can't get a sense of priority level. Whether priority 1 means the highest priority or lowest priority.
  • Users can specify any int value as the priority. It is syntactically correct but incorrect from the scenario point of view.

Good Code

Option 1:Unions of singletons
type Priority 1|2|3;
 
type Issue record {|
  string title;
  Priority priority;
|};
 
Issue issue = {title: "Incorrect input parameters", priority: 1};
Option 2: Unions of constants
const HIGH = 1;
const MEDIUM = 2;
const LOW = 3;
 
type Priority HIGH|MEDIUM|LOW;
 
type Issue record {|
   string title;
   Priority priority;
|};
 
Issue issue = {title: "Incorrect input parameters", priority: HIGH};

Conclusion

  • Both Options 1 and 2 restrict the users from having arbitrary integer values for priority.
  • But in option 1, by looking at the priority value, we can't understand whether 1 means high or low.
  • So Option 2: Unions of constants is the best option.

See Also:

Concatenate string values

Use string backtick template.

A backtick template is composed of a tag followed by a backtick string, enclosed within the backtick notation, where you can have expressions that are enclosed in ${...}.

Bad Code

int age = 10;
string name = "Anne";
log:printInfo("Child name is " + name + " and age is " + age.toString());
  • Need to convert non string values to strings.
  • Need to handle spaces in the text properly along with the +.

Good Code

int age = 10;
string name = "Anne";
log:printInfo(string `Child name is ${name} and age is ${age}`);

See Also:

Avoid parentheses in if statement

Ballerina requires braces in if statements. But parentheses are not required around the condition.

Bad Code

if (x == 0) {
    //
}

Good Code

if x == 0 {
    //
}

See Also:

Using match statement

The match statement is similar to switch statement in C and JavaScript. It matches the value, not the type. If-else conditional branches are great for variable conditions that result into a boolean, whereas match statements are great for fixed data values.

Bad Code

function getDay(int date) returns string {
    if date == 0 {
        return "Sunday";
    } else if date == 1 {
        return "Monday";
    } else if date == 2 {
        return "Tuesday";
    } else if date == 3 {
        return "Wednesday";
    } else if date == 4 {
        return "Thursday";
    } else if date == 5 {
        return "Friday";
    } else if date == 6 {
        return "Saturday";
    } else {
        return "Invalid";
    }
}

Good Code

function getDay(int date) returns string {
    match date {
        0 => {
            return "Sunday";
        }
        1 => {
            return "Monday";
        }
        2 => {
            return "Tuesday";
        }
        3 => {
            return "Wednesday";
        }
        4 => {
            return "Thursday";
        }
        5 => {
            return "Friday";
        }
        6 => {
            return "Saturday";
        }
        _ => {
            return "Invalid";
        }
    }
}

See Also:

Query expressions for iterations

  • A query expression is similar to the SQL query syntax where you can construct a list, a mapping, a table, a stream, or a sequence by iterating over an iterable value.
  • It provides a convenient way to iterate while doing filtering and sorting as well.

Bad Code

import ballerina/io;

type CovidData record {
    string country;
    int cases;
    int population;
    int deaths;
};

type Country record {
    string name;
    int population;
    decimal caseFatalityRatio;
};

public function main() {
    CovidData[] covidData = getCovidData();

    Country[] countrySummary = [];
    int count = 0;
    foreach CovidData cd in covidData {
        if (cd.population > 5000 && cd.cases > 100) {
            decimal caseFatalityRatio = <decimal>cd.deaths / <decimal>cd.cases * 100;
            Country country = {name: cd.country, population: cd.population, caseFatalityRatio: caseFatalityRatio};
            countrySummary.push(country);
            count += 1;
            if (count == 3) {
                break;
            }
        }
    }
    io:println(countrySummary);
}

function getCovidData() returns CovidData[] {
    return [
        {country: "USA", cases: 1000000, population: 10000000, deaths: 10000},
        {country: "UK", cases: 100000, population: 1000000, deaths: 1000},
        {country: "India", cases: 10000, population: 100000, deaths: 100},
        {country: "Sri Lanka", cases: 1000, population: 10000, deaths: 10},
        {country: "Maldives", cases: 150, population: 1000, deaths: 1},
        {country: "Nepal", cases: 10, population: 100, deaths: 0}
    ];
}

Good Code

The iteration can be re-write as follows using query expressions.

Country[] countrySummary = from var {country, population, cases, deaths} in covidData
    where population > 5000 && cases > 100
    let decimal caseFatalityRatio = <decimal>deaths / <decimal>cases * 100
    order by caseFatalityRatio descending
    limit 3
    select {name: country, population, caseFatalityRatio};

Common best practices guide

These are common some best practices which are common for any language.

Use early returns

Use early returns to avoid nested if conditions. Then the code will become more readable and maintainable.

Note: If both if and else contain similar kinds of logic, don’t return early.

Bad Code

function handleCSVBodyParts(http:Request request) returns string[][]|error {
    var bodyParts = request.getBodyParts();
    if bodyParts is mime:Entity[] {
        string[][] csvLines = [];
        foreach var bodyPart in bodyParts {
            var mediaType = mime:getMediaType(bodyPart.getContentType());
            if mediaType is mime:MediaType {
                string baseType = mediaType.getBaseType();
                if "text/csv" == baseType {
                    byte[] payload = check bodyPart.getByteArray();
                    csvLines = check getCSVData(payload);
                } else {
                    return error("Invalid base type, not text/csv");
                }
            } else {
                return error("Invalid media type");
            }
        }
        return csvLines;
    } else {
        return error("Error in decoding multiparts!");
    }
}
  • Actual logic resides after many depths.
  • Code is not readable.

Good Code

function handleCSVBodyParts2(http:Request request) returns string[][]|error {
    mime:Entity[]|error bodyParts = request.getBodyParts();
    if bodyParts is error {
        return error("Error in decoding multiparts!");
    }
    string[][] csvLines = [];
    foreach var bodyPart in bodyParts {
        mime:MediaType|error mediaType = mime:getMediaType(bodyPart.getContentType());
        if mediaType is error {
            return error("Invalid media type");
        }
        string baseType = mediaType.getBaseType();
        if "text/csv" != baseType {
            return error("Invalid base type, not text/csv");
        }
        byte[] payload = check bodyPart.getByteArray();
        csvLines = check getCSVData(payload);
    }
    return csvLines;
}

See Also:

Avoid redundant variables

The intention of redundant variables is to increase readability. In reality, it makes the code more verbose and difficult to understand. Any variable used only once is redundant and must be replaced with a value.

Bad Code

type Employee record {|
    string name;
    int age;
    string department;
|};

function getEmployee(string name, int age, string department) returns Employee {
    Employee emp = {name, department, age};
    return emp;
}

Good Code

type Employee record {|
    string name;
    int age;
    string department;
|};

function getEmployee2(string name, int age, string department) returns Employee {
    return {name, department, age};
}

Avoid unnecessary comments

Clear and concise code is crucial for readability and maintainability. While comments can be helpful for explaining complex logic or providing context, excessive or unnecessary comments can indeed clutter the code and make it harder to understand.

It's important to strike a balance between using comments where they're truly needed and writing self-explanatory code that speaks for itself.

  • Comments should not duplicate the code.
  • Good comments do not excuse unclear code.

Bad Code

i = i + 1;         // Add one to i
//Validates the json input.
function validate(json input) returns boolean|error {
}

See Also:

Wrap code at 120 characters

It is conventional to wrap lines of code at 120 characters. This is usually IDE's default wrap margin, and it is the number of characters that can be displayed in GitHub's web UI without requiring horizontal scrolling.

Excessively long lines are indicative of a code quality issue, suggesting that a single statement is attempting to handle too much. Maintaining code lines at 120 characters or fewer enhances readability and ease of review.

  • It's advisable to refactor the code, ensuring it remains within the 120-character limit.
  • Alternatively, introduce line breaks strategically to aid readers in comprehending the code more effectively.

Bad Code

public function extractToolsFromOpenApiJsonSpec(map<json> openApiSpec, *AdditionInfoFlags additionInfoFlags) returns HttpApiSpecification & readonly|error {
    
}

Good Names

public function extractToolsFromOpenApiJsonSpec(map<json> openApiSpec, *AdditionInfoFlags additionInfoFlags) 
    returns HttpApiSpecification & readonly|error {
    
}

A universal and definitive formula for line-wrapping in all scenarios is absent. Frequently, multiple legitimate approaches exist for line-wrapping a given code segment.

See Also:

Use proper commit messages and PR titles

Effective Git commit messages and subject lines hold immense significance in comprehending alterations and enhancing the code's maintainability.

Always commit the changes to your fork and push them to the corresponding original repo by sending a Pull Request (PR). Follow the best practices for writing commit messages/PR titles.

  1. Limit the subject line to 50 characters

  2. Capitalize the subject line

  3. Do not end the subject line with a period

  4. Use the imperative mood in the subject line. A properly formed Git commit subject line should always be able to complete the following sentence:

    If applied, this commit will <your subject line here>

Bad commit messages/subject lines

Feature request for banking app - Violting 4th point above and not informative enough

Add minor changes - Not informative enough

Implementing XML to record converter - Violting 4th point above

fix GraalVM compatibility warnings after Java17 migration. - Violting 2nd and 3rd points above

Good commit messages/subject lines

Fix the failure to generate records from xml when multiple namespaces exist

Fix GraalVM compatibility warnings after Java17 migration

See Also

Awsome Ballerina

An uncurated list of Ballerina resources. Once you have an overview of the language, here are resources you can use to learn more.

This is grouped by different technical areas and ordered by the time.

Note: Since the language syntax has changed over the time, some resources may contain invalid code/details.

Ballerina projects

RepoDescriptionLast CommitTotal IssuesStarsContributors
bal-game-of-lifeSeveral iterations of Conway's Game Of LifeGitHub lastcommitGithub issuesGitHub starsGitHub contrib
GatewayService designed to manage and improve traffic to and from web applications and apisGitHub lastcommitGithub issuesGitHub starsGitHub contrib
Object MonitoringServer for moving object monitoring systemGitHub lastcommitGithub issuesGitHub starsGitHub contrib
msgpack-balImplementation of the msgpack specGitHub lastcommitGithub issuesGitHub starsGitHub contrib
DSA-with-BallerinaData structures and algo in BallerinaGitHub lastcommitGithub issuesGitHub starsGitHub contrib
Prettify JSONPrettify JSON valuesGitHub lastcommitGithub issuesGitHub starsGitHub contrib
JSON PathAPI to extract information from json valuesGitHub lastcommitGithub issuesGitHub starsGitHub contrib

Content (Articles/Blogs/Videos)

General

TypeTitleAuthorPublisehd Date
Video[Introductory] Integration with BallerinaBallerinalang2023-05-29
BlogA Quick Introduction to Ballerina: The Network-Aware Programming LanguageHasitha Aravinda2023-06-04
InfoWorldBallerina: A programming language for the cloudMartin Heller2023-03-08
PodcastSimplifying Cloud Native Application Development with BallerinaEric Newcomer2022-07-01
BlogSeven reasons to try out Ballerinashazni nazeer2022-06-28
InfoQWhy Ballerina is a languageJames Clark2022-05-04
TNSWhy Should You Program with Ballerina?Vishva Ahangama2022-04-21
InfoQBallerina for Full-Stack Developers: a Guide to Creating Backend APIsImesha Sudasingha2022-03-14
InfoQBallerina: a Data-Oriented Programming LanguageYehonathan Sharvit2022-05-10
VideoHighlights of Ballerina Swan Lake Release2021-06-29
BlogBallerina: Integration Programming LanguageAyesh Almeida2021-05-08
InfoQBallerina Swan Lake: 10 Compelling Language Characteristics for Cloud Native ProgrammingDakshitha Ratnayake2021-09-15
InfoQRethinking Programming: Language and Platform for Cloud-Era Application DevelopersLakmal W2022-03-15
InfoQJames Clark on How Ballerina Handles Network Interaction, Data, and ConcurrencyJames Clark2021-11-29
InfoQBallerina - An Open Source JVM Language and Platform for Cloud-Era Application ProgrammersMichael Redlich2020-01-29
BlogBallerina — Part 1: ConceptJames Clark2019-09-12
BlogBallerina — Part 0: ContextJames Clark2019-09-11
BlogBallerina: Why a New Programming LanguageShafreen Anfar2019-06-02
BlogThe top ten articles about BallerinaAnjana Fernando2018-09-05
InfoQBallerina Microservices Programming Language: Introducing the Latest Release and "Ballerina Central"Tyler Jewell2018-05-29
BlogBallerinaLang — Visual Programming and its Role in Service IntegrationNadeeshaan Gunasinghe2017-08-27
DZoneBallerina Dances Onto the Integration StageSteve Gertiser2017-07-27
DZoneGetting Started With Ballerina in 10 MinutesChanaka Fernando2017-03-08
DZoneMaking Integration Great AgainChanaka Fernando2017-02-22

Listings

TypeTitleAuthorPublisehd Date
Article8 Lesser-Known Programming Languages Worth ExploringRocky2023-07-12
Blog10 Lesser-Known Programming Languages Revolutionizing the Tech Industry (July 2023 Edition)Arslan Mirza2023-07-03
ArticleTop Microservices Frameworks to Build Scalable ApplicationsParth Patel2023-06-19
Blog14 Programming Languages You’ve Probably Never Heard OfClement Brian2023-04-12
ArticleTOP 12 MICROSERVICES FRAMEWORKSVishal Shah2023-02-17
Article7 Best Programming Languages for MicroservicesJosh Wulf2022-09-27

Language Concepts

General Language

Error handling
TypeTitleAuthorPublisehd Date
SOErrors and Error Handling in Ballerina - Part II - Error SubtypesMaryam Ziyad2023-05-10
SOErrors and Error Handling in Ballerina - Part IMaryam Ziyad2023-04-24
Blog[Ballerina] Error Handling — Part IIMaryam Ziyad2019-12-24
Blog[Ballerina] Error Handling — Part IMaryam Ziyad2019-09-28
JSON
TypeTitleAuthorPublisehd Date
BlogIntuitive REST APIs and JSON Handling With Ballerina Programming LanguageDakshitha Ratnayake2022-05-05
Blog[Ballerina] Working with JSON — JSON to record conversionMaryam Ziyad2021-01-27
Blog[Ballerina] Converting CSV to JSONMaryam Ziyad2019-09-25
BlogBallerina’s JSON type and lax static typingMaryam Ziyad2019-09-13
XML
TypeTitleAuthorPublisehd Date
VideoXML ManipulationBallerinalang2023-05-29
DZoneXML Processing Made Easy with BallerinaAnjana Fernando2020-10-26
Records
TypeTitleAuthorPublisehd Date
BlogMapping values in Ballerina: maps and recordsMaryam Ziyad2024-01-19
Immutability
TypeTitleAuthorPublisehd Date
BlogImmutability in Ballerina — Part IMaryam Ziyad2021-09-26
BlogImmutable Values in BallerinaMaryam Ziyad2018-12-13
Binding Patterns
TypeTitleAuthorPublisehd Date
DZoneUsing Binding Patterns in BallerinaSuleka Helmini2021-10-20
DZoneBinding Patterns in BallerinaSuleka Helmini2021-10-19
Functions
TypeTitleAuthorPublisehd Date
BlogHello, World! Program in BallerinaAyesh Almeida2021-05-09
BlogDefaultable Parameters in BallerinaRajith Vitharana2019-12-10
BlogChanging the “main” functionMaryam Ziyad2018-10-04
Type conversions
TypeTitleAuthorPublisehd Date
Blog[Ballerina] Casting and Conversions — Part II — Stamping, Cloning and ConvertingMaryam Ziyad2018-12-11
Blog[Ballerina] Casting and Conversions — Part IMaryam Ziyad2018-12-11
Language integrated queries
TypeTitleAuthorPublisehd Date
InfoQData Manipulation with Functional Programming and Queries in BallerinaYehonathan Sharvit2022-08-11
SOEfficient Joins with Ballerina Query ExpressionsLasini Liyanage2022-06-29
SOQuery Expressions in BallerinaLasini Liyanage2022-06-22
VideoUsing Language Integrated Queries2021-09-28
DZoneLanguage Integrated Queries In BallerinaMohanadarshan Vivekanandalingam2020-10-16
Services and Listners
TypeTitleAuthorPublisehd Date
Blog[Attaching multiple services to the same listener in BallerinaMaryam Ziyad2023-12-30
VideoServices and Network Communication2021-02-03
Regular Expressions
TypeTitleAuthorPublisehd Date
VideoRegular Expressions - An IntroductionBallerinalang2023-05-28
VideoBend it like Ballerina: Unveiling our Regex SupportBallerinalang2023-05-08
Other Data types
TypeTitleAuthorPublisehd Date
BlogBallerina: Behavioral TypesAyesh Almeida2021-06-26
BlogBallerina: Data TypesAyesh Almeida2021-05-09
DZoneWorking With Data in MicroservicesLakmal Warusawithana2020-04-14
BlogIntroduction to Ballerina TablesAnupama Pathirage2018-09-23
BlogBallerina Object type and all you need to knowRajith Vitharana2018-07-12
BlogCoding in meaningful way(Identifier literal support in ballerina ).Rajith Vitharana2017-05-14
BlogAny type support in ballerinaRajith Vitharana2017-05-04
Statements
TypeTitleAuthorPublisehd Date
BlogControl Structures in BallerinaAyesh Almeida2021-01-04
Identifiers
TypeTitleAuthorPublisehd Date
BlogBallerina Identifiers: A Simple Guide for New DevelopersHasitha Aravinda2023-03-15

Data structures and algorithms

TypeTitleAuthorPublisehd Date
BlogRepresenting Graph Data Structure in BallerinaPrakanth2023-06-22
BlogData Structures and Algorithms with BallerinaTharindu Udupitiya2023-05-19
BlogBallerina Collections: TablesAyesh Almeida2022-03-10
BlogBallerina Collections: Arrays & MapsAyesh Almeida2022-02-22
BlogBasic Algorithms using BallerinaAyesh Almeida2022-02-20
BlogParallel Merge Sort with BallerinaKishanthan Thangarajah2018-11-11

Compiler

TypeTitleAuthorPublisehd Date
BlogBallerina Compilation ProcessRajith Vitharana2019-12-17

Compiler Plugin

TypeTitleAuthorPublisehd Date
BlogModule Import Restriction with Ballerina Code AnalyzersGayal Dassanayake2023-09-04

Concurrency

TypeTitleAuthorPublisehd Date
DZoneConcurrency-Safe Execution Using Ballerina IsolationHinduja Balasubramaniyam2021-11-07
BlogBallerina Concurrency Model and Non-Blocking I/OAnjana Fernando2021-02-22
BlogUnveiling Ballerina Non-Blocking ArchitectureVinod Kavinda2019-09-30
BlogConcurrency in Ballerina (Workers, Send, Receive, Flush, Wait …)Vinod Kavinda2018-12-28
BlogConcurrency control in Ballerina (Field based locking)Vinod Kavinda2018 Dev 16
BlogBallerina: Concurrency Done Right!Anjana Fernando2018-04-29
BlogConcurrency Management in Ballerina (Lock statement)Rajith Vitharana2018-04-28
BlogA Glimpse Inside Workers In BallerinaNatasha Wijesekare2018-12-25
BlogBallerina ChannelsVinod Kavinda2018-10-09

Java interoperability

TypeTitleAuthorPublisehd Date
BlogCall a User-Defined Java Method from BallerinaDulmina Renuke2023-11-15
VideoJava Interoperability in Ballerina2020-12-08
BlogBallerina Interop and all you need to knowRajith Vitharana2019-12-10

Transactions

TypeTitleAuthorPublisehd Date
DZonePractical Transaction Handling in Microservice ArchitectureAnjana Fernando2020-12-01

Streams

TypeTitleAuthorPublisehd Date
BlogLets write a window in BallerinaGimantha Bandara2019-03-11
BlogWriting Ballerina Streaming ExtensionsGrainier Perera2019-03-11

Workflows

TypeTitleAuthorPublisehd Date
BlogSimple Long Running Workflows with BallerinaAnjana Fernando2018-10-08

Runtime

TypeTitleAuthorPublisehd Date
BlogUnveiling Ballerina GraalVM image: A comparative analysisKrishnananthalingam Tharmigan2024-01-02
BlogBallerina meets GraalVM in the Cloud: A Winning Formula for Cloud-Native ApplicationsKrishnananthalingam Tharmigan2023-09-01
BlogUnveiling Ballerina GraalVM image: Tackling Production IssuesKrishnananthalingam Tharmigan2023-08-14
BlogBallerina meets GraalVM: From code to native executableKrishnananthalingam Tharmigan2024-08-13
BlogBallerina Program Execution FlowNadeeshan Dissanayake2023-07-07
BlogDeep Dive Into Ballerina RuntimeJayod2023-02-03

Ballerina library

HTTP

TypeTitleAuthorPublisehd Date
SOImplementing a REST API with Ballerinashazni nazeer2022-12-20
VideoChanges in the HTTP Package in Ballerina Swan Lake2021-07-27
BlogSingle Liner Payload Read…Chamil Elladeniya2021-06-06
BlogHTTP Deep-Dive with Ballerina: ServicesAnjana Fernando2021-01-28
DZoneHTTP Deep-Dive With Ballerina: Client CommunicationAnjana Fernando2020-12-17
BlogRequest dispatching patterns of Ballerina HTTP serviceChamil Elladeniya2019-09-19
BlogImplementing a Simple Web Server using BallerinaHemika Kodikara2019-04-24
BlogEat My Dust! : Making of Ballerina’s Lightning Fast HTTP TransportShafreen Anfar2019-02-23
BlogIntercepting HTTP requests in BallerinaVinod Kavinda2018-11-13
BlogHTTP Caching in Ballerina - Part IPubudu Fernando2018-11-13

HTTP2

TypeTitleAuthorPublisehd Date
BlogHow to play with HTTP/2 in BallerinaChanaka Lakmal2018-08-01

GraphQL

TypeTitleAuthorPublisehd Date
BlogGraphQL Federation with Ballerina and Apollo — Part IIThisaru Guruge2023-10-03
BlogGraphQL Federation with Ballerina and Apollo — Part IThisaru Guruge2023-10-02
BlogData Modeling and Exposing Made Easy with Ballerina Persist and GraphQLShammi Kolonne2023-07-05
SOAn Intro to GraphQL Federation with Ballerina GraphQLMohamed Sabthar2023-04-24
BlogGraphQL Subscriptions with Apache Kafka in BallerinaThisaru Guruge2023-02-06
BlogGraphQL Subscriptions with Ballerina: A Step-By-Step GuideNuvindu Dias2022-09-30
BlogUsing GraphQL and Ballerina with Multiple Data SourcesAnupama Pathirage2022-07-01
VideoGraphQL and Ballerina: A Match Made in Heaven2021-08-31
BlogREST is History, Let’s Do GraphQL (with Ballerina)Thisaru Guruge2021-06-29
BlogIntroduction to GraphQL with BallerinaAnjana Fernando2021-02-09

WebSocket

TypeTitleAuthorPublisehd Date
BlogImplementing a Websocket Server using Ballerinashazni nazeer2023-05-04
BlogBallerina WebSocket Service — The AnatomyBhashinee Nirmali2022-05-24
BlogReal-Time Stock Data Updates with WebSockets using BallerinaBhashinee Nirmali2021-11-26
BlogGo Real-Time with Ballerina WebSocketsBhashinee Nirmali2021-07-28
TNSAn Introduction to WebSockets with BallerinaAnjana Fernando2020-12-18
VideoHow to use WebSocket with BallerinaAnjana Fernando2020-11-05

Pub/Sub

TypeTitleAuthorPublisehd Date
BlogAn Introduction to Pub/Sub in BallerinaNuvindu Dias2022-09-30

SerDes

TypeTitleAuthorPublisehd Date
BlogSerialization and Deserialization with Ballerina SerDes moduleMohomed Sabthar2022-08-16

Email

TypeTitleAuthorPublisehd Date
BlogSending Emails with BallerinaShammi Kolonne2022-08-16

File

TypeTitleAuthorPublisehd Date
BlogHow to download a large file using BallerinaAnupama Pathirage2022-06-22
BlogHow to download a file from URL using BallerinaAnupama Pathirage2022-06-20

Websub and webhooks

TypeTitleAuthorPublisehd Date
BlogLearning Websub (Part 4) : Connecting a Message BrokerAyesh Almeida2023-03-12
BlogLearning Websub (Part 3) : Integrating OpenWeatherMap APIAyesh Almeida2023-03-10
BlogLearning WebSub (Part 2) : Building a WebSub hub using BallerinaAyesh Almeida2023-03-08
BlogLearning WebSub (Part 1) : Introduction to WebSubAyesh Almeida2023-03-06
VideoBuilding Real-time Systems with WebSub2021-11-30
BlogEvent-Driven APIs With Webhook and WebSubAnupama Pathirage2021-11-08
Blog[Ballerina] Registering a GitHub WebhookMaryam Ziyad2018-08-12
Blog[Ballerina] Event Notification via WebhooksMaryam Ziyad2018-07-21

gRPC

TypeTitleAuthorPublisehd Date
BlogIntroduction to gRPC on BallerinaAnupama Pathirage2021-08-28
VideogRPC in Ballerina2020-09-01
InfoQBuilding Effective Microservices with gRPC, Ballerina, and GoLakmal W2020-08-25
DZonegRPC Basics: Why, When, and How?Anjana Fernando2020-07-24
BlogBallerina + gRPCBuddhi Kothalawala2020-04-07

Database

TypeTitleAuthorPublisehd Date
BlogMastering Ballerina SQL Clients: Your Go-To GuideNiveathika2022-12-01
BlogGuarding Against SQL Injection in Ballerina ApplicationsNiveathika2022-11-28
BlogData Modeling and Exposing Made Easy with Ballerina Persist and GraphQLShammi Kolonne2023-07-05
SOGuidelines and best practices for Ballerina SQL client usagesNiveathika2022-12-18
SOAvoiding SQL Injection in BallerinaNiveathika2022-12-08
SOInteracting with a RDBMS using BallerinaExtremum2022-09-21
SOCreate a Data API with Ballerina and H2Dakshitha Ratnayake2022-07-17
BlogInteracting with a RDBMS using Ballerinashazni nazeer2022-09-21
BlogConnecting to and using Google’s Cloud SQL with BallerinaKaneel Dias2021-10-21
VideoData Access in Ballerina2020-11-10
BlogSQL Injection — Introduction with BallerinaAnupama Pathirage2020-08-03
BlogInteract with an Oracle database with BallerinaManuri Perera2019-03-30
BlogContainerized Ballerina service with a MongoDB data backendManuri Perera2018-11-25
BlogHow to connect to MongoDB Atlas with BallerinaManuri Perera2018-11-02
Blog[Ballerina] Database connection pool exhausted?Manuri Perera2018-10-27
BlogData Access for MicroservicesAnjana Fernando2018-08-21
BlogXA transaction example with Ballerina — Oracle and MySQL as resource managersManuri Perera2018-08-13
BlogUsing a Ballerina table as a proxy to an actual database tableManuri Perera2018-08-12
BlogInteract with a Postgresql database with Ballerina!Manuri Perera2018-08-12
BlogOracle RefCursor Example with BallerinaManuri Perera2018-08-11
BlogOracle PL/SQL example with BallerinaManuri Perera2018-08-09
Blog“select” iterable operation on Ballerina tablesManuri Perera2018-08-13
BlogRedis Caching example with Ballerina !Anupama Pathirage2018-07-21
BlogConnect to your data with BallerinaManuri Perera2018-07-08
BlogInsert batch of data to DB using BallerinaAnupama Pathirage2018-06-09
BlogTalking to a database with BallerinaManuri Perera2018-04-30
BlogBallerina JDBC Client — Performing DB OperationsAnupama Pathirage2017-12-02
BlogBallerina JDBC Client— Connecting to DBAnupama Pathirage2017-11-26
BlogData Integration with BallerinaAnupama Pathirage2017-11-25

Kafka

TypeTitleAuthorPublisehd Date
BlogBallerina Kafka Serialization with AvroThisaru Guruge2020-05-05
BlogBuilding a Simple Review Filtering System Using Ballerina KafkaThisaru Guruge2019-02-12
BlogGetting Started with Ballerina KafkaThisaru Guruge2019-02-05

Time

TypeTitleAuthorPublisehd Date
BlogA guide for Date/Time conversion in Ballerina Languagesahanhe2023-12-17
SOA guide for Date/Time conversion in Ballerina Languagesahanhe2022-08-08

Cache

TypeTitleAuthorPublisehd Date
BlogRedesigning of Ballerina CacheChanaka Lakmal2020-06-27

FTP

TypeTitleAuthorPublisehd Date
BlogBallerina FTP clientBhashinee Nirmali2021-07-14

SOAP

TypeTitleAuthorPublisehd Date
BlogBallerina SOAP ConnectorBhashinee Nirmali2019-04-17

Encoding/Decoding

TypeTitleAuthorPublisehd Date
SODifferent Types of Encoding/Decoding with BallerinaChanaka Lakmal2022-07-28

CSV I/O

TypeTitleAuthorPublisehd Date
SOUpload CSV files to Ballerina ServiceAnupama Pathirage2022-09-01

Persist

TypeTitleAuthorPublisehd Date
BlogEnhanced Data Management: Google Sheets Empowered by bal persistSahan Hemachandra2023-12-17

Extended Library

AI

TypeTitleAuthorPublisehd Date
SOUnleash the Power of AI: Develop a Question Answering Service with OpenAI and BallerinaJayani Hewavitharana2023-05-15

GitHub

TypeTitleAuthorPublisehd Date
BlogUse Ballerina Github Connector to interact with GithubCharuka Udupitiya2023-02-20

RabbitMQ

TypeTitleAuthorPublisehd Date
BlogConnecting Ballerina to CloudAMQP: A Quick GuideArshika Mohottige2024-01-07
BlogMastering Work Queues in RabbitMQ with BallerinaArshika Mohottige2023-11-08
SORabbitMQ Tutorials in Ballerina. - Part 1Arshika Mohottige2023-05-15

Salesforce

TypeTitleAuthorPublisehd Date
BlogSeamless Salesforce Integration with BallerinaArshika Mohottige2024-02-22
BlogIntegrations — A key for getting the most out of SalesforceChathura Ekanayake2023-11-13
BlogHarvesting Sales Data from B2B ChannelsChathura Ekanayake2023-09-05

AWS Redshift

TypeTitleAuthorPublisehd Date
BlogAmazon Redshift Integration with BallerinaArshika Mohottige2024-02-05
BlogConnecting Ballerina to AWS Redshift: A Quick GuideArshika Mohottige2024-01-07

NATS

TypeTitleAuthorPublisehd Date
BlogSimplifying Distributed Systems with NATS and BallerinaArshika Mohottige2024-01-23

Security

Ballerina security overview

TypeTitleAuthor
WebsiteBallerina securityChanaka Lakmal

Microservices Security

TypeTitleAuthorPublisehd Date
BlogHTTP Security in BallerinaChanaka Lakmal2021-08-10
BlogMicroservices Security with BallerinaChanaka Lakmal2021-08-02
BlogSecurely invoking a Client Endpoint in BallerinaChanaka Lakmal2018-05-21

OAuth

TypeTitleAuthorPublisehd Date
BlogAuthenticate A Shopify App Using OAuth — The Ballerina WayThisaru Guruge2020-06-02

OAuth2

TypeTitleAuthorPublisehd Date
BlogSecuring Microservices with OAuth2Chanaka Lakmal2022-02-28

JWT

TypeTitleAuthorPublisehd Date
BlogSecuring Microservices with JWTChanaka Lakmal2021-10-21

OSCP

TypeTitleAuthorPublisehd Date
BlogCRL, OCSP and OCSP stapling validation with BallerinaBhashinee Nirmali2018-09-15
Blog[Ballerina] Enable OCSP stapling in BallerinaBhashinee Nirmali2018-08-13

TLS/SSL

TypeTitleAuthorPublisehd Date
BlogTransport layer security in Ballerina — SSL/TLS with HTTPAnupama Pathirage2023-05-19
BlogConfiguring Transport Layer Security (TLS/SSL) in Ballerina ClientBhashinee Nirmali2019-10-02
BlogConfigure Ciphers and SSL protocols in BallerinaBhashinee Nirmali2017-10-30
BlogSSL Mutual Authentication with BallerinaBhashinee Nirmali2017-10-28

OpenID

TypeTitleAuthorPublisehd Date
SOSecure a Ballerina REST API with OpenID Connect using Asgardeo-Part 2Dakshitha Ratnayake2022-09-16
SOSecure a Ballerina REST API with OpenID Connect using Asgardeo-Part 1Dakshitha Ratnayake2022-08-10
DZoneBuilding a Secure REST API with OpenID ConnectAnjana Fernando2020-07-14

Taint Checking (Deprecated)

TypeTitleAuthorPublisehd Date
BlogBallerina taint checking guideDhananjaya Wicramasingha2019-09-25

Cloud

Kubernetes/C2C

TypeTitleAuthorPublisehd Date
BlogBuild A Container with Zero Effort in Zero Time with BallerinaThevakumar Luheerathan2023-07-03
DZoneDeploying Ballerina Code on the CloudAnuruddha Liyanarachchi2021-11-18
VideoCode to Cloud with Ballerina2021-01-26
DZoneMicroservices in Practice: Deployment Shouldn't Be an AfterthoughtLakmal Warusawithana2020-07-06
DZoneHow Ballerina Makes Deploying to Kubernetes Easier for DevelopersLakmal Warusawithana2020-02-13
DZoneGenerate Kubernetes YAML Right From Your App CodeDmitry Sotnikov2018-07-11
DZoneMicroservices, Docker, Kubernetes, Serverless, Service Mesh, and BeyondChanaka Fernando2018-05-11

AWS Step Functions

TypeTitleAuthorPublisehd Date
BlogPractical Serverless: Long-Running Workflows with Human Interactions using Step Functions and BallerinaAnjana Fernando2020-09-27

AWS Lambda

TypeTitleAuthorPublisehd Date
BlogExpose a simple Ballerina program as an AWS Lambda FunctionPraneesha Chandrasiri2023-07-13
VideoServerless in Ballerina2020-10-13
BlogPractical Serverless: Integrating Amazon S3 and Rekognition with BallerinaAnjana Fernando2020-08-31
BlogTest your Ballerina Function written for AWS LambdaHemika Kodikara2020-02-20
TNSA Step-by-Step Guide For AWS Lambda Deployments with BallerinaAnjana Fernando2019-05-28
DZoneRunning a Ballerina Service as a Serverless Function in AWS LambdaIsuru Perera2018-01-19
DZoneImplementing Serverless Functions With Ballerina on AWS LambdaImesh Gunaratne2017-06-27

Azure functions

TypeTitleAuthorPublisehd Date
BlogInvoke an Azure Function via a Cosmos DB Trigger Using BallerinaPraneesha Chandrasiri2023-09-07
SOBuilding Azure Functions Project With BallerinaAnjana Supun2022-11-04
BlogPractical Serverless: A Scalable OCR Solution in 10 MinutesAnjana Fernando2020-08-03
BlogIntroduction to Azure Functions in BallerinaAnjana Fernando2020-07-23
VideoBallerina Azure Functions Walk-throughAnjana Fernando2020-07-23

Azure services

TypeTitleAuthorPublisehd Date
DZoneProduction Grade Ballerina Microservices on Azure AKS - Part 2: Continuous Integration With Azure DevOpsDunith Dhanushka2020-09-01
DZoneProduction-Grade Microservices on Azure AKS With Ballerina — Part 1: The BasicsDunith Dhanushka2020-05-28
BlogBallerina/Azure Cloud Case Study: Scalable Asynchronous Request ProcessingAnjana Fernando2019-03-06

OpenShift

TypeTitleAuthorPublisehd Date
BlogBallerina Services on OpenShiftHemika Kodikara2019-03-21

Observability

TypeTitleAuthorPublisehd Date
BlogObserve Ballerina Integrations with New Relic ExtensionNipuna Madhushan2023-12-15
BlogObserve Ballerina Programs with New RelicNipuna Madhushan2023-10-06
DZoneAutomated Microservices Observability in the CloudAnjana Fernando2021-10-12
DZoneRethinking Programming: Automated ObservabilityAnjana Fernando2020-05-01

Tooling

OpenAPI

TypeTitleAuthorPublisehd Date
SOGenerating proper OpenAPI Documentation for Ballerina Resource APIsSumudu Nissanka2022-06-18
VideoBallerina OpenAPI Support 2022-01-25
BlogIntroduction to OpenAPI with BallerinaAnupama Pathirage2021-09-04
BlogMake your Own Ballerina Client Connector using the Ballerina OpenAPI ToolSumudu Nissanka2021-07-23
BlogHow Ballerina OpenAPI Tool addresses your Code-First and Design-First API ApproachesSumudu Nissanka2021-04-04
BlogSuper Cool Feature for your Ballerina service from Ballerina OpenAPI toolSumudu Nissanka2021-07-23
BlogGenerating a Mock Service for BallerinaImesh Chandrasiri2019-10-01

AsyncAPI

TypeTitleAuthorPublisehd Date
BlogLearn how to use the AsyncAPI contract with cloud-native programming language Ballerina to benefit your API developmentSumudu Nissanka2022-07-28

Ballerina CLI tool

TypeTitleAuthorPublisehd Date
DZoneDeveloping Ballerina Project With Ballerina CLI ToolDhanushka Madushan2020-03-11
BlogBallerina tool for distribution managementTharik Kanaka2019-12-25

SemVer validator

TypeTitleAuthorPublisehd Date
BlogIntroduction to Ballerina Semantic Versioning ValidatorNipuna Ranasinghe2022-09-19

Strand dump tool

TypeTitleAuthorPublisehd Date
BlogTroubleshoot Ballerina runtime using the strand dumpNadeeshan Dissanayake2022-10-10

Ballerina shell

TypeTitleAuthorPublisehd Date
VideoBallerina Shell and Debugging Tools2021-03-30
BlogBallerina Shell REPL — Implementation OverviewSunera Avinash2021-03-01
BlogBallerina Shell — A REPL for BallerinaSunera Avinash2021-02-28

Debugger

TypeTitleAuthorPublisehd Date
BlogA Practical Guide to Ballerina Remote DebuggingPraveen Nadarajah2021-03-31

Homebrew

TypeTitleAuthorPublisehd Date
BlogHow we built Ballerina Homebrew FormulaRasika Perera2019-01-06

Editor

VS Code

TypeTitleAuthorPublisehd Date
VideoBallerina Architecture ViewBallerinalang2023-06-01
VideoNew HTTP API DesignerBallerinalang2023-05-30
BlogBallerina statement editorMadusha Gunasekara2022-09-20
VideoBallerina Programming with VS Code 2022-02-23
BlogBallerina Development With VSCodeNadeeshaan Gunasinghe2018-11-04
BlogBallerina VSCode Plugin — Graphical Editor for BallerinaNadeeshaan Gunasinghe2018-11-03
BlogBallerina VSCode Plugin — Language IntelligenceNadeeshaan Gunasinghe2018-11-03
BlogSetting Up VSCode for Ballerina Development in 60 SecondsNadeeshaan Gunasinghe2018-09-07

Language Server

TypeTitleAuthorPublisehd Date
BlogA Practical Guide for Language Server ProtocolMalintha Ranasinghe2022-06-28
BlogImplementing a Language Server… How Hard Can It Be? — Part 3Nipuna Marcus2020-01-14
BlogImplementing a Language Server…How Hard Can It Be?? — Part 2Nipuna Marcus2019-09-30
BlogImplementing a Language Server…How Hard Can It Be?? — Part 1 (Introduction)Nipuna Marcus2018-03-07
BlogBallerina Language Server — Demystifying Goto DefinitionNadeeshaan Gunasinghe2019-12-31
BlogExtending Ballerina Language Server — Auto-CompletionNadeeshaan Gunasinghe2019-11-17
BlogLanguage Server for Ballerina— Auto Completion Engine in DepthNadeeshaan Gunasinghe2018-05-07

IntelliJIDEA

TypeTitleAuthorPublisehd Date
BlogBallerina Hello World: The IntelliJ Style!Nipuna Ranasinghe2021-04-12
BlogSetting up Ballerina in IntelliJ IDEAShan Mahanama2017-11-14

Composer (Deprecated)

TypeTitleAuthorPublisehd Date
BlogBallerina Composer — Tutorial (Part II — Function Definitions)Nadeeshaan Gunasinghe2017-02-28
BlogBallerina Composer — Tutorial (Part II — Function Definitions)Nadeeshaan Gunasinghe2017-02-28
BlogBallerina Composer — Flexible, powerful and Smartest ever graphical tool for composing your Ballerina ProgramsNadeeshaan Gunasinghe2017-02-22

Testing

TypeTitleAuthorPublisehd Date
BlogUnit test Ballerina integration with Mock backendsAquib Zulfikar2021-08-17
BlogGet started with service testing using Ballerina test frameworkFathima Dilhasha2021-08-17

Logging

TypeTitleAuthorPublisehd Date
DZoneIntegrating Humio With Ballerina for Microservices LoggingPJ Hagerty2020-02-25

Configuration management

TypeTitleAuthorPublisehd Date
BlogConfiguration Management in BallerinaPubudu Fernando2019-01-01
BlogMaking Use of the Ballerina Config APIPubudu Fernando2017-11-11

Package management

TypeTitleAuthorPublisehd Date
VideoPackage Management with BallerinaBallerinalang2023-05-29
VideoDeprecate a Ballerina Package VersionBallerinalang2023-05-28
DZoneHow to Use Ballerina Local RepositoryPramodya Mendis2021-12-10
VideoManaging Dependencies in Ballerina2021-10-26
BlogInternals of Module Management in BallerinaNatasha Wijesekare2018-12-23
BlogCheat Sheet for Ballerina Commands associated with Module ManagementNatasha Wijesekare2018-10-21

Building and installing Ballerina

TypeTitleAuthorPublisehd Date
BlogBuilding Ballerina from SourcesAyesh Almeida2021-05-11
BlogInstalling Ballerina: The hard wayShan Mahanama2019-09-18

Ballerina Connectors

TypeTitleAuthorPublisehd Date
BlogHow to Write a Connector in BallerinaChanaka Lakmal2018-05-14
BlogBallerina Native Client Connectors and all you need to know :)Rajith Vitharana2017-11-12
BlogBallerina Connectors/Endpoints and What? How? Why?Rajith Vitharana2017-11-08
BlogPlug custom native functions to BallerinaRajith Vitharana2017-07-02

CI/CD

TypeTitleAuthorPublisehd Date
BlogStreamline Your Ballerina Workflow on GitHub with setup-ballerina GitHub ActionHasitha Aravinda2023-03-03
BlogCI/CD Cloud Workflows with GitHub Actions and BallerinaAnjana Fernando2019-05-09
DZoneEffective Microservices CI/CD With GitHub Actions and BallerinaAnjana Fernando2020-02-25

Comparisons with other languages

TypeTitleAuthorPublisehd Date
TechtargetA 7-point language comparison of Ballerina vs. GolangKerry Doyle2022-06-30
BlogHow to Create a REST API — Spring Boot and BallerinaNadeeshaan Gunasinghe2022-02-18
BloggRPC Compression Support in Go, Java, and BallerinaBuddhi Kothalawala2021-10-22
BlogEcho Websocket service example — GO vs NodeJs vs BallerinaBhashinee Nirmali2020-10-31
DZoneFile-Based Integration: Spring Integration vs BallerinaAnjana Fernando2019-12-23
BlogSpring Boot vs Ballerina: Back-end For Front-end (BFF) ServiceShafreen Anfar2019-12-21
BlogConverting a Spring Boot Service To BallerinaAnjana Fernando2019-11-27
BlogSpring Boot vs Ballerina: Hello-World ServiceShafreen Anfar2019-11-22
BlogManaging data using Ballerina vs GoAnupama Pathirage2018-12-19
BlogDockerize services written in Go, SpringBoot & Ballerina — A comparisonKishanthan Thangarajah2018-12-14
DZoneHow Ballerina  Is Different From Other Programming LanguagesChanaka Fernando2017-03-02

Usecases

TypeTitleAuthorPublisehd Date
SODocument Your GitHub Repo Changes to Google Sheets Using BallerinaTharushi J2022-10-10
SOServer for moving object monitoring system in Ballerina - Final partKavindu Zoysa2023-03-11
SOServer for moving object monitoring system in Ballerina - Part 3Kavindu Zoysa2022-10-23
SOServer for moving object monitoring system in Ballerina - Part 2Kavindu Zoysa2022-09-22
SOServer for moving object monitoring system in Ballerina - Part 1Kavindu Zoysa2022-09-01
BlogGet Daily Exchange Rates via SMS Using BallerinaMalintha Ranasinghe2022-08-25
BlogOverview of manipulating data in Ballerina with different APIs (PayPal API and randomuser.me)Dulaj Dilshan2022-08-16
BlogUncovering Interesting 2020 Olympics Stats with Ballerina Language-integrated QueriesImesha Sudasingha2021-09-16
BlogExtract data from a mail and upload it to a Google Spreadsheet using Ballerina IntegratorAquib Zulfikar2020-01-02
Blog[Ballerina] Event Notification via WebhooksMaryam Ziyad2018-05-01
DZoneThree Programming Languages That Will Drive Enterprise DevelopmentChanaka Fernando2019-09-19
InfoQBuilding an API Gateway with the Ballerina Programming LanguageNuwan Dias2018-07-18
BlogTweet my Stars, Ballerina!Shan Mahanama2017-10-23

User stories

TypeTitleAuthorPublisehd Date
TNSHow MOSIP Uses Ballerina WebSubHub for Event-Driven IntegrationDakshitha Ratnayake2022-06-28
BlogBuild Employee Onboarding Automation With WSO2 Ballerina & ChoreoSudaraka Jayashanka2022-11-01

Integration and design Patterns

TypeTitleAuthorPublisehd Date
BlogBusiness to Business integration with BallerinaChathura Ekanayake2023-06-20
ArticleThe future of SaaS middlewareEILEEN O'CONNOR2022-12-07
DZonePractical Microservices Development Patterns: Sync vs. AsyncAnjana Fernando2020-07-06
DZoneReactive Microservices Done Right!Anjana Fernando2020-06-24
BlogClone and Aggregate Integration Pattern with BallerinaShafreen Anfar2018-12-23
DZoneRethinking Service Integrations With Microservices ArchitectureImesh Gunaratne2017-03-03

Ballerina FAQ!

What is Ballerina?

  • Ballerina is a general-purpose, open-source programming language.
  • It specializes in solving integration/API integration/network interactions & cloud-based problems by providing the right level of language abstractions and tools.
  • Ballerina is NOT a JVM language.
  • Ballerina is a programming language which is
    • compiled : (Compiled languages are converted directly into machine code that the processor can execute. C, C++, Rust, Go are examples. In interpreted Languages, interpreters run through a program line by line and execute each command. PHP, Ruby, Python are examples. )
    • type safe
    • concurrent
  • Ballerina is neither an object oriented language nor a functional one.
    • While the language has objects, the development methods are not completely OOP-based.
    • Both objects and functions are first class concepts, giving developers the ability to choose the best option based on their requirements.
  • It has two implementations.
    • jBallerina - written in java to run on top of JVM. This is the first implementation to prove the language.
    • nBallerina - Compiled using LLVM, directly to the platform architecture.

Why do we need a new programming language?

What there is in the Ballerina language and platform that could not be done except with a new language and platform?

  • networking: networking abstractions for services and clients
  • data and types: support for plain data(anydata), structured data (maps and arrays), collections (tables) and the ability to transform to and from json/xml easily.
  • concurrency: The graphical view of a function as a sequence diagram provided by the VS Code extension shows not only how the function accesses network services, but also the concurrent logic of the function. The language's worker-based concurrency primitives are designed for this graphical view. Isolation concept and readonly types etc which guarantee compile-time safety for data races.

Is Ballerina an object-oriented language?

  • Ballerina is neither an object-oriented language nor a functional one.
  • While the Language has objects, the development methods are not completely OOP-based.
  • Both objects and functions are first-class concepts, giving developers the ability to choose the best option based on their requirements.
  • It is data-oriented.

Why is Ballerina data-oriented?

  • The primary focus is on represent, describe, communicate pure data.
  • Ballerina makes it easy for the user to transfer, declare, manipulate, process and query the data.

Is Ballerina JVM language?

Ballerina is NOT a JVM language. It has two implementations.

  • jBallerina - written in java to run on top of JVM. This is the first implementation as a proof-of-concept of the Language. Although it's implemented on top of the JVM, it does not embrace the JVM. It is designed with the goal that we can do another implementation that does not use the JVM, and the user code will run unchanged. (We do provide JVM interop features, but that is specifically for when you want to interop with existing JVM code.)
  • nBallerina - Compiled using LLVM, directly to the platform architecture.

Is Ballerina a language or platform?

Ballerina is a new programming language and is also a platform.

Language: This is the core and it's the part that's defined in the language specification.

Platform: the Language has been designed in conjunction with key components of the surrounding ecosystem, which we called platform. The platform includes:

  • a standard library
  • a centralized module repository, and the tooling needed to support that
  • a documentation system (based on Markdown)
  • a testing framework
  • extensions/plug-ins for popular IDEs (notably Visual Studio Code).

What are the unique features of Ballerina?

  • Data-oriented - Ballerina makes it easy for the user to transfer, declare, manipulate, process and query the data.
  • Network oriented - Ballerina has language constructs/concepts which capture network primitives. (E.g., type system concepts to easily bind data coming via network to language types, service types, client types, etc.)
  • Graphical representation - Can easily explain network interactions via sequence diagrams. Each program has both a textual syntax and an equivalent graphical form based on sequence diagrams
  • Enterprise-grade application development - Built-in concurrency, Explicit error handling, transactions, full life cycle management concepts including testing, documenting, configurability, dependency management & versioning
  • Cloud-Native - Reduces the gap between development to deployment and makes it easier for the developer to write the application and instruct how it should be deployed in the cloud.

What are the special things about Ballerina type system?

Ballerina is a statically typed language.

That means that every variable has a type that is known at compile time.

Ballerina has structural type system.

A static type checker uses either the names or the structure of the types in order to compare them against other types. Checking against the name is nominal typing and checking against the structure is structural typing.

So in Ballerina, type compatibility is identified by considering the structure of the value rather than just relying on the name of the type.

All mainstream object-oriented languages use nominal subtyping. For ex: Java has no structural subtyping at all; all subtype relationships must be explicitly declared.

Ballerina has semantic subtyping.

The syntax - describes which strings of of characters comprise a valid program. i.e., the form of the language.

The semantics - describes what syntactically valid programs mean, what they do. i.e. the meaning of the language.

Semantic subtyping is an approach for defining subtyping relation based on set-theoretic models, rather than syntactic rules.

Type is a set of values. When is an assignment, x = y legal?

There are at least two possible answers:

  1. When x and y are of equal types

    Structural type checking decides that.

  2. When y’s type can be “converted” to x’s type

    • Once we consider types as set of values, we realize immediately one set may be a subset of another set.
    • When the set of values in one type, T, is a subset of the set of values in another type, U, we say that T is a subtype of U.
    • There are two main approaches for defining the subtyping relation:
      • syntactic approach - it is defined by means of a formal system of deduction rules
      • semantic approach - It is defined based on set theories. The subtyping relation is defined as inclusion of sets denoting types. Ballerina is using this approach.

Semantic subtyping is most useful for expressing types of tree-structured data, such as JSON.

Ballerina has network aware type system.

Ballerina's type system is specifically focused on aiding the development of networked and distributed applications. It has constructs that seamlessly map to network programming concepts such as services and network resources.

What are the values and types in Ballerina?

Ballerina programs operate on a rich universe of values. This universe of values is partitioned into a number of basic types; every value belongs to exactly one basic type.

A variable has a type, which constrains what values the variable can hold.

Values are of four kinds, each corresponding to a kind of basic type:

  1. Simple values - which are not constructed from other values;
    • nil, boolean, int, float, decimal
  2. Structured values - which contain other values. They are containers for other values, which are called their members.
    • array, map, record, table, tuple
  3. Sequence values - which consists of an ordered sequence of zero or more constituent items, where the constituent items belong to the same basic type as the sequence value itself.
    • string, xml
  4. Behavioral values- which are not just data
    • function, object, error, stream, future, typedesc
  5. Other - which allows some flexibility to define custom types based on the combination of two or more types.
    • any, anydata, json, byte and union

What is Langlib?

This is a library which provides fundamentnal operations on built-in datatypes. There is a ballerina/lang.T module for each built-in type T and they are automatically imported using T prefix.

We can call Langlib functions in two ways and both produce the same result.

Currently there is Langlib module for following built-in types.

  • For Simple Types - lang.boolean, lang.int, lang.float, lang.decimal
  • For Structured Types - lang.array, lang.map, lang.table
  • For Sequence Types - lang.string, lang.xml
  • For Behavioral Types - lang.object, lang.error, lang.stream, lang.future, lang.typedesc
  • For common types, provides functions that work on values of more than one basic type - lang.value

Other than above modules for built-in types Langlib has following modules as well.

  • For functions related to language runtime - lang.runtime
  • For functions related to transactions - lang.transaction

Langlib functions can be called in two different ways.

Using method call syntax

import ballerina/io;

public function main() {
    // Can call using the conventinent method-call syntax.
    string s = "hello World".substring(1, 2);

    io:println(s);
}

Using as a module function

import ballerina/io;

public function main() {
    // Can call as a langlib module function. No need to import explicitly. 
    string s = string:substring("Hello World", 1, 2);

    io:println(s);
}

What is the future of the Language?

The long-term vision for Ballerina includes a number of important features which are not yet implemented but which have a foundation in existing language features.

  • Event streams (unbounded streams of records with timestamps). Be able to both generate them and query them (using various kinds of windows). Related to this is more first-class support for a client subscribing to a stream of events from the server.
  • Network security. Language support to help the user avoid network security problems (we have experimented with a feature similar to tainting in Perl); this can leverage the explicitness of network interactions in Ballerina.
  • Workflow. Support long-running process execution. Be able to suspend a program and later resume it as a result of an incoming network message. This also requires that transactions get better support for compensation.

Is Ballerina only for WSO2 usage?

Ballerina's development is funded by WSO2 and WSO2's ultimate goal is to create a product that is useful to its customers. But Ballerina is not itself the product: both Ballerina the Language and Ballerina the platform are free and open source.

Ballerina library samples

List of integration samples for Ballerina library packages.

Twilio Connector - Ballerina

In today’s interconnected world, communication is key, and what better way to enhance your application’s communication capabilities than by integrating Twilio with the Ballerina programming language?

Ballerina, known for its simplicity and power in building cloud-native integrations, combines with Twilio’s versatile communication APIs to help you send SMS, make voice calls, send WhatsApp messages, and more.

In this guide, we’ll explore how the ballerinax/twilio package can empower you to build robust communication features effortlessly. Refer to ballerina/twilio API Docs for more details.

Prerequisites

Sample 1: Send/Receive Calls and Messages With Ballerina

Create a new Ballerina package using the command below.

bal new send-receive-with-twilio

This creates a new Ballerina package in the default module with the Ballerina.toml file, which identifies a directory as a package and a sample source file (i.e., main.bal) with a main function.

To provide the configurations required, create a new file named `Config.toml`` and add the send/receive phone numbers, SID, and auth token received from Twilio. The file structure within the package will look like below.

Alt text

Add the following code to main.bal file.

import ballerina/log;
import ballerinax/twilio;

configurable string accountSId = ?;
configurable string authToken = ?;
configurable string fromNumber = ?;
configurable string fromWhatsAppNumber = ?;
configurable string toNumber = ?;

configurable string message = "This is a test message from Ballerina";

//Create Twilio client
final twilio:Client twilio = check new ({twilioAuth: {accountSId, authToken}});

public function main() returns error? {
    //Send SMS
    twilio:SmsResponse smsResponse = check twilio->sendSms(fromNumber, toNumber, message);
    log:printInfo(string `SMS Response: ${smsResponse.toString()}`);

    //Get the details of SMS sent above
    twilio:MessageResourceResponse details = check twilio->getMessage(smsResponse.sid);
    log:printInfo("Message Detail: " + details.toString());

    //Make a voice call
    twilio:VoiceCallResponse voiceResponse = check twilio->makeVoiceCall(fromNumber, toNumber, {
        userInput: message,
        userInputType: twilio:MESSAGE_IN_TEXT
    });
    log:printInfo(string `Voice Call Response: ${voiceResponse.toString()}`);

    //Send whatsapp message
    twilio:WhatsAppResponse whatsappResponse = check twilio->sendWhatsAppMessage(fromWhatsAppNumber, toNumber, message);
    log:printInfo(string `WhatsApp Response: ${whatsappResponse.toString()}`);

    // Get Account Details
    twilio:Account accountDetails = check twilio->getAccountDetails();
    log:printInfo(string `Account Details: ${accountDetails.toString()}`);

}

Add the configuration values to the Config.toml file. It will look like below.

accountSId="xxxxxxxxxxxxxxxxxxxxxxx"
authToken="xxxxxxxxxxxxxxxxxxxxxxx"
fromNumber="+1xxxxxxxxxx"
fromWhatsAppNumber="+1xxxxxxxxxx"
toNumber="+1xxxxxxxxxx"

Then, run the program using bal run command, and you will see the following logs.

time = 2023-08-29T16:54:47.536-05:00 level = INFO module = anupama/twilio_samples message = "SMS Response: {\"sid\":\"SM12099885cce2c78bf5f50903ca83d3ac\",\"dateCreated\":\"Tue, 29 Aug 2023 21:54:47 +0000\",\"dateUpdated\":\"Tue, 29 Aug 2023 21:54:47 +0000\",\"dateSent\":\"\",\"accountSid\":\"xxxxxxxxxxxxx\",\"toNumber\":\"+1xxxxxxxxxx\",\"fromNumber\":\"+1xxxxxxxxxx\",\"body\":\"Sent from your Twilio trial account - This is a test message from Ballerina\",\"status\":\"queued\",\"direction\":\"outbound-api\",\"apiVersion\":\"2010-04-01\",\"price\":\"\",\"priceUnit\":\"USD\",\"uri\":\"/2010-04-01/Accounts/xxxxxxxxxxxxx/Messages/SM12099885cce2c78bf5f50903ca83d3ac.json\",\"numSegments\":\"1\"}"
time = 2023-08-29T16:54:47.694-05:00 level = INFO module = anupama/twilio_samples message = "Message Detail: {\"body\":\"Sent from your Twilio trial account - This is a test message from Ballerina\",\"numSegments\":\"1\",\"direction\":\"outbound-api\",\"fromNumber\":\"outbound-api\",\"toNumber\":\"+1xxxxxxxxxx\",\"dateUpdated\":\"Tue, 29 Aug 2023 21:54:47 +0000\",\"price\":\"\",\"errorMessage\":\"\",\"uri\":\"/2010-04-01/Accounts/xxxxxxxxxxxxx/Messages/SM12099885cce2c78bf5f50903ca83d3ac.json\",\"accountSid\":\"xxxxxxxxxxxxx\",\"numMedia\":\"0\",\"status\":\"sent\",\"messagingServiceSid\":\"\",\"sid\":\"SM12099885cce2c78bf5f50903ca83d3ac\",\"dateSent\":\"Tue, 29 Aug 2023 21:54:47 +0000\",\"dateCreated\":\"Tue, 29 Aug 2023 21:54:47 +0000\",\"errorCode\":\"\",\"priceUnit\":\"USD\",\"apiVersion\":\"2010-04-01\",\"subresourceUris\":\"{\"media\":\"/2010-04-01/Accounts/xxxxxxxxxxxxx/Messages/SM12099885cce2c78bf5f50903ca83d3ac/Media.json\",\"feedback\":\"/2010-04-01/Accounts/xxxxxxxxxxxxx/Messages/SM12099885cce2c78bf5f50903ca83d3ac/Feedback.json\"}\"}"
time = 2023-08-29T16:54:47.828-05:00 level = INFO module = anupama/twilio_samples message = "Voice Call Response: {\"sid\":\"CAaa2e5a5c7591928f7e28c79da97e615a\",\"status\":\"queued\",\"price\":\"\",\"priceUnit\":\"USD\"}"
time = 2023-08-29T16:54:47.993-05:00 level = INFO module = anupama/twilio_samples message = "WhatsApp Response: {\"sid\":\"SM3c272753409bd4814a60c7fd06d97232\",\"dateCreated\":\"Tue, 29 Aug 2023 21:54:47 +0000\",\"dateUpdated\":\"Tue, 29 Aug 2023 21:54:47 +0000\",\"dateSent\":\"\",\"accountSid\":\"xxxxxxxxxxxxx\",\"toNumber\":\"whatsapp:+1xxxxxxxxxx\",\"fromNumber\":\"whatsapp:+1xxxxxxxxxx\",\"messageServiceSid\":\"\",\"body\":\"This is a test message from Ballerina\",\"status\":\"queued\",\"numSegments\":\"1\",\"numMedia\":\"0\",\"direction\":\"outbound-api\",\"apiVersion\":\"2010-04-01\",\"price\":\"\",\"priceUnit\":\"\",\"errorCode\":\"\",\"errorMessage\":\"\",\"uri\":\"\",\"subresourceUris\":\"{\"media\":\"/2010-04-01/Accounts/xxxxxxxxxxxxx/Messages/SM3c272753409bd4814a60c7fd06d97232/Media.json\"}\"}"
time = 2023-08-29T16:54:48.076-05:00 level = INFO module = anupama/twilio_samples message = "Account Details: {\"sid\":\"xxxxxxxxxxxxx\",\"name\":\"My first Twilio account\",\"status\":\"active\",\"type\":\"Trial\",\"createdDate\":\"Fri, 18 Aug 2023 21:14:20 +0000\",\"updatedDate\":\"Fri, 18 Aug 2023 21:14:54 +0000\"}"

Also, you will get an SMS, a voice call, and a WhatsApp message to the specified number.

Are you interested in seeing this sample's sequence diagram generated by the Ballerina VS Code plugin? You can see the interactions with Twilio clearly in this diagram without reading the code. The Sequence diagram can capture how the logic of your program flows, how the concurrent execution flow works, which remote endpoints are involved, and how those endpoints interact with the different workers in the program. See the Sequence diagram view for more details.

Alt text

Complete code

Refer to the code in send-receive-with-twilio

Sample 2: Use TwiML for Programmable Messaging With Ballerina

The TwiML (Twilio Markup Language) is a set of instructions you can use to tell Twilio what to do when you receive an incoming call, SMS, MMS, or WhatsApp message.

Let’s see how to write a Ballerina program that makes a voice call with the instructions of the given TwiML URL. Here, we need to have a URL that returns TwiML Voice instructions to make the call.

If you don’t have such a URL that returns TwiML, you can write a simple Ballerina HTTP service to return it as follows and run it. The instruction returned by this service will contain a bell sound, which is looped ten times.

import ballerina/http;

service /twilio on new http:Listener(9090) {

    resource function post voice() returns xml {
        xml response = xml `<?xml version="1.0" encoding="UTF-8"?>
        <Response>
            <Play loop="10">https://api.twilio.com/cowbell.mp3</Play>
        </Response>`;
        return response;
    }
}

If you are running the above service locally, you need to expose it to external so that it can be accessed by Twilio when making the call. You can use ngrok for that, which is a cross-platform application that enables developers to expose a local development server to the Internet with minimal effort.

Expose the above service with the following ngrok command.

./ngrok http 9090

This will return a URL similar to the following:

https://a624-2600-1700-1bd0-1390-9587-3a61-a470-879b.ngrok.io

Then, you can append it with the service path and resource path in your above Ballerina service to be used with the Twilio voice call example.

https://a624-2600-1700-1bd0-1390-9587-3a61-a470-879b.ngrok.io/twilio/voice

Next, write your Ballerina code as follows. Use the above complete ngrok URL as the voiceTwimUrl configurable.

import ballerina/log;
import ballerinax/twilio;

configurable string accountSId = ?;
configurable string authToken = ?;
configurable string fromNumber = ?;
configurable string toNumber = ?;
configurable string voiceTwimUrl = ?;

//Create Twilio client
final twilio:Client twilio = check new ({twilioAuth: {accountSId, authToken}});

public function main() returns error? {
    //Make a voice call
    twilio:VoiceCallResponse voiceResponse = check twilio->makeVoiceCall(fromNumber, toNumber, {
        userInput: voiceTwimUrl,
        userInputType: twilio:TWIML_URL
    });
    log:printInfo(string `Voice Call Response: ${voiceResponse.toString()}`);

}

When running the program, you will receive a phone call to the specified number with a Bell sound of 10 times. You can see the below logs in your Ballerina application.

time = 2023-08-29T17:03:13.804-05:00 level = INFO module = anupama/twilio_samples message = "Voice Call Response: {\"sid\":\"CA3d8f5cd381a4eaae1028728f00770f00\",\"status\":\"queued\",\"price\":\"\",\"priceUnit\":\"USD\"}"

Complete code for instruction server

Refer to the code in twiml-instruction-server

Complete code for instruction server

Refer to the code in twiml-voice-call

Conclusion

In conclusion, Twilio’s synergy with Ballerina through the ballerinax/twilio package presents a powerful tool for elevating your application’s communication prowess. The showcased sample code highlights its ease and adaptability, setting it apart from connectors in other languages.

Hope you’ve enjoyed making calls and sending messages using this seamless integration.