Ballerina WebSocket Service — The Anatomy

Bhashinee Nirmali
Ballerina Swan Lake Tech Blog
4 min readMay 24, 2022

The Ballerina WebSocket server is implemented in a reactive manner. The server listens for messages and acts on them as they are received. To receive messages, the WebSocket service has a predefined structure of remote functions. Users do not need to implement each and every remote function as they are optional. Users can decide what remote functions they need for their use case and implement only them.

Let’s see what a WebSocket service looks like after implementing all the remote functions.

Let’s discuss the remote functions one by one.

onOpen

As soon as the connection is upgraded to a WebSocket connection after the initial handshake, the `onOpen` remote function is dispatched. This remote function has only one optional argument which is the `websocket:Caller caller`.

If someone wants to do some tasks before reading the incoming messages or just after the connection is upgraded, users can implement them inside this remote function.

onMessage

The `onMessage` remote function accepts both types of text and binary messages. This function accepts `anydata` as the function parameter as this remote function supports data binding.

This means instead of receiving the incoming messages as a string or binary data, they can also be received as `json`, `xml`, `record`, or `array` types as well.

Data deserialization for text messages happens similar to the following,

  • If the contextually-expected data type is `string`, the received data will be directly presented to the API without performing any deserialization.
  • If the contextually-expected data type is `xml`, the received text data will be deserialized to `xml`.
  • All the other data types are treated as `json` and the received text data will be deserialized to `json`.

Data deserialization for binary messages happens similar to the following,

  • If the contextually-expected data type is `byte[]`, the received data will be directly presented to the API without doing any deserialization.
  • If the contextually-expected data type is `xml`, the received binary data will be first converted to the string representation of the `byte[]` and then deserialized to `xml`.
  • All the other data types are treated as `json` and the received binary data will be first converted to the string representation of the `byte[]` and then will be deserialized to` json`.

If the data binding fails, the connection will be terminated by sending a close frame with the 1003 error code(1003 indicates that an endpoint is terminating the connection because it has received a type of data it cannot accept ) and will print an error log at the listener side.

onPing

Ping messages received are dispatched to this remote function. This has `websocket:Caller` and the binary data received in the ping message as arguments. You do not need to explicitly control these messages as they are handled automatically by the services. If this remote function is not implemented, a pong message is automatically sent back.

onPong

Pong messages received are dispatched to this remote function. This has `websocket:Caller` and the binary data received in the pong message as arguments.

onIdleTimeout

This remote function is dispatched when an idle timeout is reached. `idletimeout` has to be configured by the user in the WebSocket service. This has optional `websocket:Caller` as the function argument.

onClose

This remote function is dispatched when a close message is received. This remote function has `WebSocket:Caller`, the close code, and the close reason as the function arguments. Clean-up tasks such as releasing all the resources (For example, if you stored WebSocket connections in a map, you can remove them) can be performed in this remote function.

onError

This remote function is dispatched when network errors such as the reception of a corrupted frame occur. Dispatching to this resource will always be preceded by a connection closure with an appropriate close frame. Similar to `onClose`, clean-up tasks can be executed in this remote function.

Low-level APIs to use instead of `onMessage` function

It is possible to separate the text and binary messages into two functions using the `onTextMessage` and `onBinaryMessage` remote functions. Users are not allowed to have these remote functions along with the `onMessage` remote function.

onTextMessage

Text messages are dispatched to this remote function. This remote function has the optional `websocket:Caller` parameter and the mandatory `string` parameter to take in the text message. Users are not allowed to have this remote function along with the `onMessage` remote function.

onBinaryMessage

Binary messages are dispatched to this remote function. This remote function has the optional `websocket:Caller` parameter and the mandatory `byte[]` parameter to take in the binary message. Users are not allowed to have this remote function along with the `onMessage` remote function.

If you want to learn more about the Ballerina WebSocket library or if you’d like to find out more about Ballerina Language here are some useful links, for further exploration:

Hope you found this useful!

--

--