ballerina/websub module

Module overview

This module contains an implementation of the W3C WebSub recommendation, which facilitates a push-based content delivery/notification mechanism between publishers and subscribers.

This implementation supports introducing all WebSub components: subscribers, publishers, and hubs.

  • Subscriber - A party interested in receiving update notifications for particular topics.
  • Publisher - A party that advertises topics to which interested parties subscribe in order to receive notifications on occurrence of events.
  • Hub - A party that accepts subscription requests from subscribers and delivers content to the subscribers when the topic is updated by the topic's publisher.

Basic flow with WebSub

  1. The subscriber discovers from the publisher, the topic it needs to subscribe to and the hub(s) that deliver notifications on updates of the topic.

  2. The subscriber sends a subscription request to one or more discovered hub(s) specifying the discovered topic along with other subscription parameters such as:

    • The callback URL to which content is expected to be delivered.
    • (Optional) The lease period (in seconds) the subscriber wants the subscription to stay active.
    • (Optional) A secret to use for authenticated content distribution.
  3. The hub sends an intent verification request to the specified callback URL. If the response indicates verification (by echoing a challenge specified in the request) by the subscriber, the subscription is added for the topic at the hub.

  4. The publisher notifies the hub of updates to the topic and the content to deliver is identified.

  5. The hub delivers the identified content to the subscribers of the topic.

Features

Subscriber

This module allows introducing a WebSub Subscriber Service with onIntentVerification, which accepts HTTP GET requests for intent verification, and onNotification, which accepts HTTP POST requests for notifications. The WebSub Subscriber Service provides the following capabilities:

  • When the service is started a subscription request is sent for a hub/topic combination, either specified as annotations or discovered based on the resource URL specified as an annotation.
  • If onIntentVerification is not specified, intent verification will be done automatically against the topic specified as an annotation or discovered based on the resource URL specified as an annotation.
  • If a secret is specified for the subscription, signature validation will be done for authenticated content distribution.

Hub

A WebSub compliant hub based on the Ballerina Message Broker is also available. This can be used as a remote hub or to be used by publishers who want to have their own internal hub. Ballerina's WebSub hub honors specified lease periods and supports authenticated content distribution.

Enabling Basic Auth support for the hub

The Ballerina WebSub Hub can be secured by enforcing authentication (Basic Authentication) and optionally authorization. AuthProvider and authConfig need to be specified for the hub listener and service respectively. If the authStoreProvider of the AuthProvider is set as "http:CONFIG_AUTH_STORE", usernames and passwords for authentication and scopes for authorization would be read from a config toml file. A user can specify AuthProvider as follows and set it to the hubListenerConfig record passed when starting the hub.

http:AuthProvider basicAuthProvider = {
    scheme: http:BASIC_AUTH,
    authStoreProvider: http:CONFIG_AUTH_STORE
};

http:ServiceEndpointConfiguration hubListenerConfig = {
    authProviders: [basicAuthProvider],
    secureSocket: {
        keyStore: {
            path: "${ballerina.home}/bre/security/ballerinaKeystore.p12",
            password: "ballerina"
        }
    }
};

var val = websub:startHub(new http:Listener (9191, config =  hubListenerConfig));

In addition to the AuthProvider for listener, a user also has to specify the authConfig properties at service config level.

It can be populated by providing authConfig via a toml formatted file under the b7a.websub.hub.auth alias. Recognized users can also be mentioned in the same file which permits auth providers to read.

["b7a.websub.hub.auth"]
enabled=true  // enables the authentication
scopes="scope1" // defines the scope of possible users

["b7a.users"]

["b7a.users.tom"]
password="1234"
scopes="scope1"

Once the hub is secured over basic auth, a subscriber should provide the relevant auth config in the subscriptionClientConfig field of the subscriber service annotation.

@websub:SubscriberServiceConfig {
    path: "/ordereventsubscriber",
    subscriptionClientConfig: {
        auth: {
            scheme: http:BASIC_AUTH,
            username: "tom",
            password: "1234"
        }
    }
}
Enabling data persistence for the hub

The Ballerina WebSub Hub supports persistence of topic and subscription data that needs to be restored when the hub is restarted.

Users can introduce their own persistence implementation, by introducing an object type that is structurally equivalent to the websub:HubPersistenceStore abstract object. Alternatively, the H2-based websub:H2HubPersistenceStore object made available in the ballerina/websub module could be used to persist data.

Persistence can be enabled by setting a suitable websub:HubPersistenceStore value for the hubPersistenceStore field in the HubConfiguration record, which is passed to the websub:startHub() function.

import ballerina/h2;
import ballerina/http;
import ballerina/websub;

// Define an `h2:Client` to use with the `websub:H2HubPersistenceStore`.
h2:Client h2Client = new({
    path: "./target/hubDB",
    name: "hubdb",
    username: "user1",
    password: "pass1"
});

// Define a `websub:H2HubPersistenceStore` as a `websub:HubPersistenceStore`.
websub:HubPersistenceStore hubPersistenceStore = new websub:H2HubPersistenceStore(h2Client);
// Set the defined persistence store as the `hubPersistenceStore` in the `hubConfig` record.
websub:HubConfiguration hubConfig = {
    hubPersistenceStore: hubPersistenceStore
};

// Pass the `hubConfig` record when starting up the hub to enable persistence.
var result = websub:startHub(new http:Listener(8080), hubConfiguration = hubConfig);

