Fork me on GitHub

Back to Home

WebSockets configuration HOWTO

Table of contents

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:

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

Back to top

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)

Back to top

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.

Back to top

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:

Back to top

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:

Back to top

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:

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

Back to top

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.

Back to top

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"
         }]
      ...

Back to top

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:

Back to top

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:

Back to top

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.

Back to top

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

Back to top

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

Back to Home