WebSockets is a bidirectional communication channel that can be established at the request of the client. While websocket communication is not really part of a standard REST api, it has many uses and can easily be used together with one.
api_message(api, handler, async = NULL, then = NULL)This functions return the api object allowing for easy chaining
with the pipe
A plumber2 api object to add the handler to
A function conforming to the specifications laid out in Details
If FALSE create a regular handler. If TRUE, use the default
async evaluator to create an async handler. If a string, the async evaluator
registered to that name is used. If a function is provided then this is used
as the async evaluator. See the Async section for more detail
A list of function to be called once the async handler is done.
The functions will be chained using promises::then(). See the Async
section for more detail
You can handle websocket messages asynchronously if needed. Like with
request handlers you can either do it manually by creating and
returning a promise inside the handler, or by letting plumber2 convert your
handler to an async handler using the async argument. Due to the nature of
promises a handler being converted to a promise can't take request and
server arguments, so if you need to manipulate these you need to use then
(more on this shortly). The same conventions about return value holds for
async message handlers as for regular ones.
Because you can't manipulate request or server in the async handler it
may be needed to add operations to perform once the async handler has
finished. This can be done through the then argument. This takes a list of
functions to chain to the promise using promises::then(). Before the then
chain is executed the return value of the async handler will be send back to
the client if it is a string or a raw vector. Each then call will receive
the same arguments as a standard message handler as well as result which
will hold the return value of the previous handler in the chain. For the
first then call result will be whatever the main async handler returned.
The return value of the last call in the chain will be silently ignored.
A websocket message handler can be added to an API in an annotated route file
by using the @message tag
#* @message
function(message) {
if (message == "Hello") {
return("Hello, you...")
}
}
You can create async handlers with then chaining using annotation, through
the @async and @then tags
#* @message
#* @async
function(message) {
if (message == "Hello") {
return("Hello, you...")
}
}
#* @then
function(server) {
server$log("message", "websocket message received")
}
A handler for a websocket message is much simpler than for requests in general since it doesn't have to concern itself with methods, paths, and responses. Any message handler registered will get called in sequence when a websocket message is received from a client. Still, a few expectations apply
The handler can take any of the following arguments:
message: Either a raw vector if the message received is in binary form or
a single string, giving the message sent from the client
server: The Plumber2 object representing your server implementation
client_id: A string uniquely identifying the session the request comes
from
request: The request that was initially used to establish the websocket
connection with the client as a reqres::Request object
It is not expected that a websocket message sends a response and thus the handler is not required to do anything like that. However, if the handler returns either a raw vector or a single string it is taken as a signal to send this back to the client. Any other return value is silently ignored.
api() |>
api_message(
function(message) {
if (message == "Hello") {
return("Hello, you...")
}
}
)
Run the code above in your browser using DataLab