Any subscriptions added at the hub will now be available even when the hub is restarted.

Publisher

Ballerina WebSub publishers can use utility functions to add WebSub link headers indicating the hub and topic URLs, which facilitates WebSub discovery.

A hub client endpoint is also made available to publishers and subscribers to perform the following:

  • Publishers
    • Register a topic at the Hub
    • Publish to the hub indicating an update of the topic
  • Subscribers
    • Subscribe/Unsubscribe to/from topics at a hub

Samples

This sample demonstrates a Subscriber Service with subscribeOnStartUp set to true. This will result in a subscription request being sent to the specified hub for the specified topic, with the specified lease seconds value and the specified secret for authenticated content distribution. Since an onIntentVerification resource function is not included, intent verification for subscription and unsubscription requests would happen automatically, if the topic specified in the request matches that specified as an annotation or that discovered for the annotated resource URL.

import ballerina/log;
import ballerina/websub;

listener websub:Listener websubEP = new(8181);

@websub:SubscriberServiceConfig {
    path: "/websub",
    subscribeOnStartUp: true,
    topic: "<TOPIC_URL>",
    hub: "<HUB_URL>",
    leaseSeconds: 3600,
    secret: "<SECRET>"
}
service websubSubscriber on websubEP {

    resource function onNotification(websub:Notification notification) {
        var payload = notification.getTextPayload();
        if (payload is string) {
            log:printInfo("WebSub Notification Received: " + payload);
        } else {
            log:printError("Error retrieving payload as string", err = payload);
        }
    }
}

Explicit intent verification can be done by introducing an onIntentVerification resource function.

import ballerina/http;
import ballerina/log;
import ballerina/websub;

listener websub:Listener websubEP = new(8181);

@websub:SubscriberServiceConfig {
    path: "/websub",
    subscribeOnStartUp: true,
    topic: "<TOPIC_URL>",
    hub: "<HUB_URL>",
    leaseSeconds: 3600,
    secret: "<SECRET>"
}
service websubSubscriber on websubEP {

    resource function onIntentVerification(websub:Caller caller, websub:IntentVerificationRequest request) {
        http:Response response = new;
        // Insert logic to build subscription/unsubscription intent verification response.
        var result = caller->respond(response);
        if (result is error) { 
            log:printError("Error responding to intent verification request", err = result); 
        }
    }

    resource function onNotification(websub:Notification notification) {
        var payload = notification.getTextPayload();
        if (payload is string) {
            log:printInfo("WebSub Notification Received: " + payload);
        } else {
            log:printError("Error retrieving payload as string", err = payload);
        }
    }
}

Functions are made available on the websub:IntentVerificationRequest to build a subscription or unsubscription verification response, specifying the topic to verify intent against:

http:Response response = request.buildSubscriptionVerificationResponse("<TOPIC_TO_VERIFY_FOR>");
http:Response response = request.buildUnsubscriptionVerificationResponse("<TOPIC_TO_VERIFY_FOR>");

Ballerina publishers can start up and publish directly to the Ballerina WebSub hub.

import ballerina/log;
import ballerina/http;
import ballerina/runtime;
import ballerina/websub;

public function main() {

    log:printInfo("Starting up the Ballerina Hub Service");
    var result = websub:startHub(new http:Listener(9191));
    websub:WebSubHub webSubHub = result is websub:WebSubHub ? result : result.startedUpHub;

    var registrationResponse = webSubHub.registerTopic("<TOPIC_URL>");
    if (registrationResponse is error) {
        log:printError("Error occurred registering topic: " + <string>registrationResponse.detail().message);
    } else {
        log:printInfo("Topic registration successful!");
    }

    // Make the publisher wait until the subscriber subscribes at the hub.
    runtime:sleep(20000);

    log:printInfo("Publishing update to internal Hub");
    var publishResponse = webSubHub.publishUpdate("<TOPIC_URL>", {"action": "publish", "mode": "internal-hub"});
    if (publishResponse is error) {
        log:printError("Error notifying hub: " + <string>publishResponse.detail().message);
    } else {
        log:printInfo("Update notification successful!");
    }

    // Make sure the service is running until the subscriber receives the update notification.
    runtime:sleep(5000);
}

Ballerina publishers can also use the hub client endpoint to register topics at Ballerina WebSub hubs and publish/notify updates to the remote hubs.

import ballerina/log;
import ballerina/runtime;
import ballerina/websub;

websub:Client websubHubClientEP = new("https://localhost:9191/websub/hub");

public function main() {

    var registrationResponse = websubHubClientEP->registerTopic("<TOPIC_URL>");
    if (registrationResponse is error) {
        log:printError("Error occurred registering topic: " + <string>registrationResponse.detail().message);
    } else {
        log:printInfo("Topic registration successful!");
    }

    // Make the publisher wait until the subscriber subscribes at the hub.
    runtime:sleep(10000);

    log:printInfo("Publishing update to remote Hub");
    var publishResponse = websubHubClientEP->publishUpdate("<TOPIC_URL>", { "action": "publish", "mode": "remote-hub" });
    if (publishResponse is error) {
        log:printError("Error notifying hub: " + <string>publishResponse.detail().message);
    } else {
        log:printInfo("Update notification successful!");
    }

}

The hub client endpoint can also be used by subscribers to send subscription and unsubscription requests explicitly.

import ballerina/log;
import ballerina/websub;

