WebSockets configuration HOWTO
Table of contents
- WebSockets configuration HOWTO
- Available WebSockets endpoints
- WebSockets configuration
- Managing websocket configuration via the REST API
Summary
As of v7.5.0
(incl.) of stubby4j
, you can stub a WebSocket with the stubby4j
app, and use it to send and receive messages across the WebSocket connection. On this page you will learn how to add a new websocket configuration to stubby4j
stubs config, described in YAML.
The WebSocket protocol provides a way to exchange data between a client and stubby4j
over a persistent connection. The data can be passed in both directions with low latency and overhead, and without breaking the connection. WebSockets provide a bidirectional, full-duplex communications channel that operates over HTTP through a single TCP socket connection. This means the stubby4j
can independently send data to the client without the client having to request it, and vice versa.
Do note, that stubby4j
versions v7.5.x
only supports WebSocket protocol over the HTTP/1.1
, by the virtue of relying on jetty v9.x.x
which does not support bootstrapping WebSockets with HTTP/2
. Support for RFC8441 WebSocket over HTTP/2 is available in jetty v10.x.x and v11.x.x. In the future versions of stubby4j
, the library will be powered by jetty v11.x.x
.
Keep on reading to understand how to add websocket configurations to your stubby4j
YAML config.
Available WebSockets endpoints
When stubby4j
application starts, it exposes two WebSockets endpoints over HTTP/1.1
: secure (i.e.: over TLS) & insecure (i.e.: no TLS). When making websocket requests to the stubbed websocket configuration, the request should be sent over to the websocket context root path /ws/
(i.e.: protocol_scheme://addreess:port/ws/
), plus the stubbed request URI path. For example:
- Insecure:
ws://<STUBS_HOSTNAME>:<STUBS_PORT>/ws/<URI_PATH>
=>ws://localhost:8882/ws/demo/web-socket/1
- Secure:
wss://<STUBS_HOSTNAME>:<STUBS_TLS_PORT>/ws/<URI_PATH>
=>wss://localhost:7443/ws/demo/web-socket/1
To note, if you want to make secure websocket requests , you have to add to your client certificate trust-store stubby4j’s self-signed certificate (if you have not provided your own), see Client-side TLS configuration and Making requests over TLS for more information
Now let’s understand how to declare a websocket configuration.
WebSockets configuration
In stubby4j
YAML config, the websocket configuration metadata is declared using the web-socket
property. You can have multiple web-socket
configured, where each web-socket
must be uniquely identified by a request URI path, used for connecting to the websocket, for example:
- web-socket:
url: /demo/web-socket/1
...
...
- web-socket:
url: /demo/web-socket/2
...
...
Fully-populated example with multiple web-socket
objects
Click to expand
- web-socket:
description: this is a web-socket config
url: /demo/web-socket/1
sub-protocols: echo, mamba, zumba
on-open:
policy: once
message-type: text
body: You have been successfully connected
delay: 200
on-message:
- client-request:
message-type: text
body: do push
server-response:
policy: push
message-type: text
body: pushing
delay: 50
- client-request:
message-type: text
body: hello
server-response:
policy: once
message-type: text
body: bye-bye
delay: 250
- client-request:
message-type: text
body: disconnect with a message
server-response:
policy: disconnect
message-type: text
body: bon-voyage
delay: 250
- web-socket:
url: /demo/web-socket/2
sub-protocols: echo, mamba, zumba
on-open:
policy: once
message-type: text
body: You have been successfully connected
on-message:
- client-request:
message-type: text
body: send-big-json
server-response:
policy: once
message-type: binary
file: ../json/response/json_response_1.json
delay: 250
- client-request:
message-type: text
body: push-pdf-to-me
server-response:
policy: push
message-type: binary
file: ../binary/hello-world.pdf
delay: 500
- web-socket:
url: /demo/web-socket/3
sub-protocols: echo, mamba, zumba
on-open:
policy: once
message-type: binary
file: ../binary/hello-world.pdf
delay: 200
- web-socket:
url: /demo/web-socket/4
on-message:
- client-request:
message-type: binary
file: ../binary/hello-world.pdf
server-response:
policy: once
message-type: binary
file: ../binary/hello-world.pdf
delay: 500
- client-request:
message-type: binary
file: ../json/response/json_response_6.json
server-response:
policy: once
message-type: binary
file: ../binary/hello-world.pdf
delay: 500
- web-socket:
url: /demo/web-socket/5
on-message:
- client-request:
message-type: text
body: send-fragmentation-pls
server-response:
policy: fragmentation
message-type: binary
file: ../json/response/json_response_1.json
delay: 10
YAML websocket configuartion can be in the same YAML config as the other HTTP stub types supported by stubby4j
, i,e.: it is totally OK to mix configs for request
/response
/proxy-config
(HTTP endpoint configuration HOWTO) & web-socket
in the same file. For example, the following is a totally valid YAML configuration:
- proxy-config:
uuid: default
description: this is a default catch-all config
strategy: as-is
properties:
endpoint: https://jsonplaceholder.typicode.com
- request:
method:
- GET
url: /resources/user/1
response:
status: 200
body: >
{"status": "OK"}
headers:
content-type: application/json
- web-socket:
url: /demo/web-socket/5
on-message:
- client-request:
message-type: text
body: send-fragmentation-pls
server-response:
policy: fragmentation
message-type: binary
file: ../json/response/json_response_1.json
delay: 10
Alternatively, you may consider splitting main YAML config in order to have logical separation in your YAML configuration between HTTP stubs and websocket configs:
includes:
- include-all-test-stubs.yaml
- include-web-socket-config.yaml
(from: main-test-stubs-with-web-socket-config.yaml)
Supported YAML properties
This section explains the usage, intent and behavior of each YAML property on the web-socket
object.
uuid (optional
)
Unique identifier so it would be easier to manage websocket configuration via the REST API at runtime
description (optional
)
This can be anything describing your websocket configuration.
url (required
)
Defines a unique (across all defined web-scoket
objects in the YAML config) websocket URI path that client should connect to. The url
should not include the websocket context root path /ws/
. For example, if a client plans to open a webscoket connection to ws://localhost:8882/ws/demo/web-socket/1
, then the value of the url
property should be /demo/web-socket/1
- web-socket:
url: /demo/web-socket/1
...
...
sub-protocols (optional
)
Defines a comma-separated arbitrary sub-protocol names. Defaults to empty string.
- web-socket:
url: /demo/web-socket/1
sub-protocols: echo, mamba, zumba
...
...
If the sub-protocols
is specified, then each value in the comma-separated value will be matched against the value of Sec-WebSocket-Protocol
header in the client’s request during the handshake with the connecting client. The server will include the same field and one of the matched subprotocol values in its response for the connection to be established. See RFC6455#section-1.9 about subprotocols using the WebSocket protocol
If the the sub-protocols
is specified, then the value was not matched against the value of Sec-WebSocket-Protocol
header in the client’s request, the stubby4j
server will respond with 403
error.
What are the sub-protocols?
WebSocket protocol defines a mechanism to exchange arbitrary messages. What those messages mean, what kind of messages a client can expect at any particular point in time or what messages they are allowed to send is entirely up to the implementing application.
Sub-protocol can help to reach an agreement between the server and client about these things, i.e.: it is like a protocol specification. The sub-protocols
property lets clients formally exchange this information. You can just make up any name for any protocol you want. The server can simply check that the client’s request appears to adhere to that protocol during the handshake.
on-open
The object on-open
describes the behavior that stubby4j
websocket server initiates when the WebSocket connection between the server and a client is established. With the on-open
object you can configure what events the connected client should receive and in what manner. The server starts the event sending first, upon established connection, without waiting for the connected client to request them first.
Do note the difference between the on-open
server behavior VS the on-message (discussed further) server behavior: with the behavior defined in on-message, the server requires an explicit request (i.e.: a trigger) from the connected client to start sending events.
To note:
on-open
object is optional when the object on-message (discussed further) has been declared in thisweb-socket
configon-open
object is required when the object on-message is not declared in thisweb-socket
config
on-open object properties
The on-open
object supports the following properties: policy
, message-type
, body
, file
, delay
. Keep on reading to understand their usage, intent and behavior.
policy (optional
)
Defines the behavior of the server, when sending events (i.e.: any text, binary or Ping messages) to the connected client using the defined event metadata. Defaults to once
. Currently, the following five types of policies are supported and explained as follows:
once
: the server sends an event once only.push
: the server sends the same event in a periodic manner. Thepush
value should be used together with the defined delay property. Thestubby4j
server will keep continuously pushing events to the connected client in a periodic manner.-
fragmentation
: the server sends an event payload in a form sequential fragmented frames one after another in a periodic manner, instead of sending the payload as a whole blob, which is the behavior of policiesonce
,push
anddisconnect
. Thefragmentation
value should be used together with the defined delay property.A use-case for the
fragmentation
policy can be as per following: you want to configurestubby4j
websocket server to stream a large file to the connected client in chunks instead of sending a one whole blob. -
ping
: the server sends aPing
event (without a payload) as per WebSocket spec RFC6455#section-5.5.2 in a periodic manner. Theping
value should be used together with the defined delay property. Thestubby4j
server will keep continuously pinging the connected client in a periodic manner.The behavior of
ping
is similar to thepush
behavior, the difference here is thatstubby4j
sends a special binary data frame of typePing
instead of a text in UTF-8 or any other binary data. disconnect
: the server sends an event once only, followed by a WebSocketClose
frame with status code1000
. In other words, the server gracefully closes the connection to the remote client endpoint
message-type (optional
)
Defines the payload type of the event, which the server sends to the connected client using the defined event metadata. Defaults to text
Currently, the following two types of message types are supported:
text
: the event payload sent in a UTF-8 text formatbinary
: the event payload sent as bytes
Please note, in case of policy
of type ping
, even if you defined message-type: text
, the event payload will always be a binary data frame of type Ping
, as per WebSocket spec RFC6455#section-5.5.2
delay (optional
)
Describes the delay (in milliseconds) between the subsequent server events to the connected client. Defaults to zero. This property should be used in conjunction with defined policy
of type push
, fragmentation
or ping
.
If one of the aforementioned policy types is defined and the delay
is not specified, there will be no delay between the subsequent server events to the connected client. The delay
takes no affect with the policies of type once
and disconnect
.
body (optional
)
Contains contents of the server event payload to the connected client. Defaults to empty string. Depending on the defined message-type
, the payload will be sent as text in UTF-8 format or bytes.
- web-socket:
...
...
on-open:
...
message-type: binary
body: >
[{
"name":"John",
"email":"john@example.com"
},{
"name":"Jane",
"email":"jane@example.com"
}]
...
file (optional
)
Holds a path to a local file (it can be an absolute or relative path to the main YAML specified in -d
or --data
, see command-line-switches). This property allows you to split up your config across multiple files instead of making one huge bloated web-config
YAML. Depending on the defined message-type
value (text
or binary
), the payload will be sent as text in UTF-8 format or bytes.
For example, let’s say you want the server to render a large JSON response body to the connected client, so instead of dumping a lot of text under the body
property, you could specify a local file with the payload content using the file
property (btw, the file
property can also refer to binary files):
- web-socket:
...
...
on-open:
...
message-type: binary
file: ../json/extremelyLongJsonFile.json
...
Please note:
- If both
file
&body
properties are supplied, thefile
takes precedence & replacesbody
with the contents from the provided file - If the local file could not be loaded using the path form
file
property,stubby4j
falls back to the value stubbed inbody
. Ifbody
was not stubbed, an empty string is returned by default - Local file path specified in
file
it can be ASCII of binary file (PDF, images, etc.). Please keep in mind, that contents of the local file is preloaded uponstubby4j
startup and its content is kept as a byte array in memory.
on-message
The object on-message
describes the behavior of the stubby4j
websocket server upon receiving a request from the connected client. With the on-message
object you can configure what events your client should receive and in what manner, upon receiving a client request.
Do note the difference between the on-message
server behavior VS the on-open server behavior: with the behavior defined in on-open, the server does not require an explicit request (i.e.: a trigger) from the connected client and starts sending events the moment the connection was established.
To note:
on-message
object is optional when the object on-open (discussed earlier) has been declared in thisweb-socket
configon-message
object is required when the object on-open is not declared in thisweb-socket
config
on-message object properties
The on-message
object supports the following properties: client-request
and server-response
. Keep on reading to understand their usage, intent and behavior.
client-request (required
)
The client-request
object describes the metadata of the incoming client request, in order to trigger stubby4j
server websocket response described by the following server-response
object. For example:
- web-socket:
...
on-message:
- client-request:
message-type: text
body: send-me-a-message
server-response:
...
...
...
After WebSocket connection has been established and the server receives text message send-me-a-message
from the connected client, the stubby4j
server will render a response as described by the server-response
object.
The client-request
object supports the following properties: message-type
, body
and file
. Those are the same YAML properties as the properties discussed in on-open object properties, the difference is here it is the message type and the request payload that the client must send to the server. So please refer to the aforementioned section to understand their usage, intent and behavior.
server-response (required
)
With the server-response
object you can configure what events your client should receive and in what manner when the metadata of the incoming client request was matched the stubbed metadata in client-request
.
The server-response
object supports the following properties: policy
, message-type
, body
, file
, delay
. Those are the same YAML properties as the properties discussed in on-open object properties. So please refer to the aforementioned section to understand their usage, intent and behavior.
- web-socket:
...
...
on-message:
- client-request:
...
...
server-response:
policy: fragmentation
message-type: binary
file: ../json/response/json_response_1.json
delay: 10
As of v7.6.1
(incl.) or latest
of stubby4j
, you can stub a WebSocket with multiple sequenced server-response
for the same stubbed URI.
When sequenced server-response
is configured, on each incoming request to the same URI, a subsequent response in the list will be sent to the client. The sequenced server-response
play in a cycle (loop). In other words: after the response sequence plays through, the response cycle restarts on the next incoming client request.
- web-socket:
...
...
on-open:
...
...
on-message:
- client-request:
message-type: text
body: Hello, World!
server-response:
- policy: once
message-type: text
body: hello-world-0
delay: 20
- policy: once
message-type: text
body: hello-world-1
delay: 30
- policy: fragmentation
message-type: binary
body: hello-world-2,hello-world-2a and hello-world-2c
delay: 40
- policy: once
message-type: text
body: hello-world-3
delay: 50
Managing websocket configuration via the REST API
Just like with stubs management, stubby4j
enables you to manage your web-socket
definitions via the REST API exposed by the Admin Portal. See the available REST API summary