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.
- Structure your code
- Naming conventions
- Format the code
- Logging
- Documenting the source code
- Configuration management
- Dependency management
Language best practices
List of common Ballerina language best practices to follow.
Optionality and nil values
Values and types
Functions and parameters
- Using included record parameters
- Use expression-bodied functions
- Use tuples to return multiple values
Error handling
Records
Objects
Working with constants and strings
- Using constants
- Handle unions of string constants
- Handle unions of integer constants
- Concatenate string values
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
- Naming conventions
- Coding Style
- Logging
- Documenting the source code
- Configuration management
- Dependency management
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 andpackage
name for your project inBallerina.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
andModule.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 theballerina
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 theservice 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.
- Right-click on the source file and use the
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/
andballerinax/
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.
- ERROR
- WARN
- INFO
- 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, addConfig.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
and1.0.1
has been released. The compiler will pick1.0.1
in the next build and will update theDependencies.toml
. -
Dependencies.toml
will be created if it is not available. TheDependencies.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 theDependencies.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
- Using included record parameters
- Use expression-bodied functions
- Use tuples to return multiple values
Error handling
Records
Objects
Working with constants and strings
- Using constants
- Handle unions of string constants
- Handle unions of integer constants
- Generate string by concatenating values
Conditionals
Query expressions
Represent optionality
Use nil (i.e. ()
) to represent optional values.
Note: Use
()
instead ofnull
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:
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
andcheckpanic
-
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
- Avoid redundant variables
- Avoid unnecessary comments
- Wrap code at 120 characters
- Use proper commit messages and PR titles
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.
-
Limit the subject line to 50 characters
-
Capitalize the subject line
-
Do not end the subject line with a period
-
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.
- Awsome Ballerina
- Ballerina projects
- Content (Articles/Blogs/Videos)
- General
- Listings
- Language Concepts
- Runtime
- Ballerina Library
- Extended Library
- Security
- Cloud
- Observability
- Tooling
- Editor
- Testing
- Logging
- Configuration management
- Package management
- Building and installing Ballerina
- Ballerina Connectors
- CI/CD
- Comparisons with other languages
- Usecases
- User stories
- Integration and design Patterns
Ballerina projects
Repo | Description | Last Commit | Total Issues | Stars | Contributors |
---|---|---|---|---|---|
bal-game-of-life | Several iterations of Conway's Game Of Life | ||||
Gateway | Service designed to manage and improve traffic to and from web applications and apis | ||||
Object Monitoring | Server for moving object monitoring system | ||||
msgpack-bal | Implementation of the msgpack spec | ||||
DSA-with-Ballerina | Data structures and algo in Ballerina | ||||
Prettify JSON | Prettify JSON values | ||||
JSON Path | API to extract information from json values |
Content (Articles/Blogs/Videos)
General
Listings
Type | Title | Author | Publisehd Date |
---|---|---|---|
Article | 8 Lesser-Known Programming Languages Worth Exploring | Rocky | 2023-07-12 |
Blog | 10 Lesser-Known Programming Languages Revolutionizing the Tech Industry (July 2023 Edition) | Arslan Mirza | 2023-07-03 |
Article | Top Microservices Frameworks to Build Scalable Applications | Parth Patel | 2023-06-19 |
Blog | 14 Programming Languages You’ve Probably Never Heard Of | Clement Brian | 2023-04-12 |
Article | TOP 12 MICROSERVICES FRAMEWORKS | Vishal Shah | 2023-02-17 |
Article | 7 Best Programming Languages for Microservices | Josh Wulf | 2022-09-27 |
Language Concepts
General Language
Error handling
Type | Title | Author | Publisehd Date |
---|---|---|---|
SO | Errors and Error Handling in Ballerina - Part II - Error Subtypes | Maryam Ziyad | 2023-05-10 |
SO | Errors and Error Handling in Ballerina - Part I | Maryam Ziyad | 2023-04-24 |
Blog | [Ballerina] Error Handling — Part II | Maryam Ziyad | 2019-12-24 |
Blog | [Ballerina] Error Handling — Part I | Maryam Ziyad | 2019-09-28 |
JSON
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Intuitive REST APIs and JSON Handling With Ballerina Programming Language | Dakshitha Ratnayake | 2022-05-05 |
Blog | [Ballerina] Working with JSON — JSON to record conversion | Maryam Ziyad | 2021-01-27 |
Blog | [Ballerina] Converting CSV to JSON | Maryam Ziyad | 2019-09-25 |
Blog | Ballerina’s JSON type and lax static typing | Maryam Ziyad | 2019-09-13 |
XML
Type | Title | Author | Publisehd Date |
---|---|---|---|
Video | XML Manipulation | Ballerinalang | 2023-05-29 |
DZone | XML Processing Made Easy with Ballerina | Anjana Fernando | 2020-10-26 |
Records
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Mapping values in Ballerina: maps and records | Maryam Ziyad | 2024-01-19 |
Immutability
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Immutability in Ballerina — Part I | Maryam Ziyad | 2021-09-26 |
Blog | Immutable Values in Ballerina | Maryam Ziyad | 2018-12-13 |
Binding Patterns
Type | Title | Author | Publisehd Date |
---|---|---|---|
DZone | Using Binding Patterns in Ballerina | Suleka Helmini | 2021-10-20 |
DZone | Binding Patterns in Ballerina | Suleka Helmini | 2021-10-19 |
Functions
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Hello, World! Program in Ballerina | Ayesh Almeida | 2021-05-09 |
Blog | Defaultable Parameters in Ballerina | Rajith Vitharana | 2019-12-10 |
Blog | Changing the “main” function | Maryam Ziyad | 2018-10-04 |
Type conversions
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | [Ballerina] Casting and Conversions — Part II — Stamping, Cloning and Converting | Maryam Ziyad | 2018-12-11 |
Blog | [Ballerina] Casting and Conversions — Part I | Maryam Ziyad | 2018-12-11 |
Language integrated queries
Type | Title | Author | Publisehd Date |
---|---|---|---|
InfoQ | Data Manipulation with Functional Programming and Queries in Ballerina | Yehonathan Sharvit | 2022-08-11 |
SO | Efficient Joins with Ballerina Query Expressions | Lasini Liyanage | 2022-06-29 |
SO | Query Expressions in Ballerina | Lasini Liyanage | 2022-06-22 |
Video | Using Language Integrated Queries | 2021-09-28 | |
DZone | Language Integrated Queries In Ballerina | Mohanadarshan Vivekanandalingam | 2020-10-16 |
Services and Listners
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | [Attaching multiple services to the same listener in Ballerina | Maryam Ziyad | 2023-12-30 |
Video | Services and Network Communication | 2021-02-03 |
Regular Expressions
Type | Title | Author | Publisehd Date |
---|---|---|---|
Video | Regular Expressions - An Introduction | Ballerinalang | 2023-05-28 |
Video | Bend it like Ballerina: Unveiling our Regex Support | Ballerinalang | 2023-05-08 |
Other Data types
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Ballerina: Behavioral Types | Ayesh Almeida | 2021-06-26 |
Blog | Ballerina: Data Types | Ayesh Almeida | 2021-05-09 |
DZone | Working With Data in Microservices | Lakmal Warusawithana | 2020-04-14 |
Blog | Introduction to Ballerina Tables | Anupama Pathirage | 2018-09-23 |
Blog | Ballerina Object type and all you need to know | Rajith Vitharana | 2018-07-12 |
Blog | Coding in meaningful way(Identifier literal support in ballerina ). | Rajith Vitharana | 2017-05-14 |
Blog | Any type support in ballerina | Rajith Vitharana | 2017-05-04 |
Statements
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Control Structures in Ballerina | Ayesh Almeida | 2021-01-04 |
Identifiers
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Ballerina Identifiers: A Simple Guide for New Developers | Hasitha Aravinda | 2023-03-15 |
Data structures and algorithms
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Representing Graph Data Structure in Ballerina | Prakanth | 2023-06-22 |
Blog | Data Structures and Algorithms with Ballerina | Tharindu Udupitiya | 2023-05-19 |
Blog | Ballerina Collections: Tables | Ayesh Almeida | 2022-03-10 |
Blog | Ballerina Collections: Arrays & Maps | Ayesh Almeida | 2022-02-22 |
Blog | Basic Algorithms using Ballerina | Ayesh Almeida | 2022-02-20 |
Blog | Parallel Merge Sort with Ballerina | Kishanthan Thangarajah | 2018-11-11 |
Compiler
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Ballerina Compilation Process | Rajith Vitharana | 2019-12-17 |
Compiler Plugin
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Module Import Restriction with Ballerina Code Analyzers | Gayal Dassanayake | 2023-09-04 |
Concurrency
Type | Title | Author | Publisehd Date |
---|---|---|---|
DZone | Concurrency-Safe Execution Using Ballerina Isolation | Hinduja Balasubramaniyam | 2021-11-07 |
Blog | Ballerina Concurrency Model and Non-Blocking I/O | Anjana Fernando | 2021-02-22 |
Blog | Unveiling Ballerina Non-Blocking Architecture | Vinod Kavinda | 2019-09-30 |
Blog | Concurrency in Ballerina (Workers, Send, Receive, Flush, Wait …) | Vinod Kavinda | 2018-12-28 |
Blog | Concurrency control in Ballerina (Field based locking) | Vinod Kavinda | 2018 Dev 16 |
Blog | Ballerina: Concurrency Done Right! | Anjana Fernando | 2018-04-29 |
Blog | Concurrency Management in Ballerina (Lock statement) | Rajith Vitharana | 2018-04-28 |
Blog | A Glimpse Inside Workers In Ballerina | Natasha Wijesekare | 2018-12-25 |
Blog | Ballerina Channels | Vinod Kavinda | 2018-10-09 |
Java interoperability
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Call a User-Defined Java Method from Ballerina | Dulmina Renuke | 2023-11-15 |
Video | Java Interoperability in Ballerina | 2020-12-08 | |
Blog | Ballerina Interop and all you need to know | Rajith Vitharana | 2019-12-10 |
Transactions
Type | Title | Author | Publisehd Date |
---|---|---|---|
DZone | Practical Transaction Handling in Microservice Architecture | Anjana Fernando | 2020-12-01 |
Streams
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Lets write a window in Ballerina | Gimantha Bandara | 2019-03-11 |
Blog | Writing Ballerina Streaming Extensions | Grainier Perera | 2019-03-11 |
Workflows
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Simple Long Running Workflows with Ballerina | Anjana Fernando | 2018-10-08 |
Runtime
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Unveiling Ballerina GraalVM image: A comparative analysis | Krishnananthalingam Tharmigan | 2024-01-02 |
Blog | Ballerina meets GraalVM in the Cloud: A Winning Formula for Cloud-Native Applications | Krishnananthalingam Tharmigan | 2023-09-01 |
Blog | Unveiling Ballerina GraalVM image: Tackling Production Issues | Krishnananthalingam Tharmigan | 2023-08-14 |
Blog | Ballerina meets GraalVM: From code to native executable | Krishnananthalingam Tharmigan | 2024-08-13 |
Blog | Ballerina Program Execution Flow | Nadeeshan Dissanayake | 2023-07-07 |
Blog | Deep Dive Into Ballerina Runtime | Jayod | 2023-02-03 |
Ballerina library
HTTP
Type | Title | Author | Publisehd Date |
---|---|---|---|
SO | Implementing a REST API with Ballerina | shazni nazeer | 2022-12-20 |
Video | Changes in the HTTP Package in Ballerina Swan Lake | 2021-07-27 | |
Blog | Single Liner Payload Read… | Chamil Elladeniya | 2021-06-06 |
Blog | HTTP Deep-Dive with Ballerina: Services | Anjana Fernando | 2021-01-28 |
DZone | HTTP Deep-Dive With Ballerina: Client Communication | Anjana Fernando | 2020-12-17 |
Blog | Request dispatching patterns of Ballerina HTTP service | Chamil Elladeniya | 2019-09-19 |
Blog | Implementing a Simple Web Server using Ballerina | Hemika Kodikara | 2019-04-24 |
Blog | Eat My Dust! : Making of Ballerina’s Lightning Fast HTTP Transport | Shafreen Anfar | 2019-02-23 |
Blog | Intercepting HTTP requests in Ballerina | Vinod Kavinda | 2018-11-13 |
Blog | HTTP Caching in Ballerina - Part I | Pubudu Fernando | 2018-11-13 |
HTTP2
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | How to play with HTTP/2 in Ballerina | Chanaka Lakmal | 2018-08-01 |
GraphQL
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | GraphQL Federation with Ballerina and Apollo — Part II | Thisaru Guruge | 2023-10-03 |
Blog | GraphQL Federation with Ballerina and Apollo — Part I | Thisaru Guruge | 2023-10-02 |
Blog | Data Modeling and Exposing Made Easy with Ballerina Persist and GraphQL | Shammi Kolonne | 2023-07-05 |
SO | An Intro to GraphQL Federation with Ballerina GraphQL | Mohamed Sabthar | 2023-04-24 |
Blog | GraphQL Subscriptions with Apache Kafka in Ballerina | Thisaru Guruge | 2023-02-06 |
Blog | GraphQL Subscriptions with Ballerina: A Step-By-Step Guide | Nuvindu Dias | 2022-09-30 |
Blog | Using GraphQL and Ballerina with Multiple Data Sources | Anupama Pathirage | 2022-07-01 |
Video | GraphQL and Ballerina: A Match Made in Heaven | 2021-08-31 | |
Blog | REST is History, Let’s Do GraphQL (with Ballerina) | Thisaru Guruge | 2021-06-29 |
Blog | Introduction to GraphQL with Ballerina | Anjana Fernando | 2021-02-09 |
WebSocket
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Implementing a Websocket Server using Ballerina | shazni nazeer | 2023-05-04 |
Blog | Ballerina WebSocket Service — The Anatomy | Bhashinee Nirmali | 2022-05-24 |
Blog | Real-Time Stock Data Updates with WebSockets using Ballerina | Bhashinee Nirmali | 2021-11-26 |
Blog | Go Real-Time with Ballerina WebSockets | Bhashinee Nirmali | 2021-07-28 |
TNS | An Introduction to WebSockets with Ballerina | Anjana Fernando | 2020-12-18 |
Video | How to use WebSocket with Ballerina | Anjana Fernando | 2020-11-05 |
Pub/Sub
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | An Introduction to Pub/Sub in Ballerina | Nuvindu Dias | 2022-09-30 |
SerDes
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Serialization and Deserialization with Ballerina SerDes module | Mohomed Sabthar | 2022-08-16 |
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Sending Emails with Ballerina | Shammi Kolonne | 2022-08-16 |
File
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | How to download a large file using Ballerina | Anupama Pathirage | 2022-06-22 |
Blog | How to download a file from URL using Ballerina | Anupama Pathirage | 2022-06-20 |
Websub and webhooks
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Learning Websub (Part 4) : Connecting a Message Broker | Ayesh Almeida | 2023-03-12 |
Blog | Learning Websub (Part 3) : Integrating OpenWeatherMap API | Ayesh Almeida | 2023-03-10 |
Blog | Learning WebSub (Part 2) : Building a WebSub hub using Ballerina | Ayesh Almeida | 2023-03-08 |
Blog | Learning WebSub (Part 1) : Introduction to WebSub | Ayesh Almeida | 2023-03-06 |
Video | Building Real-time Systems with WebSub | 2021-11-30 | |
Blog | Event-Driven APIs With Webhook and WebSub | Anupama Pathirage | 2021-11-08 |
Blog | [Ballerina] Registering a GitHub Webhook | Maryam Ziyad | 2018-08-12 |
Blog | [Ballerina] Event Notification via Webhooks | Maryam Ziyad | 2018-07-21 |
gRPC
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Introduction to gRPC on Ballerina | Anupama Pathirage | 2021-08-28 |
Video | gRPC in Ballerina | 2020-09-01 | |
InfoQ | Building Effective Microservices with gRPC, Ballerina, and Go | Lakmal W | 2020-08-25 |
DZone | gRPC Basics: Why, When, and How? | Anjana Fernando | 2020-07-24 |
Blog | Ballerina + gRPC | Buddhi Kothalawala | 2020-04-07 |
Database
Kafka
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Ballerina Kafka Serialization with Avro | Thisaru Guruge | 2020-05-05 |
Blog | Building a Simple Review Filtering System Using Ballerina Kafka | Thisaru Guruge | 2019-02-12 |
Blog | Getting Started with Ballerina Kafka | Thisaru Guruge | 2019-02-05 |
Time
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | A guide for Date/Time conversion in Ballerina Language | sahanhe | 2023-12-17 |
SO | A guide for Date/Time conversion in Ballerina Language | sahanhe | 2022-08-08 |
Cache
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Redesigning of Ballerina Cache | Chanaka Lakmal | 2020-06-27 |
FTP
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Ballerina FTP client | Bhashinee Nirmali | 2021-07-14 |
SOAP
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Ballerina SOAP Connector | Bhashinee Nirmali | 2019-04-17 |
Encoding/Decoding
Type | Title | Author | Publisehd Date |
---|---|---|---|
SO | Different Types of Encoding/Decoding with Ballerina | Chanaka Lakmal | 2022-07-28 |
CSV I/O
Type | Title | Author | Publisehd Date |
---|---|---|---|
SO | Upload CSV files to Ballerina Service | Anupama Pathirage | 2022-09-01 |
Persist
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Enhanced Data Management: Google Sheets Empowered by bal persist | Sahan Hemachandra | 2023-12-17 |
Extended Library
AI
Type | Title | Author | Publisehd Date |
---|---|---|---|
SO | Unleash the Power of AI: Develop a Question Answering Service with OpenAI and Ballerina | Jayani Hewavitharana | 2023-05-15 |
GitHub
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Use Ballerina Github Connector to interact with Github | Charuka Udupitiya | 2023-02-20 |
RabbitMQ
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Connecting Ballerina to CloudAMQP: A Quick Guide | Arshika Mohottige | 2024-01-07 |
Blog | Mastering Work Queues in RabbitMQ with Ballerina | Arshika Mohottige | 2023-11-08 |
SO | RabbitMQ Tutorials in Ballerina. - Part 1 | Arshika Mohottige | 2023-05-15 |
Salesforce
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Seamless Salesforce Integration with Ballerina | Arshika Mohottige | 2024-02-22 |
Blog | Integrations — A key for getting the most out of Salesforce | Chathura Ekanayake | 2023-11-13 |
Blog | Harvesting Sales Data from B2B Channels | Chathura Ekanayake | 2023-09-05 |
AWS Redshift
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Amazon Redshift Integration with Ballerina | Arshika Mohottige | 2024-02-05 |
Blog | Connecting Ballerina to AWS Redshift: A Quick Guide | Arshika Mohottige | 2024-01-07 |
NATS
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Simplifying Distributed Systems with NATS and Ballerina | Arshika Mohottige | 2024-01-23 |
Security
Ballerina security overview
Type | Title | Author |
---|---|---|
Website | Ballerina security | Chanaka Lakmal |
Microservices Security
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | HTTP Security in Ballerina | Chanaka Lakmal | 2021-08-10 |
Blog | Microservices Security with Ballerina | Chanaka Lakmal | 2021-08-02 |
Blog | Securely invoking a Client Endpoint in Ballerina | Chanaka Lakmal | 2018-05-21 |
OAuth
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Authenticate A Shopify App Using OAuth — The Ballerina Way | Thisaru Guruge | 2020-06-02 |
OAuth2
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Securing Microservices with OAuth2 | Chanaka Lakmal | 2022-02-28 |
JWT
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Securing Microservices with JWT | Chanaka Lakmal | 2021-10-21 |
OSCP
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | CRL, OCSP and OCSP stapling validation with Ballerina | Bhashinee Nirmali | 2018-09-15 |
Blog | [Ballerina] Enable OCSP stapling in Ballerina | Bhashinee Nirmali | 2018-08-13 |
TLS/SSL
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Transport layer security in Ballerina — SSL/TLS with HTTP | Anupama Pathirage | 2023-05-19 |
Blog | Configuring Transport Layer Security (TLS/SSL) in Ballerina Client | Bhashinee Nirmali | 2019-10-02 |
Blog | Configure Ciphers and SSL protocols in Ballerina | Bhashinee Nirmali | 2017-10-30 |
Blog | SSL Mutual Authentication with Ballerina | Bhashinee Nirmali | 2017-10-28 |
OpenID
Type | Title | Author | Publisehd Date |
---|---|---|---|
SO | Secure a Ballerina REST API with OpenID Connect using Asgardeo-Part 2 | Dakshitha Ratnayake | 2022-09-16 |
SO | Secure a Ballerina REST API with OpenID Connect using Asgardeo-Part 1 | Dakshitha Ratnayake | 2022-08-10 |
DZone | Building a Secure REST API with OpenID Connect | Anjana Fernando | 2020-07-14 |
Taint Checking (Deprecated)
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Ballerina taint checking guide | Dhananjaya Wicramasingha | 2019-09-25 |
Cloud
Kubernetes/C2C
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Build A Container with Zero Effort in Zero Time with Ballerina | Thevakumar Luheerathan | 2023-07-03 |
DZone | Deploying Ballerina Code on the Cloud | Anuruddha Liyanarachchi | 2021-11-18 |
Video | Code to Cloud with Ballerina | 2021-01-26 | |
DZone | Microservices in Practice: Deployment Shouldn't Be an Afterthought | Lakmal Warusawithana | 2020-07-06 |
DZone | How Ballerina Makes Deploying to Kubernetes Easier for Developers | Lakmal Warusawithana | 2020-02-13 |
DZone | Generate Kubernetes YAML Right From Your App Code | Dmitry Sotnikov | 2018-07-11 |
DZone | Microservices, Docker, Kubernetes, Serverless, Service Mesh, and Beyond | Chanaka Fernando | 2018-05-11 |
AWS Step Functions
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Practical Serverless: Long-Running Workflows with Human Interactions using Step Functions and Ballerina | Anjana Fernando | 2020-09-27 |
AWS Lambda
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Expose a simple Ballerina program as an AWS Lambda Function | Praneesha Chandrasiri | 2023-07-13 |
Video | Serverless in Ballerina | 2020-10-13 | |
Blog | Practical Serverless: Integrating Amazon S3 and Rekognition with Ballerina | Anjana Fernando | 2020-08-31 |
Blog | Test your Ballerina Function written for AWS Lambda | Hemika Kodikara | 2020-02-20 |
TNS | A Step-by-Step Guide For AWS Lambda Deployments with Ballerina | Anjana Fernando | 2019-05-28 |
DZone | Running a Ballerina Service as a Serverless Function in AWS Lambda | Isuru Perera | 2018-01-19 |
DZone | Implementing Serverless Functions With Ballerina on AWS Lambda | Imesh Gunaratne | 2017-06-27 |
Azure functions
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Invoke an Azure Function via a Cosmos DB Trigger Using Ballerina | Praneesha Chandrasiri | 2023-09-07 |
SO | Building Azure Functions Project With Ballerina | Anjana Supun | 2022-11-04 |
Blog | Practical Serverless: A Scalable OCR Solution in 10 Minutes | Anjana Fernando | 2020-08-03 |
Blog | Introduction to Azure Functions in Ballerina | Anjana Fernando | 2020-07-23 |
Video | Ballerina Azure Functions Walk-through | Anjana Fernando | 2020-07-23 |
Azure services
Type | Title | Author | Publisehd Date |
---|---|---|---|
DZone | Production Grade Ballerina Microservices on Azure AKS - Part 2: Continuous Integration With Azure DevOps | Dunith Dhanushka | 2020-09-01 |
DZone | Production-Grade Microservices on Azure AKS With Ballerina — Part 1: The Basics | Dunith Dhanushka | 2020-05-28 |
Blog | Ballerina/Azure Cloud Case Study: Scalable Asynchronous Request Processing | Anjana Fernando | 2019-03-06 |
OpenShift
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Ballerina Services on OpenShift | Hemika Kodikara | 2019-03-21 |
Observability
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Observe Ballerina Integrations with New Relic Extension | Nipuna Madhushan | 2023-12-15 |
Blog | Observe Ballerina Programs with New Relic | Nipuna Madhushan | 2023-10-06 |
DZone | Automated Microservices Observability in the Cloud | Anjana Fernando | 2021-10-12 |
DZone | Rethinking Programming: Automated Observability | Anjana Fernando | 2020-05-01 |
Tooling
OpenAPI
Type | Title | Author | Publisehd Date |
---|---|---|---|
SO | Generating proper OpenAPI Documentation for Ballerina Resource APIs | Sumudu Nissanka | 2022-06-18 |
Video | Ballerina OpenAPI Support | 2022-01-25 | |
Blog | Introduction to OpenAPI with Ballerina | Anupama Pathirage | 2021-09-04 |
Blog | Make your Own Ballerina Client Connector using the Ballerina OpenAPI Tool | Sumudu Nissanka | 2021-07-23 |
Blog | How Ballerina OpenAPI Tool addresses your Code-First and Design-First API Approaches | Sumudu Nissanka | 2021-04-04 |
Blog | Super Cool Feature for your Ballerina service from Ballerina OpenAPI tool | Sumudu Nissanka | 2021-07-23 |
Blog | Generating a Mock Service for Ballerina | Imesh Chandrasiri | 2019-10-01 |
AsyncAPI
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Learn how to use the AsyncAPI contract with cloud-native programming language Ballerina to benefit your API development | Sumudu Nissanka | 2022-07-28 |
Ballerina CLI tool
Type | Title | Author | Publisehd Date |
---|---|---|---|
DZone | Developing Ballerina Project With Ballerina CLI Tool | Dhanushka Madushan | 2020-03-11 |
Blog | Ballerina tool for distribution management | Tharik Kanaka | 2019-12-25 |
SemVer validator
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Introduction to Ballerina Semantic Versioning Validator | Nipuna Ranasinghe | 2022-09-19 |
Strand dump tool
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Troubleshoot Ballerina runtime using the strand dump | Nadeeshan Dissanayake | 2022-10-10 |
Ballerina shell
Type | Title | Author | Publisehd Date |
---|---|---|---|
Video | Ballerina Shell and Debugging Tools | 2021-03-30 | |
Blog | Ballerina Shell REPL — Implementation Overview | Sunera Avinash | 2021-03-01 |
Blog | Ballerina Shell — A REPL for Ballerina | Sunera Avinash | 2021-02-28 |
Debugger
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | A Practical Guide to Ballerina Remote Debugging | Praveen Nadarajah | 2021-03-31 |
Homebrew
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | How we built Ballerina Homebrew Formula | Rasika Perera | 2019-01-06 |
Editor
VS Code
Type | Title | Author | Publisehd Date |
---|---|---|---|
Video | Ballerina Architecture View | Ballerinalang | 2023-06-01 |
Video | New HTTP API Designer | Ballerinalang | 2023-05-30 |
Blog | Ballerina statement editor | Madusha Gunasekara | 2022-09-20 |
Video | Ballerina Programming with VS Code | 2022-02-23 | |
Blog | Ballerina Development With VSCode | Nadeeshaan Gunasinghe | 2018-11-04 |
Blog | Ballerina VSCode Plugin — Graphical Editor for Ballerina | Nadeeshaan Gunasinghe | 2018-11-03 |
Blog | Ballerina VSCode Plugin — Language Intelligence | Nadeeshaan Gunasinghe | 2018-11-03 |
Blog | Setting Up VSCode for Ballerina Development in 60 Seconds | Nadeeshaan Gunasinghe | 2018-09-07 |
Language Server
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | A Practical Guide for Language Server Protocol | Malintha Ranasinghe | 2022-06-28 |
Blog | Implementing a Language Server… How Hard Can It Be? — Part 3 | Nipuna Marcus | 2020-01-14 |
Blog | Implementing a Language Server…How Hard Can It Be?? — Part 2 | Nipuna Marcus | 2019-09-30 |
Blog | Implementing a Language Server…How Hard Can It Be?? — Part 1 (Introduction) | Nipuna Marcus | 2018-03-07 |
Blog | Ballerina Language Server — Demystifying Goto Definition | Nadeeshaan Gunasinghe | 2019-12-31 |
Blog | Extending Ballerina Language Server — Auto-Completion | Nadeeshaan Gunasinghe | 2019-11-17 |
Blog | Language Server for Ballerina— Auto Completion Engine in Depth | Nadeeshaan Gunasinghe | 2018-05-07 |
IntelliJIDEA
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Ballerina Hello World: The IntelliJ Style! | Nipuna Ranasinghe | 2021-04-12 |
Blog | Setting up Ballerina in IntelliJ IDEA | Shan Mahanama | 2017-11-14 |
Composer (Deprecated)
Testing
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Unit test Ballerina integration with Mock backends | Aquib Zulfikar | 2021-08-17 |
Blog | Get started with service testing using Ballerina test framework | Fathima Dilhasha | 2021-08-17 |
Logging
Type | Title | Author | Publisehd Date |
---|---|---|---|
DZone | Integrating Humio With Ballerina for Microservices Logging | PJ Hagerty | 2020-02-25 |
Configuration management
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Configuration Management in Ballerina | Pubudu Fernando | 2019-01-01 |
Blog | Making Use of the Ballerina Config API | Pubudu Fernando | 2017-11-11 |
Package management
Type | Title | Author | Publisehd Date |
---|---|---|---|
Video | Package Management with Ballerina | Ballerinalang | 2023-05-29 |
Video | Deprecate a Ballerina Package Version | Ballerinalang | 2023-05-28 |
DZone | How to Use Ballerina Local Repository | Pramodya Mendis | 2021-12-10 |
Video | Managing Dependencies in Ballerina | 2021-10-26 | |
Blog | Internals of Module Management in Ballerina | Natasha Wijesekare | 2018-12-23 |
Blog | Cheat Sheet for Ballerina Commands associated with Module Management | Natasha Wijesekare | 2018-10-21 |
Building and installing Ballerina
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Building Ballerina from Sources | Ayesh Almeida | 2021-05-11 |
Blog | Installing Ballerina: The hard way | Shan Mahanama | 2019-09-18 |
Ballerina Connectors
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | How to Write a Connector in Ballerina | Chanaka Lakmal | 2018-05-14 |
Blog | Ballerina Native Client Connectors and all you need to know :) | Rajith Vitharana | 2017-11-12 |
Blog | Ballerina Connectors/Endpoints and What? How? Why? | Rajith Vitharana | 2017-11-08 |
Blog | Plug custom native functions to Ballerina | Rajith Vitharana | 2017-07-02 |
CI/CD
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Streamline Your Ballerina Workflow on GitHub with setup-ballerina GitHub Action | Hasitha Aravinda | 2023-03-03 |
Blog | CI/CD Cloud Workflows with GitHub Actions and Ballerina | Anjana Fernando | 2019-05-09 |
DZone | Effective Microservices CI/CD With GitHub Actions and Ballerina | Anjana Fernando | 2020-02-25 |
Comparisons with other languages
Type | Title | Author | Publisehd Date |
---|---|---|---|
Techtarget | A 7-point language comparison of Ballerina vs. Golang | Kerry Doyle | 2022-06-30 |
Blog | How to Create a REST API — Spring Boot and Ballerina | Nadeeshaan Gunasinghe | 2022-02-18 |
Blog | gRPC Compression Support in Go, Java, and Ballerina | Buddhi Kothalawala | 2021-10-22 |
Blog | Echo Websocket service example — GO vs NodeJs vs Ballerina | Bhashinee Nirmali | 2020-10-31 |
DZone | File-Based Integration: Spring Integration vs Ballerina | Anjana Fernando | 2019-12-23 |
Blog | Spring Boot vs Ballerina: Back-end For Front-end (BFF) Service | Shafreen Anfar | 2019-12-21 |
Blog | Converting a Spring Boot Service To Ballerina | Anjana Fernando | 2019-11-27 |
Blog | Spring Boot vs Ballerina: Hello-World Service | Shafreen Anfar | 2019-11-22 |
Blog | Managing data using Ballerina vs Go | Anupama Pathirage | 2018-12-19 |
Blog | Dockerize services written in Go, SpringBoot & Ballerina — A comparison | Kishanthan Thangarajah | 2018-12-14 |
DZone | How Ballerina Is Different From Other Programming Languages | Chanaka Fernando | 2017-03-02 |
Usecases
User stories
Type | Title | Author | Publisehd Date |
---|---|---|---|
TNS | How MOSIP Uses Ballerina WebSubHub for Event-Driven Integration | Dakshitha Ratnayake | 2022-06-28 |
Blog | Build Employee Onboarding Automation With WSO2 Ballerina & Choreo | Sudaraka Jayashanka | 2022-11-01 |
Integration and design Patterns
Type | Title | Author | Publisehd Date |
---|---|---|---|
Blog | Business to Business integration with Ballerina | Chathura Ekanayake | 2023-06-20 |
Article | The future of SaaS middleware | EILEEN O'CONNOR | 2022-12-07 |
DZone | Practical Microservices Development Patterns: Sync vs. Async | Anjana Fernando | 2020-07-06 |
DZone | Reactive Microservices Done Right! | Anjana Fernando | 2020-06-24 |
Blog | Clone and Aggregate Integration Pattern with Ballerina | Shafreen Anfar | 2018-12-23 |
DZone | Rethinking Service Integrations With Microservices Architecture | Imesh Gunaratne | 2017-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:
-
When
x
andy
are of equal typesStructural type checking decides that.
-
When
y
’s type can be “converted” tox
’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 thatT
is a subtype ofU
. - 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:
- Simple values - which are not constructed from other values;
nil
,boolean
,int
,float
,decimal
- Structured values - which contain other values. They are containers for other values, which are called their members.
array
,map
,record
,table
,tuple
- 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
- Behavioral values- which are not just data
function
,object
,error
,stream
,future
,typedesc
- Other - which allows some flexibility to define custom types based on the combination of two or more types.
any
,anydata
,json
,byte
andunion
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
- Install Ballerina Swan Lake and Ballerina VS Code plugin.
- Create a Twilio account.
- Obtain Twilio phone number.
- Obtain Twilio Auth Tokens.
- Obtain the Twilio WhatsApp number from the Console’s WhatsApp Sandbox.
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.
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.
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.