websub:Client websubHubClientEP = new("<HUB_URL>");

public function main() {

    // Send subscription request for a subscriber service.
    websub:SubscriptionChangeRequest subscriptionRequest = {
        topic: "<TOPIC_URL>", 
        callback: "<CALLBACK_URL>",
        secret: "<SECRET>"
    };

    var subscriptionChangeResponse = websubHubClientEP->subscribe(subscriptionRequest);
    if (subscriptionChangeResponse is websub:SubscriptionChangeResponse) {
        log:printInfo("Subscription Request successful at Hub [" + subscriptionChangeResponse.hub 
                        + "] for Topic [" + subscriptionChangeResponse.topic + "]");
    } else {
        log:printError("Error occurred with Subscription Request", err = subscriptionChangeResponse);
    }

    // Send unsubscription request for the subscriber service.
    websub:SubscriptionChangeRequest unsubscriptionRequest = {
        topic: "<TOPIC_URL>",
        callback: "<CALLBACK_URL>"
    };

    subscriptionChangeResponse = websubHubClientEP->unsubscribe(unsubscriptionRequest);
    if (subscriptionChangeResponse is websub:SubscriptionChangeResponse) {
        log:printInfo("Unsubscription Request successful at Hub [" + subscriptionChangeResponse.hub
                + "] for Topic [" + subscriptionChangeResponse.topic + "]");
    } else {
        log:printError("Error occurred with Unsubscription Request", err = subscriptionChangeResponse);
    }
}

Configuration Parameters

The Ballerina WebSub implementation allows specifying the following properties/parameters via the Ballerina Config API, where the values specified via the Config API would override values specified as params on hub start up.

Configuration KeyDefault ValueDescription
b7a.websub.hub.leasetime86400The default lease period, if not specified in a request
b7a.websub.hub.signaturemethod"SHA256"The signature method to use for authenticated content distribution
b7a.websub.hub.remotepublishfalseWhether publishing updates against the topics in the hub could be done by remote publishers via HTTP requests with hub.mode set to publish
b7a.websub.hub.topicregistrationtrueWhether a topic needs to be registered at the hub for publishers to publish updates against the topic and for subscribers to send subscription requests for the topic

Introducing Specific Subscriber Services (Webhook Callback Services)

Ballerina's WebSub subscriber service listener can be extended to introduce specific Webhooks.

Instead of the single onNotification resource, you can introduce multiple resources to accept content delivery requests using specific subscriber services. These resources will correspond to the content delivery requests that will be delivered with respect to a particular topic.

For example, assume a scenario in which you receive notifications either when an issue is opened or when an issue is closed by subscribing to a particular topic in an issue tracking system. With a custom subscriber service listener, which extends the generic WebSub subscriber service listener, you can allow two resources to accept content delivery requests (e.g., onIssueOpened and onIssueClosed) instead of the onNotification resource.

These resources will accept two parameters:

  1. The generic websub:Notification record as the first parameter
  2. A custom record corresponding to the expected (JSON) payload of the notification (e.g., IssueCreatedEvent, IssueClosedEvent)

You can introduce a specific service as such by extending the generic subscriber service listener, specifying a mapping between the expected notifications and the resources that requests need to be dispatched to.

The mapping can be based on one of the following indicators of a notification request. (Requests will then be dispatched based on the value of the indicator in the request and a pre-defined mapping.)

  • A request header
  • The payload: the value of a particular key in the JSON payload
  • A request header and the payload (combination of the above two)

Samples for Resource Mapping

Based on a request header

Dispatching will be based on the value of the request header specified as topicHeader.

websub:ExtensionConfig extensionConfig = {
    topicIdentifier: websub:TOPIC_ID_HEADER,
    topicHeader: "<HEADER_TO_CONSIDER>",
    headerResourceMap: {
        "issueOpened": ("onIssueOpened", IssueOpenedEvent),
        "issueClosed": ("onIssueClosed", IssueClosedEvent)
    }
};

The "issueOpened": ("onIssueOpened", IssueOpenedEvent) entry indicates that when the value of the <HEADER_TO_CONSIDER> header is issueOpened, dispatching should happen to a resource named onIssueOpened.

The first parameter of this resource will be the generic websub:Notification record, and the second parameter will be a custom IssueOpenedEvent record mapping the JSON payload received when an issue is created.

Based on the payload

Dispatching will be based on the value in the request payload of one of the map keys specified in the payloadKeyResourceMap map.

websub:ExtensionConfig extensionConfig = {
    topicIdentifier: websub:TOPIC_ID_PAYLOAD_KEY,
    payloadKeyResourceMap: {
        "<PAYLOAD_KEY_TO_CONSIDER>": {
            "issueOpened": ("onIssueOpened", IssueOpenedEvent),
            "issueClosed": ("onIssueClosed", IssueClosedEvent)
        }
    }
};

The "issueOpened": ("onIssueOpened", IssueOpenedEvent) entry indicates that when the value for the JSON payload key <PAYLOAD_KEY_TO_CONSIDER> is issueOpened, dispatching should happen to a resource named onIssueOpened.

The first parameter of this resource will be the generic websub:Notification record, and the second parameter will be a custom IssueOpenedEvent record, mapping the JSON payload received when an issue is created.

Based on a request header and the payload

