Middleware is disappearing into code
In the modern computer world, in general, everything is becoming smaller and creating disaggregated architectures. Massively disaggregated approaches like microservices, serverless, and APIs are becoming the norm for us all.
We have seen these disaggregated components become network accessible. We call them endpoints. Whether it is data, IoT, APIs, SaaS, or serverless functions, everything is becoming programmable endpoints. The number of endpoints is exploding and resilient communication is the key for these programs to become successful. Integration is the discipline of resilient communication between endpoints. But it isn’t easy.
In the last decade or so, we have mainly used systems like ESB (enterprise service bus) and EIs (enterprise integrators) to do the integrations. MuleSoft, Tibco, IBM, and WSO2 are few well-reputed middleware product vendors who have a full spectrum of middleware products. In this world, the programmer does a little bit of business logic and integration is taken care of by middleware products. These middleware products help to make integration simple but they have one big challenge: it is not agile.
With the emergence of microservice architecture, writing and deploying these business applications have changed. Now there is no need for running servers (app servers) to deploy these apps. This is totally different from the fundamentals of how we ran middleware. The developer can use general-purpose programming languages like Java, Node, and Go to write these microservers and then deploy them by using distributed infrastructures like containers, Kubernetes, and Service-Mesh.
But these programs require a little bit of code to handle middleware functionalities like transactions, events, circuit breakers, discovery, protocol handling, and mediation. Middleware has disappeared and leaked into the code.
“Middleware is dead; middleware is everywhere.”
— Sanjiva Weerawarana
Writing middleware functionalities by using general-purpose languages is not easy. Almost all existing programming languages are designed for a world where the normal case is to run on a standalone machine. But integration is all about interactions with a massive number of endpoints distributed over the network. So the developer has to take responsibility for either solving these hard problems or they have to find a suitable framework to support that. Camel and Spring integration frameworks are some common frameworks people are using.
But how about a programming language that understands middleware concepts and abstractions rather than using bolt-on frameworks?
Ballerina - cloud-native middleware as a programming language
Ballerina is a statically typed, concurrent programming language, focusing on network interaction and structured data. It is intended to be the core of a language-centric middleware platform. It has all the general-purpose functionality expected of a modern programming language, but it also has several unusual aspects that make it particularly suitable for its intended purpose.
In addition to the general-purpose constructs (classes, objects, structures, functions, etc.) provided by other languages, Ballerina provides language constructs (endpoints, services, etc.) specifically for consuming and providing network services. The Ballerina roadmap will add language constructs for other middleware functionality such as event stream processing, distributed transactions and reliable messaging.
Ballerina abstractions and syntax for concurrency and network interaction have been designed so that there is a close correspondence with sequence diagrams. This enables a bidirectional mapping for any Ballerina function between its textual representation in the syntax described in this specification and its graphical representation as a sequence diagram, such that the sequence diagram fully shows the aspects of the behavior of that function that relates to concurrency and network interaction.
You can find the full language spec here.
In this post, I will not be going to discuss all the capabilities of Ballerina rather I would like to focus on creating reusable modules called client-connectors to integrate with the rest of the world.
Ballerina Connectors
Ballerina connectors are reusable Ballerina modules that integrate Ballerina programs with external network endpoints. Any developer can create these connector modules and push them into Ballerina Central which is a public module repository.
To find out more details, let’s create a connector to retrieve weather data from OpenWeather API by passing a city name. In this sample connector, I am going to use the`http:Client` object in Ballerina.
OpenWeather Connector
Let’s start by creating an openweather-connector` Ballerina project.
A connector is a data structure that is represented by a client object. A client object is similar to an ordinary object. However, unlike ordinary objects, in client objects, the actions are performed on a remote network endpoint. Hence, the ‘remote’ keyword should be used in the method signature.
Like normal objects, client objects take their configuration parameters as the values of the constructor parameter. Since OpenWeather requires an apiKey and we can define the configuration record as bellow.
Now, let’s add a remote function that takes the city name as the input and returns the corresponding weather data as a `weatherData` record.
Bellow is the WeatherData record which we will populate from extracting OpenWeather API response.
You can find the full source code of the sample OpenWeather connector in following GitHub link.
Share Ballerina modules
We can publish our custom connector for others to use into a Ballerina registry, such as Ballerina Central.
Once you have built the module, you can do: ballerina push <org-name>/<module-name> and your module will be available at Ballerina Central for others to use.
The <org-name> is defined in the Ballerina.toml that resides with the project and must match the organization name that is attached to your account at Ballerina Central. The <module-name> is defined by the folder that you placed the source code within the Ballerina project. Here is Ballerina.toml of my sample project.
You will need to have an account at Ballerina Central and your CLI token from central placed into your Ballerina settings. The ballerina `push` command will initiate an OAuth flow that automates this for you, even if you do not already have an existing account on Ballerina Central.
Let's write a simple HTTP service and see how we can use the OpenWeather connector to retrieve weather data.
Bellow is the auto-generated sequence diagram of our sample program.
OpenWeather connector is a sample connector written to explain how we can create our own connector. But if you wish to find out real production-ready connectors, the list below provides a few connectors develop by WSO2.
- wso2/twitter — https://github.com/wso2-ballerina/module-twitter
- wso2/gmail — https://github.com/wso2-ballerina/module-gmail
- wso2/salesforce—https://github.com/wso2-ballerina/module-salesforce
Useful resources
[1] [Ballerina is not Java, BallerinaCon 2018](https://www.youtube.com/watch?v=DusyY-oH-JM) — Sanjiva Weerawarana
[2] [Ballerina — Cloud Native Programming Language, BallerinaCon 2018](https://www.youtube.com/watch?v=-lA3KD3ostU) — Paul Fremantle
[3] [Ballerina Session in SummerSOC 2019 — Why Ballerina & Key language concepts](https://www.youtube.com/watch?v=bzzP1Q26T5g) — Sanjiva, Krishanthan
[4] [Ballerina.io](ballerina.io)