- 2201.12.10 (Swan Lake Update 12)
- 2201.12.9 (Swan Lake Update 12)
- 2201.12.8 (Swan Lake Update 12)
- 2201.12.7 (Swan Lake Update 12)
- 2201.12.6 (Swan Lake Update 12)
- 2201.12.5 (Swan Lake Update 12)
- 2201.12.4 (Swan Lake Update 12)
- 2201.12.3 (Swan Lake Update 12)
- 2201.12.2 (Swan Lake Update 12)
- 2201.12.1 (Swan Lake Update 12)
- 2201.12.0 (Swan Lake Update 12)
- 2201.8.10 (Swan Lake Update 8)
- 2201.8.9 (Swan Lake Update 8)
- 2201.8.8 (Swan Lake Update 8)
- 2201.8.7 (Swan Lake Update 8)
- 2201.8.6 (Swan Lake Update 8)
- 2201.8.5 (Swan Lake Update 8)
- 2201.8.4 (Swan Lake Update 8)
- 2201.8.3 (Swan Lake Update 8)
- 2201.8.2 (Swan Lake Update 8)
- 2201.8.1 (Swan Lake Update 8)
- 2201.8.0 (Swan Lake Update 8)
- 1.2.62
- 1.2.61
- 1.2.60
- 1.2.59
- 1.2.58
- 1.2.57
- 1.2.56
- 1.2.55
- 1.2.54
- 1.2.53
- 1.2.52
- 1.2.51
- 1.2.50
- 1.2.49
- 1.2.48
- 1.2.47
- 1.2.46
- 1.2.45
- 1.2.44
- 1.2.43
- 1.2.42
- 1.2.41
- 1.2.40
- 1.2.39
- 1.2.38
- 1.2.37
- 1.2.36
- 1.2.35
- 1.2.34
- 1.2.33
- 1.2.32
- 1.2.31
- 1.2.30
- 1.2.29
- 1.2.28
- 1.2.27
- 1.2.26
- 1.2.25
- 1.2.24
- 1.2.23
- 1.2.22
- 1.2.21
- 1.2.20
- 1.2.19
- 1.2.18
- 1.2.17
- 1.2.16
- 1.2.15
- 1.2.14
- 1.2.13
- 1.2.12
- 1.2.11
- 1.2.10
- 1.2.9
- 1.2.8
- 1.2.7
- 1.2.6
- 1.2.5
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.2.0
Overview of Ballerina Swan Lake Preview 8
This release is the eighth preview version of Ballerina Swan Lake. It includes a new set of language features along with improvements and bug fixes to the compiler, runtime, standard library, and developer tooling.
Updating Ballerina
You can use the update tool to update to Ballerina Swan Lake Preview 8 as follows.
For existing users
If you are already using Ballerina, you can directly update your distribution to the Swan Lake channel using the Ballerina update tool. To do this, first, execute the command below to get the update tool updated to its latest version.
ballerina update
Next, execute the command below to update to Swan Lake Preview 8.
ballerina dist pull slp8
However, if you are using a Ballerina version below 1.1.0, install via the installers.
For new users
If you have not installed Ballerina, then download the installers to install.
Highlights
- Ability to use
\to escape the special characters in an identifier without specifying the initial quote - Introduction of included record parameters
- Introduction of service typing changes basing services on objects
- Extension of Ballerina transaction capabilities to define transactional resource functions and transactional remote functions
- Improvements to the HTTP, Log, Email, and WebSub Standard Library modules
- Introduction of the new GraphQL, NATS Streaming (STAN), UUID, and WebSocket Standard Library modules
What is new in Ballerina Swan Lake Preview 8
Language
Support identifier escapes without an initial quote
Now, \ can simply be used to escape the special characters in an identifier without specifying the initial quote. For example, both the formats below are supported now.
int a\-b; int 'a\-b;
Included record parameters
Included record parameters can be specified as *T P in which T denotes a record type descriptor and P denotes the name of the parameter.
An included record parameter is similar to a required parameter, but it also allows the caller of the function to specify the value for a field of the record type as a named argument using the field's name, as if it had been declared as a parameter.
The names of the fields in the record type of an included record parameter must be distinct from each other and also from the names of the other parameters, unless it is an optional field of type never.
A named argument in a function call can correspond to the fields of an included record parameter in two different ways.
-
Being relevant to a field of the included recorded parameter, which is not of the
nevertype.mport ballerina/io; ype Student record { string firstName; string lastName?; ; unction printStudentDetails(int admissionNo, *Student student) { string name = student.firstName; string? lastName = student?.lastName; if lastName is string { name += string ` ${lastName}`; } io:println("Admission No: ", admissionNo, ", Student Name: ", name); ublic function main() { printStudentDetails(1001, firstName = "Peter"); printStudentDetails(1002, firstName = "Anne", lastName = "Doe"); -
Being relevant to a record rest descriptor of an included record parameter that is of an open record type. The following conditions should be satisfied for this.
- In the parameter list, there should be only one included record parameter that is of an open record type.
- The open record type must disallow fields of the same names as the other parameters and individual field descriptors of the other included record parameters, by including optional individual field descriptors of the type
never. In addition to these optional individual field descriptors, there should not be any other field descriptors in this record type.
import ballerina/io; type Grades record {| never math?; never physics?; int...; |}; function printAverage(int math, int physics, *Grades grades) { int totalMarks = math + physics; int count = grades.length() + 2; foreach int grade in grades { totalMarks += grade; } io:println("Average: ", totalMarks/count); } public function main() { printAverage(90, 85); printAverage(85, 85, chemistry = 75); printAverage(75, 85, chemistry = 90, zoology = 80); }
Service typing changes
Services are now based on objects. The service declaration syntax below is mere syntactic sugar for creating a new instance of a service class and then attaching it to a listener. With this change, the path that the service should serve on can be provided in the service-declaration syntax. This was previously provided using an annotation.
Previous syntax
import ballerina/http; service hello on new http:Listener(9090) { resource function sayHello() returns error? { } }
New syntax
import ballerina/http; service [/optional_base_path] on new http:Listener(9090) { resource function get sayHello() returns string { } }
Note: There is no longer a service variable name as
helloin the first example. Since services are objects, they can contain fields and regular methods. In addition to that, services can contain remote methods and resource methods.
Resource methods are defined as follows:
resource function resource-method-name resource-path () { }
- Resource methods do not have a method name similar to a regular method.
- The
resource-method-nameinforms the listener of the operations this resource allows. For example, in the HTTP listener, theresource-method-namemaps to the HTTP methods such asGETorPUT. - The
resource-pathis the path in which this resource resides within the service. You can use.as theresource-pathto indicate the path/.
A service declared using the service-declaration syntax cannot be referred to using an identifier anymore. Instead, you need to use an object constructor prepended by the service keyword to declare a service object or create a new instance of a service class.
service object { } hello = service object { string message = "Hello"; resource function get sayHello() returns string { } } listener http:Listener l = new (7000); string[] basePath = ["/"]; // service base path: / l.attach(hello, basePath);
service class HelloService { string message; resource function get sayHello() returns string { } function init(string message) { self.message = message; } } var hello = new HelloService("Hello"); listener http:Listener l = new(7000); string[] basePath = ["hello", "path"]; // service on "/hello/path" l.attach(hello, basePath);
Listener object
Listener is no longer defined in ballerina/lang.object lang-library, now it is a compiler known internal type.
A type is a listener object type if it is a subtype of the object type Listener<T,A>, for some type T that is a subtype of service object {} and some type A that is a subtype of string[]|string|().
The object type Listener<T,A>, is described by the following object type descriptor:
object { public function attach(T svc, A attachPoint) returns error?; public function detach(T svc) returns error?; public function start() returns error?; public function gracefulStop() returns error?; public function immediateStop() returns error?; }
Transactional services
Ballerina transaction capabilities have been extended to services. Now, you can define transactional resource methods and transactional remote methods. These methods will be participants of global distributed transactions. Infection and agreement protocols are implemented based on the Ballerina distributed transaction protocol.
By defining services as participants, all services work as a single unit of work. If any of the services fail, the whole transaction will be reverted and if all the services are successfully called, the transaction will be completed and committed successfully.
Defining transactional resource methods in a service
transactional resource function get message(http:Caller caller, http:Request req) { http:Response res = new; callSomeService(res); callAnotherService(res); checkpanic caller->respond(res); }
Defining transactional remote methods in a client object
transactional remote function callMyFirstService() returns @tainted any|error { return self.httpClient1->get("/echo/message"); } transactional remote function callMySecondService() returns @tainted any|error { return self.httpClient2->get("/user/history"); }
Calling the service
transaction { var res1 = client->callMyFirstService(); var res2 = client ->callMySecondService(); var x = commit; if (x is error) { // error code } else { // success code } }
Standard library
http module changes
Service declaration
- Basepath field has been removed from the
ServiceConfigannotation. Use theabsolute resource paththat begins with/as the basePath which is optional and defaults to/when not specified. - The service type can be added as
http:Service, which is optional after theservicekeyword.
Previous syntax
@http:ServiceConfig { basePath: “hello” } service myService on new http:Listener(9090) { }
New syntax
service http:Service /hello on new http:Listener(9090) { }
Resource method declaration
- Use the resource method name to specify the HTTP method to support instead of the
methodsfield of theResourceConfigannotation (e.g.,get). - Use
defaultas the resource method name when the resource has to support all methods including standard HTTP methods and custom methods (e.g., the passthrough/proxy use case). - The resource path segment represents the
pathas thepathfield of theResourceConfighas been removed. - Use
.to specify the resource path segment if the path needs to be set as/. - Path params are specified in the resource path segment within square brackets along with the type. The supported types are string, int, float, boolean (e.g.,
path/[string foo]). - Resource signature parameters are optional. Even the
CallerandRequestare optional and not ordered. - Query param binding support is added. The supported types are string, int, float, boolean, decimal, and the array types of the aforementioned types. The
Queryparam type can be nilable (e.g.,(string? bar)). - Rest param support is added. It can be used as a wildcard path segment to accept requests to multiple different paths. Earlier it was used as
/*and now it can be specified as[string… s]in whichsis accessible within the resource. - Use the
@http:Payload {}annotation to denote the data binding param in the resource signature as thebodyfield of theResourceConfighas been removed.
service http:Service /mytest on new http:Listener(9090) { resource function post foo/[int id]/bar/[string... extra](string? bar, http:Caller caller, @http:Payload {} json p) { // [int id] is a path param // [string... extra] is a rest param // string? bar is a query param // json p is the request payload } }
log module changes
-
Log levels are reduced to
INFOandERROR. There will be no user configuration to control the log level. All the logs will be printed to the standard error stream. -
There are only two APIs to log messages as follows.
- Log
INFOmessages
log:print("something went wrong", id = 845315); Output: time = 2019-08-09 11:47:07,342 module = "myorg/hello" message = "something went wrong" id = 845315- Log
ERRORmessages
log:printError("something went wrong", err = e, id = 845315); Output: time = 2019-08-09 11:47:07,342 module = "myorg/hello" message = "something went wrong" error = "invaild operation" id = 845315 - Log
-
The API supports passing any number of key/value pairs along with the message.
-
Log messages are printed following the
LogFMTstandards.
email module changes
The methods related to sending and receiving emails were renamed. The Listener API was divided into the POP and IMAP protocols.
Client changes
- The
email:Emaildefinition is changed toemail:Message. - The
readmethod of theemail:ImapClient,email:PopClient, andemail:Listener(i.e., the newemail:PopListenerandemail:ImapListener) are changed toreceiveEmailMessage.
Service declaration
- The
email:Listeneris split into theemail:PopListenerandemail:ImapListener. Therefore, theprotocolfield is removed from the new protocol-specific listeners. Theemail:PopConfigoremail:ImapConfigthat was used as a field for theemail:Listeneris not required for new the API implementation. The protocol configuration-related fields are made parts of the new listeners. - The resource methods are changed to remote methods in the new listener APIs.
- The service name is given as a string with the new Ballerina language changes.
- The
onMessagemethod of theemail:Listener(i.e., the newemail:PopListenerandemail:ImapListener) is changed toonEmailMessage. - The
pollingIntervalfield of theemail:Listeneris changed topollingIntervalInMillisin new listener APIs. That makes it consistent with other Ballerina modules, which have time durations configured in milliseconds.
A sample POP3 listener is given below.
Previous syntax
email:PopConfig popConfig = { port: 995, enableSsl: true }; listener email:Listener emailListener = new ({ host: "pop.email.com", username: "reader@email.com", password: "pass456", protocol: "POP", protocolConfig: popConfig, pollingInterval: 2000 }); service emailObserver on emailListener { resource function onMessage(email:Email emailMessage) { } resource function onError(email:Error emailError) { } }
New syntax
listener email:PopListener emailListener = new ({ host: "pop.email.com", username: "reader@email.com", password: "pass456", pollingIntervalInMillis: 2000, port: 995, enableSsl: true }); service "emailObserver" on emailListener { remote function onEmailMessage(email:Message emailMessage) { } remote function onError(email:Error emailError) { } }
websub module changes
- The base path is removed from the
SubscriberServiceConfigannotation. - The
onNotificationandonIntentVerificationresources are converted to remote methods.
Previous syntax
@websub:SubscriberServiceConfig { path: "/websub", target: ["http://localhost:9191/websub/hub", "http://websubpubtopic.com"] } service websubSubscriber on new websub:Listener(8181) { resource function onIntentVerification(websub:Caller caller, websub:IntentVerificationRequest request) {} resource function onNotification(websub:Notification notification) {} }
New syntax
@websub:SubscriberServiceConfig { target: ["http://localhost:23191/websub/hub", "http://one.websub.topic.com"] } service websub:SubscriberService /websub on new websub:Listener(8181) { remote function onIntentVerification(websub:Caller caller, websub:IntentVerificationRequest request) {} remote function onNotification (websub:Notification notification) {} }
Introduced new modules
GraphQL
The Ballerina GraphQL module is introduced with this release. This module provides the support to define GraphQL services and handle simple GraphQL queries. Currently, this supports GraphQL service endpoints with the resource methods, which return graphql:Scalar values (int, string, boolean, and float) and record types only.
NATS Streaming (STAN)
With this release, a new module is introduced for NATS Streaming. Previously, the Ballerina NATS module included the support for streaming as well. Now, NATS and NATS Streaming are separated into Ballerina NATS and Ballerina STAN modules.
UUID
The Ballerina UUID module is introduced with this release. This module provides functions related to UUID (Universally Unique Identifier) such as generating different types of UUIDs and validating and checking the versions of UUID strings.
WebSocket
- The WebSocket module has been moved out of the HTTP module. Therefore, you will have to change the import from
ballerina/httptoballerina/websocket. - Introduced a new listener for the WebSocket module.
Previous syntax
listener http:Listener wsListener = new (9090);
New syntax
listener websocket:Listener wsListener = new (9090);
-
The base path is removed from the
WebSocketServiceConfig. -
Has 2 types of services. In order to work with WebSockets, the two services below are mandatory.
websocket:UpgradeService- This is to handle the WebSocket upgrade. This takes thehttp:Requestandhttp:Callerparameters in. This service has a predefinedonUpgraderemote method that returns awebsocket:Serviceor an error. Earlier, this was handled by an HTTP upgrade resource.websocket:Service- This is to handle events after the WebSocket upgrade. This service is still similar to the earlier WebSocket service, which had predefined resources likeonText,onBinary,onError,onPing, andonPong. With the new syntax, all those resources are converted into remote methods.
Previous syntax
import ballerina/http; listener http:Listener socketListener = new (9000); @http:WebSocketServiceConfig { path: "/basic" } service echo on socketListener { resource function onText(http:WebSocketCaller caller, json text) {} resource function onBinary(http:WebSocketCaller caller, byte[] b) {} }
New syntax
import ballerina/http; import ballerina/websocket; service websocket:UpgradeService / basic on new websocket:Listener(9000) { remote isolated function onUpgrade(http:Caller caller, http:Request req) returns websocket:Service|websocket:WebSocketError { return new WsService(); } } service class WsService { *websocket:Service; remote isolated function onText(websocket:Caller caller, string data) { } remote isolated function onBinary(websocket:Caller caller, byte[] data) { } }