Dispatching will be based on both a request header and the payload as specified in the headerAndPayloadKeyResourceMap. Also, you can introduce a headerResourceMap and/or a payloadKeyResourceMap as additional mappings.

websub:ExtensionConfig extensionConfig = {
    topicIdentifier: websub:TOPIC_ID_HEADER_AND_PAYLOAD,
    topicHeader: "<HEADER_TO_CONSIDER>",
    headerAndPayloadKeyResourceMap: {
        "issue" : {
            "<PAYLOAD_KEY_TO_CONSIDER>" : {
                "opened": ("onIssueOpened", IssueOpenedEvent),
                "closed": ("onIssueClosed", IssueClosedEvent)
            }
        }
    }
};

The "opened": ("onIssueOpened", IssueOpenedEvent) entry indicates that when the value of the <HEADER_TO_CONSIDER> header is issue and the value of the <PAYLOAD_KEY_TO_CONSIDER> JSON payload key is opened, dispatching should happen to a resource named onIssueOpened.

The first parameter of this resource will be the generic websub:Notification record and the second parameter will be a custom IssueOpenedEvent record, mapping the JSON payload received when an issue is created.

Sample Specific Subscriber Service

In order to introduce a specific subscriber service, a new Ballerina listener needs to be introduced. This listener should wrap the generic ballerina/websub:Listener and include the extension configuration described above.

The following example is for a service provider that

  • allows registering webhooks to receive notifications when an issue is opened or assigned
  • includes a header named "Event-Header" in each content delivery request indicating what event the notification is for (e.g., "onIssueOpened" when an issue is opened and "onIssueAssigned" when an issue is assigned)
import ballerina/websub;

// Introduce a record mapping the JSON payload received when an issue is opened.
public type IssueOpenedEvent record {
    int id;
    string title;
    string openedBy;
}; 

// Introduce a record mapping the JSON payload received when an issue is assigned.
public type IssueAssignedEvent record {
    int id;
    string assignedTo;
}; 

// Introduce a new `listener` wrapping the generic `ballerina/websub:Listener` 
public type WebhookListener object {

    *AbstractListener;

    private websub:Listener websubListener;

    public function __init(int port) {
        // Introduce the extension config, based on the mapping details.
        websub:ExtensionConfig extensionConfig = {
            topicIdentifier: websub:TOPIC_ID_HEADER,
            topicHeader: "Event-Header",
            headerResourceMap: {
                "issueOpened": ("onIssueOpened", IssueOpenedEvent),
                "issueAssigned": ("onIssueAssigned", IssueAssignedEvent)
            }
        };
        
        // Set the extension config in the generic `websub:Listener` config.
        websub:SubscriberServiceEndpointConfiguration sseConfig = {
            extensionConfig: extensionConfig
        };
            
        // Initialize the wrapped generic listener.
        self.websubListener = new(port, config = sseConfig);
    }

    public function __attach(service s, string? name = ()) returns error?  {
        return self.websubListener.__attach(s, name = name);
    }

    public function __start() returns error? {
        return self.websubListener.__start();
    }
    
    public function __stop() returns error? {
        return self.websubListener.__stop();
    }
};

A service can now be introduced for the above service provider as follows.

import ballerina/io;
import ballerina/log;
import ballerina/websub;

@websub:SubscriberServiceConfig {
    path: "/subscriber",
    subscribeOnStartUp: false
}
service specificSubscriber on new WebhookListener(8080) {
    resource function onIssueOpened(websub:Notification notification, IssueOpenedEvent issueOpened) {
        log:printInfo(io:sprintf("Issue opened: ID: %s, Title: %s", issueOpened.id, issueOpened.title));
    }
    
    resource function onIssueAssigned(websub:Notification notification, IssueAssignedEvent issueAssigned) {
        log:printInfo(io:sprintf("Issue ID %s assigned to %s", issueAssigned.id, issueAssigned.assignedTo));
    }
}

For a step-by-step guide on introducing custom subscriber services, see the "Create Webhook Callback Services" section of "How to Extend Ballerina".

Module Detail

Records

Record Description
ExtensionConfig The extension configuration to introduce custom subscriber services.
HubConfiguration Record representing hub specific configurations.
HubStartedUpError Error to represent that a WebSubHub is already started up, encapsulating the started up Hub.
RemotePublishConfig Record representing remote publishing allowance.
SubscriberDetails Record to represent Subscriber Details.
SubscriberServiceConfiguration Configuration for a WebSubSubscriber service.
SubscriberServiceEndpointConfiguration Object representing the configuration for the WebSub Subscriber Service Endpoint.
SubscriptionChangeRequest Record representing a WebSub subscription change request.
SubscriptionChangeResponse Record representing subscription/unsubscription details if a subscription/unsubscription request is successful.
SubscriptionDetails Record to represent persisted Subscription Details retrieved.

Objects

Object Description
H2HubPersistenceStore

Represents H2 based hub persistence configuration and functions.

HubPersistenceStore

Represents the hub persistence configuration and functions.

IntentVerificationRequest

Object representing an intent verification request received.

Listener

Object representing the WebSubSubscriber Service Endpoint.

Notification

Object representing the WebSub Content Delivery Request received.

WebSubHub

Object representing a Ballerina WebSub Hub.

Endpoints

Endpoint Description
Caller

The caller remote functions to respond to client requests.

Client

The HTTP based Caller remote functions for outbound WebSub Subscription, Unsubscription, Registration, Unregistration and Notification requests to a Hub.

