Real-time capabilities
Introduction
In the current world, accessibility to information is crucial. Moreover, it’s not only important to have the information available, but when it’s available has gained great importance; the time to access new information is a key factor that many companies heavily rely on. To address this issue, Carbon LDP™ provides real-time capabilities in its platform.
Connecting to the broker
The platform uses WebSocket communication to allow for real-time message transmission with clients. Furthermore, it uses the Simple Text Oriented Messaging Protocol (STOMP) to compose its messages. Therefore, whichever client connects to the broker needs to be able to understand this protocol.
You can connect your WebSocket client to the broker through this address: ws://localhost:8083/broker/websocket
.
What is more, the platform also exposes a SockJS endpoint for clients to connect to. It is located in the following address: http://localhost:8083/broker
.
In conclusion, to be able to work with Carbon LDP™’s real-time features you will need to write your own WebSocket or SockJS client, capable of receiving STOMP messages.
Subscribing to events
The real-time capabilities that Carbon LDP™ provides come in the form of subscriptions to events that occur within the platform. Carbon LDP™ uses an Advanced Message Queuing Protocol (AMQP) implementation as a broker relay, so whenever you want to subscribe to an event you’ll use a path similar to this:
/topic/{event-target}.{event-type}.{document-slug-1}.{document-slug-n}
To subscribe to any event, then, you first need to identify two main things: the event you’re going to subscribe to, and the subject (document) you are interested in.
With this in mind, let’s continue detailing our subscription process.
Event types
To specify the event, Carbon LDP™ provides a series of predefined events that it can subscribe to; such events are the following:
- Child created
- Document modified
- Document deleted
- Member added
- Member removed
- Whenever a subject’s child is created.
- Whenever any of a document’s properties are modified.
- Whenever a document is deleted.
- Whenever a new member is added to a document.
- Whenever an existing member is removed from a document.
To subscribe to any of these events you need to include them on your subscription path in the following way:
Event | Event target | Event type | Sample path |
---|---|---|---|
Child created | child | created | /topic/child.created.{...} |
Document modified | document | modified | /topic/document.modified.{...} |
Document deleted | document | deleted | /topic/document.deleted.{...} |
Member added | member | added | /topic/document.added.{...} |
Member removed | member | removed | /topic/document.removed.{...} |
Depending on the type of event you are subscribed to, the return messages will differ. You should always expect a bNode, containing the type of event that triggered the message emission. Also, every message received will include a c:target
property, detailing the subject you’re subscribed to, which caused the event notification.
Moreover, if the event type was one of c:ChildCreatedEvent
, c:MemberAddedEvent
, or c:MemberRemovedEvent
, the message will also include a c:details
property pointing to a new bNode. This bNode will have a specific type and properties.
Take a look at the following table to get all the details regarding the structure of the messages you might receive, based on the type of event you’re subscribed to.
Event type | Return message model |
---|---|
Child created |
|
Document modified |
|
Document deleted |
|
Member added |
|
Member removed |
|
Alternatively, on the subscription path you could also include an asterisk (*
) as a wild card for an event target or an event type. This will allow you to subscribe to multiple event types with a single subscription path.
For example, if you wanted to monitor a document’s member events, both a member addition and a member removal, you could use a path similar to this:
/topics/member.*.{...}
In addition, if you wanted to monitor all possible events that could occur within a document, you could use a path similar to this:
/topic/*.*.{...}
Be careful since this could cause that a single action emits messages of different types within a single subscription. For example, when creating a child document you would expect to receive a notification of type c:ChildCreatedEvent
; however, creating a child also adds that document as a member of its parent. Therefore, a child creation would also emit a message of type c:MemberAddedEvent
; which you would be listening to using the last subscription path we detailed.
Now, let’s review how you would determine which subject you want to subscribe to.
Subject
Now, we need to determine which subject we will be subscribing to. While you can specify a particular resource to subscribe to, you can also use certain wild cards in your subscription path to subscribe to all the resource contained in or below a specific level.
These are the following structures you can use to detail your subscription’s subject:
-
document-slug
: indicates a particular resource.
E.g./topics/{event-target}.{event-type}.projects
means events that happen on theprojects/
document. -
*
: indicates any resource on that specific level.
E.g./topics/{event-target}.{event-type}.projects.*
means events that happen one level below theprojects/
document. -
#
: indicates any resource below that specific level.
E.g./topics/{event-target}.{event-type}.projects.#
means events that happen on any level below theprojects/
document.
In order to subscribe to an application’s root document, you would simply omit including a subject within your subscription path, i.e. /topic/{event-target}.{event-type}
.
Also, since dots (.
) are reserved characters in AMQP paths, they need to be replaced in your subscription path with a caret (^
). For example, if your platform contained a .private/
document, your subscription path would be /topic/{event-target}.{event-type}.^private
Putting it all together
Let’s use an example to better explain this topic. Imagine that you have a company and that you have defined the following structure in your platform instance:
- /
Your platform’s root (usuallyhttp://your-platform-domain:8083/
)- clients/
The document that contains the clients- client-1/
Document defining client 1 properties - client-2/
Document defining client 2 properties - client-n…/
And so on…
- client-1/
- department/
Document that contains the departments of your company - etc…
Other aspects your company has
- clients/
First, let’s imagine you want to know whenever a client is added to your company so that you can perform some adjustments to the company’s budget.
In this case, since we want to know whenever a client is added to our clients list, let’s subscribe to the clients/
document, which contains all the clients as children. This is our subscription’s subject.
Furthermore, we want to be notified whenever a child is created within the clients/
container, therefore, we are subscribing to a child created event.
Our final subscription path would look like this: /topics/child.created.clients
.
Finally, the payload received will look similar to this:
[
{
"@id" : "_:node1cqm2c7pax250",
"@type" : [ "https://carbonldp.com/ns/v1/platform#ChildCreatedEvent" ],
"https://carbonldp.com/ns/v1/platform#details" : [ {
"@id" : "_:node1cqm2c7pax251"
} ],
"https://carbonldp.com/ns/v1/platform#target" : [ {
"@id" : "http://localhost:8083/clients/"
} ]
}, {
"@id" : "_:node1cqm2c7pax251",
"@type" : [ "https://carbonldp.com/ns/v1/platform#DocumentCreatedEventDetails" ],
"https://carbonldp.com/ns/v1/platform#createdDocument" : [ {
"@id" : "http://localhost:8083/clients/client-3/"
} ]
}
]
In a separate situation, let’s now imagine that you also want to monitor whenever a client document is altered, this means modified or removed, to alter a contact list contained in a separate service.
Here, we want to monitor all the resources contained in the clients/
document, therefore, we could use a wild card to subscribe to that specific level.
Also, we are looking for different event types that are related to documents, so we could also add a wild card when defining the event type in our subscription.
In the end, our subscription path would look like this: /topics/document.*.clients.*
.
A message received due to this subscription will look similar to this:
[
{
"@id" : "_:node1cqm2c7pax331",
"@type" : [ "https://carbonldp.com/ns/v1/platform#DocumentModifiedEvent" ],
"https://carbonldp.com/ns/v1/platform#target" : [ {
"@id" : "http://localhost:8083/clients/client-1/"
} ]
}
]
Conclusion
By developing a WebSocket or SockJS client capable of handling STOMP messages, you can receive notifications whenever events occur in your Carbon LDP™ platform thanks to its real-time capabilities.
A subscription can be created using a AMQP path detailing the event target, event type, and an optional document path.
Subscription paths support the use of wild cards to subscribe to multiple event types and/or multiple levels of an endpoint. Bear in mind that this might lead to multiple messages being emitted on a single subscription from a single action.
Normally, developers will prefer use of the Carbon LDP™ Workbench (GUI) and an SDK, which together simplify the process of building and working with the platform. Still, all functions of the platform can be accessed through the REST API and those developers who understand the REST API may find it advantageous to use in some cases.