Functions

Function Description
addWebSubLinkHeader

Function to add link headers to a response to allow WebSub discovery.

extractTopicAndHubUrls

Function to retrieve hub and topic URLs from the http:response from a publisher to a discovery request.

startHub

Starts up the Ballerina Hub.

Type Definitions

Type Values Description
RemotePublishMode PUBLISH_MODE_FETCH | PUBLISH_MODE_DIRECT

The identifier to be used to identify the mode in which update content should be identified.

SignatureMethod SHA256 | SHA1

The identifier to be used to identify the cryptographic hash algorithm.

TopicIdentifier TOPIC_ID_PAYLOAD_KEY | TOPIC_ID_HEADER_AND_PAYLOAD | TOPIC_ID_HEADER

The identifier to be used to identify the topic for dispatching with custom subscriber services.

Annotations

Name Attaches To Data Type Description
SubscriberServiceConfig service SubscriberServiceConfiguration

WebSub Subscriber Configuration for the service, indicating subscription related parameters.

public type ExtensionConfig

The extension configuration to introduce custom subscriber services.

Field Name Data Type Default Value Description
topicIdentifier TOPIC_ID_HEADER|TOPIC_ID_PAYLOAD_KEY|TOPIC_ID_HEADER_AND_PAYLOAD TOPIC_ID_HEADER

The identifier based on which dispatching should happen for custom subscriber

topicHeader string? ()

The header to consider if required with dispatching for custom services

headerResourceMap map<(string,typedesc)>? ()

The mapping between header value and resource details

payloadKeyResourceMap map<map<(string,typedesc)>>? ()

The mapping between value for a particular JSON payload key and resource details

headerAndPayloadKeyResourceMap map<map<map<(string,typedesc)>>>? ()

The mapping between values for the header and a particular JSON payload key and resource details

public type HubConfiguration

Record representing hub specific configurations.

Field Name Data Type Default Value Description
leaseSeconds int 86400

The default lease seconds value to honour if not specified in subscription requests

signatureMethod SHA1|SHA256? SHA256

The signature method to use for authenticated content delivery (SHA1|SHA256)

remotePublish websub:RemotePublishConfig

The record representing configuration related to remote publishing allowance

topicRegistrationRequired boolean true

Whether a topic needs to be registered at the hub prior to publishing/subscribing to the topic

publicUrl string

The URL for the hub to be included in content delivery requests, defaults to http(s)://localhost:{port}/websub/hub if unspecified

clientConfig http:ClientEndpointConfig

The configuration for the hub to communicate with remote HTTP endpoints

hubPersistenceStore websub:HubPersistenceStore

The HubPersistenceStore to use to persist hub data

public type HubStartedUpError

Error to represent that a WebSubHub is already started up, encapsulating the started up Hub.

Field Name Data Type Default Value Description
message string

The error message

cause error? ()

The cause of the HubStartedUpError, if available

startedUpHub websub:WebSubHub

The WebSubHub object representing the started up Hub

public type RemotePublishConfig

Record representing remote publishing allowance.

Field Name Data Type Default Value Description
enabled boolean false

Whether remote publishers should be allowed to publish to this hub (HTTP requests)

mode PUBLISH_MODE_DIRECT|PUBLISH_MODE_FETCH PUBLISH_MODE_DIRECT

If remote publishing is allowed, the mode to use, direct (default) - fat ping with the notification payload specified or fetch - the hub fetches the topic URL specified in the "publish" request to identify the payload

public type SubscriberDetails

Record to represent Subscriber Details.

Field Name Data Type Default Value Description
callback string

The callback specified for the particular subscription

leaseSeconds int 0

The lease second period specified for the particular subscription

createdAt int 0

The time at which the subscription was created

public type SubscriberServiceConfiguration

Configuration for a WebSubSubscriber service.

Field Name Data Type Default Value Description
endpoints websub:Listener?[] []

Array of endpoints the service would be attached to

path string

Path of the WebSubSubscriber service

subscribeOnStartUp boolean false

Boolean indicating whether a subscription request is expected to be sent on start up

resourceUrl string

The resource URL for which discovery will be initiated to identify hub and topic if not specified

hub string

The hub at which the subscription should be registered

topic string

The topic for which this WebSub subscriber (callback) should be registered

leaseSeconds int 0

The period for which the subscription is expected to be active

secret string

The secret to be used for authenticated content distribution

callback string

The callback to use when registering, if unspecified host:port/path will be used

subscriptionClientConfig http:ClientEndpointConfig

The configuration for subscription client

public type SubscriberServiceEndpointConfiguration

Object representing the configuration for the WebSub Subscriber Service Endpoint.

Field Name Data Type Default Value Description
host string

The host name/IP of the endpoint

httpServiceSecureSocket http:ServiceSecureSocket? ()

The SSL configurations for the service endpoint

extensionConfig websub:ExtensionConfig? ()

The extension configuration to introduce custom subscriber services (webhooks)

public type SubscriptionChangeRequest

Record representing a WebSub subscription change request.

Field Name Data Type Default Value Description
topic string

The topic for which the subscription/unsubscription request is sent

callback string

The callback which should be registered/unregistered for the subscription/unsubscription request sent

leaseSeconds int 0

The lease period for which the subscription is expected to be active

secret string

The secret to be used for authenticated content distribution with this subscription

public type SubscriptionChangeResponse

Record representing subscription/unsubscription details if a subscription/unsubscription request is successful.

Field Name Data Type Default Value Description
hub string

The hub at which the subscription/unsubscription was successful

topic string

The topic for which the subscription/unsubscription was successful

response http:Response

The response from the hub to the subscription/unsubscription request

public type SubscriptionDetails

Record to represent persisted Subscription Details retrieved.

Field Name Data Type Default Value Description
topic string

The topic for which the subscription is added

callback string

The callback specified for the particular subscription

secret string

The secret to be used for authenticated content distribution

leaseSeconds int 0

The lease second period specified for the particular subscription

createdAt int 0

The time at which the subscription was created

public function addWebSubLinkHeader(http:Response response, string[] hubs, string topic)

Function to add link headers to a response to allow WebSub discovery.

Parameter Name Data Type Default Value Description
response http:Response

The response being sent

hubs string[]

The hubs the publisher advertises as the hubs that it publishes updates to

topic string

The topic to which subscribers need to subscribe to, to receive updates for the resource

public function extractTopicAndHubUrls(http:Response response) returns ((string,string[])|error<>)

Function to retrieve hub and topic URLs from the http:response from a publisher to a discovery request.

Parameter Name Data Type Default Value Description
response http:Response

The http:Response received

Return Type Description
(string,string[])|error<>

(topic, hubs) if parsing and extraction is successful, error if not

public function startHub(http:Listener hubServiceListener, websub:HubConfiguration? hubConfiguration) returns (WebSubHub|HubStartedUpError)

Starts up the Ballerina Hub.

Parameter Name Data Type Default Value Description
hubServiceListener http:Listener

The http:Listener to which the hub service is attached

hubConfiguration websub:HubConfiguration? ()

The hub specific configuration

Return Type Description
WebSubHub|HubStartedUpError

WebSubHub The WebSubHub object representing the newly started up hub, or HubStartedUpError indicating that the hub is already started, and including the WebSubHub object representing the already started up hub

public type H2HubPersistenceStore object

Represents H2 based hub persistence configuration and functions.

Field Name Data Type Default Value Description
subscriptionDbClient h2:Client

Database clint used to persist subscription data

  • <H2HubPersistenceStore> __init(h2:Client subscriptionDbClient)

    Parameter Name Data Type Default Value Description
    subscriptionDbClient h2:Client
  • <H2HubPersistenceStore> addSubscription(websub:SubscriptionDetails subscriptionDetails)

    Function to add or update subscription details.

    Parameter Name Data Type Default Value Description
    subscriptionDetails websub:SubscriptionDetails

    The details of the subscription to add or update

  • <H2HubPersistenceStore> removeSubscription(websub:SubscriptionDetails subscriptionDetails)

    Function to remove subscription details.

    Parameter Name Data Type Default Value Description
    subscriptionDetails websub:SubscriptionDetails

    The details of the subscription to remove

  • <H2HubPersistenceStore> addTopic(string topic)

    Function to add a topic.

    Parameter Name Data Type Default Value Description
    topic string

    The topic to add

  • <H2HubPersistenceStore> removeTopic(string topic)

    Function to remove a topic.

    Parameter Name Data Type Default Value Description
    topic string

    The topic to remove

  • <H2HubPersistenceStore> retrieveTopics() returns (string[])

    Function to retrieve all registered topics.

    Return Type Description
    string[]

    An array of topics

  • <H2HubPersistenceStore> retrieveAllSubscribers() returns (SubscriptionDetails[])

    Function to retrieve subscription details of all subscribers.

    Return Type Description
    SubscriptionDetails[]

    An array of subscriber details

public type HubPersistenceStore object

Represents the hub persistence configuration and functions.

  • <HubPersistenceStore> addSubscription(websub:SubscriptionDetails subscriptionDetails)

    Function to add or update subscription details.

    Parameter Name Data Type Default Value Description
    subscriptionDetails websub:SubscriptionDetails

    The details of the subscription to add or update

  • <HubPersistenceStore> removeSubscription(websub:SubscriptionDetails subscriptionDetails)

    Function to remove subscription details.

    Parameter Name Data Type Default Value Description
    subscriptionDetails websub:SubscriptionDetails

    The details of the subscription to remove

  • <HubPersistenceStore> addTopic(string topic)

    Function to add a topic.

    Parameter Name Data Type Default Value Description
    topic string

    The topic to add

  • <HubPersistenceStore> removeTopic(string topic)

    Function to remove a topic.

    Parameter Name Data Type Default Value Description
    topic string

    The topic to remove

  • <HubPersistenceStore> retrieveTopics() returns (string[])

    Function to retrieve all registered topics.

    Return Type Description
    string[]

    An array of topics

  • <HubPersistenceStore> retrieveAllSubscribers() returns (SubscriptionDetails[])

    Function to retrieve subscription details of all subscribers.

    Return Type Description
    SubscriptionDetails[]

    An array of subscriber details

public type IntentVerificationRequest object

Object representing an intent verification request received.

Field Name Data Type Default Value Description
mode string

The mode specified in the intent verification request, subscription or unsubscription

topic string

The topic for which intent is verified to subscribe/unsubscribe

challenge string

The challenge to be echoed to verify intent to subscribe/unsubscribe

leaseSeconds int 0

The lease seconds period for which a subscription will be active if intent verification is being done for subscription

request http:Request BLangTypeInit: new null ([])

The HTTP request received for intent verification

  • <IntentVerificationRequest> buildSubscriptionVerificationResponse(string expectedTopic) returns (Response)

    Builds the response for the request, verifying intention to subscribe, if the topic matches that expected.

    Parameter Name Data Type Default Value Description
    expectedTopic string

    The topic for which subscription should be accepted

    Return Type Description
    Response

    http:Response The response to the hub verifying/denying intent to subscribe

  • <IntentVerificationRequest> buildUnsubscriptionVerificationResponse(string expectedTopic) returns (Response)

    Builds the response for the request, verifying intention to unsubscribe, if the topic matches that expected.

    Parameter Name Data Type Default Value Description
    expectedTopic string

    The topic for which unsubscription should be accepted

    Return Type Description
    Response

    http:Response The response to the hub verifying/denying intent to unsubscribe

public type Listener object

Object representing the WebSubSubscriber Service Endpoint.

Field Name Data Type Default Value Description
config websub:SubscriberServiceEndpointConfiguration? ()

The configuration for the endpoint

  • <Listener> __init(int port, websub:SubscriberServiceEndpointConfiguration? config)

    Parameter Name Data Type Default Value Description
    port int
    config websub:SubscriberServiceEndpointConfiguration? ()
  • <Listener> __attach(service s, string? name) returns (error?<>)

    Parameter Name Data Type Default Value Description
    s service
    name string? ()
    Return Type Description
    error?<>

public type Notification object

Object representing the WebSub Content Delivery Request received.

  • <Notification> getQueryParams() returns (map<string>)

    Retrieves the query parameters of the content delivery request, as a map.

    Return Type Description
    map

    String constrained map of query params

  • <Notification> getEntity() returns (mime:Entity|error<>)

    Retrieves the Entity associated with the content delivery request.

    Return Type Description
    mime:Entity|error<>

    The Entity of the request. An error is returned, if entity construction fails

  • <Notification> hasHeader(string headerName) returns (boolean)

    Returns whether the requested header key exists in the header map of the content delivery request.

    Parameter Name Data Type Default Value Description
    headerName string

    The header name

    Return Type Description
    boolean

    Returns true if the specified header key exists

  • <Notification> getHeader(string headerName) returns (string)

    Returns the value of the specified header. If the specified header key maps to multiple values, the first of these values is returned.

    Parameter Name Data Type Default Value Description
    headerName string

    The header name

    Return Type Description
    string

    The first header value for the specified header name. An exception is thrown if no header is found. Ideally hasHeader() needs to be used to check the existence of header initially.

  • <Notification> getHeaders(string headerName) returns (string[])

    Retrieves all the header values to which the specified header key maps to.

    Parameter Name Data Type Default Value Description
    headerName string

    The header name

    Return Type Description
    string[]

    The header values the specified header key maps to. An exception is thrown if no header is found. Ideally hasHeader() needs to be used to check the existence of header initially.

  • <Notification> getHeaderNames() returns (string[])

    Retrieves all the names of the headers present in the content delivery request.

    Return Type Description
    string[]

    An array of all the header names

  • <Notification> getContentType() returns (string)

    Retrieves the type of the payload of the content delivery request (i.e: the content-type header value).

    Return Type Description
    string

    Returns the content-type header value as a string

  • <Notification> getJsonPayload() returns (json|error<>)

    Extracts json payload from the content delivery request.

    Return Type Description
    json|error<>

    The json payload or error in case of errors. If the content type is not JSON, an error is returned.

  • <Notification> getXmlPayload() returns (xml|error<>)

    Extracts xml payload from the content delivery request.

    Return Type Description
    xml|error<>

    The xml payload or error in case of errors. If the content type is not XML, an error is returned.

  • <Notification> getTextPayload() returns (string|error<>)

    Extracts text payload from the content delivery request.

    Return Type Description
    string|error<>

    The text payload or error in case of errors. If the content type is not of type text, an error is returned.

  • <Notification> getByteChannel() returns (io:ReadableByteChannel|error<>)

    Retrieves the request payload as a ByteChannel except in the case of multiparts.

    Return Type Description
    io:ReadableByteChannel|error<>

    A byte channel from which the message payload can be read or error in case of errors

  • <Notification> getBinaryPayload() returns (byte[]|error<>)

    Retrieves the request payload as a byte[].

    Return Type Description
    byte[]|error<>

    The byte[] representation of the message payload or error in case of errors

  • <Notification> getFormParams() returns (map<string>|error<>)

    Retrieves the form parameters from the content delivery request as a map.

    Return Type Description
    map|error<>

    The map of form params or error in case of errors

public type WebSubHub object

Object representing a Ballerina WebSub Hub.

Field Name Data Type Default Value Description
hubUrl string

The URL of the started up Ballerina WebSub Hub

  • <WebSubHub> __init(string hubUrl, http:Listener hubHttpListener)

    Parameter Name Data Type Default Value Description
    hubUrl string
    hubHttpListener http:Listener
  • <WebSubHub> stop() returns (boolean)

    Stops the started up Ballerina WebSub Hub.

    Return Type Description
    boolean

    boolean indicating whether the internal Ballerina Hub was stopped

  • <WebSubHub> publishUpdate(string topic, string|xml|json|byte[]|io:ReadableByteChannel payload, string? contentType) returns (error?<>)

    Publishes an update against the topic in the initialized Ballerina Hub.

    Parameter Name Data Type Default Value Description
    topic string

    The topic for which the update should happen

    payload string|xml|json|byte[]|io:ReadableByteChannel

    The update payload

    contentType string? ()

    The content type header to set for the request delivering the payload

    Return Type Description
    error?<>

    error if the hub is not initialized or does not represent the internal hub

  • <WebSubHub> registerTopic(string topic) returns (error?<>)

    Registers a topic in the Ballerina Hub.

    Parameter Name Data Type Default Value Description
    topic string

    The topic to register

    Return Type Description
    error?<>

    error if an error occurred with registration

  • <WebSubHub> unregisterTopic(string topic) returns (error?<>)

    Unregisters a topic in the Ballerina Hub.

    Parameter Name Data Type Default Value Description
    topic string

    The topic to unregister

    Return Type Description
    error?<>

    error if an error occurred with unregistration

  • <WebSubHub> getAvailableTopics() returns (string[])

    Retrieves topics currently recognized by the Hub.

    Return Type Description
    string[]

    An array of available topics

  • <WebSubHub> getSubscribers(string topic) returns (SubscriberDetails[])

    Retrieves details of subscribers registered to receive updates for a particular topic.

    Parameter Name Data Type Default Value Description
    topic string

    The topic for which details need to be retrieved

    Return Type Description
    SubscriberDetails[]

    An array of subscriber details

Endpoint Caller

The caller remote functions to respond to client requests.

  • <Caller> respond(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[] message) returns (error?<>)

    Sends the response to the caller.

    Parameter Name Data Type Default Value Description
    message http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]

    The response or any payload of type string, xml, json, byte[],io:ReadableByteChannel or mime:Entity[]

    Return Type Description
    error?<>

    Returns an error on failure

  • <Caller> ok(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[] message) returns (error?<>)

    Sends the response to the caller with the status 200 OK.

    Parameter Name Data Type Default Value Description
    message http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]

    The response or any payload of type string, xml, json, byte[], io:ReadableByteChannel or mime:Entity[]

    Return Type Description
    error?<>

    Returns an error on failure

  • <Caller> accepted(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[] message) returns (error?<>)

    Sends the response to the caller with the status 202 Accepted.

    Parameter Name Data Type Default Value Description
    message http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[] ()

    The response or any payload of type string, xml, json, byte[], io:ReadableByteChannel or mime:Entity[]. This message is optional.

    Return Type Description
    error?<>

    Returns an error on failure

Endpoint Client

The HTTP based Caller remote functions for outbound WebSub Subscription, Unsubscription, Registration, Unregistration and Notification requests to a Hub.

Field Name Data Type Default Value Description
hubUrl string

The URL of the target Hub to which requests need to be sent

  • <Client> subscribe(websub:SubscriptionChangeRequest subscriptionRequest) returns (SubscriptionChangeResponse|error<>)

    Sends a subscription request to a WebSub Hub.

    Parameter Name Data Type Default Value Description
    subscriptionRequest websub:SubscriptionChangeRequest

    The SubscriptionChangeRequest containing subscription details

    Return Type Description
    SubscriptionChangeResponse|error<>

    SubscriptionChangeResponse indicating subscription details, if the request was successful else error if an error occurred with the subscription request

  • <Client> unsubscribe(websub:SubscriptionChangeRequest unsubscriptionRequest) returns (SubscriptionChangeResponse|error<>)

    Sends an unsubscription request to a WebSub Hub.

    Parameter Name Data Type Default Value Description
    unsubscriptionRequest websub:SubscriptionChangeRequest

    The SubscriptionChangeRequest containing unsubscription details

    Return Type Description
    SubscriptionChangeResponse|error<>

    SubscriptionChangeResponse indicating unsubscription details, if the request was successful else error if an error occurred with the unsubscription request

  • <Client> registerTopic(string topic) returns (error?<>)

    Registers a topic in a Ballerina WebSub Hub against which subscribers can subscribe and the publisher will publish updates.

    Parameter Name Data Type Default Value Description
    topic string

    The topic to register

    Return Type Description
    error?<>

    error if an error occurred registering the topic

  • <Client> unregisterTopic(string topic) returns (error?<>)

    Unregisters a topic in a Ballerina WebSub Hub.

    Parameter Name Data Type Default Value Description
    topic string

    The topic to unregister

    Return Type Description
    error?<>

    error if an error occurred unregistering the topic

  • <Client> publishUpdate(string topic, string|xml|json|byte[]|io:ReadableByteChannel payload, string? contentType, map<string>? headers) returns (error?<>)

    Publishes an update to a remote Ballerina WebSub Hub.

    Parameter Name Data Type Default Value Description
    topic string

    The topic for which the update occurred

    payload string|xml|json|byte[]|io:ReadableByteChannel

    The update payload

    contentType string? ()

    The type of the update content, to set as the ContentType header

    headers map? ()

    The headers, if any, that need to be set

    Return Type Description
    error?<>

    error if an error occurred with the update

  • <Client> notifyUpdate(string topic, map<string>? headers) returns (error?<>)

    Notifies a remote WebSub Hub that an update is available to fetch, for hubs that require publishing to happen as such.

    Parameter Name Data Type Default Value Description
    topic string

    The topic for which the update occurred

    headers map? ()

    The headers, if any, that need to be set

    Return Type Description
    error?<>

    error if an error occurred with the notification