Quantcast
Channel: Trajano » web sockets
Viewing all articles
Browse latest Browse all 2

WebSocket Service API Contact

$
0
0

The WebSocket API like HTTP is very open and allows a lot of flexibility to be able to work with many different types of applications. Like REST on top of HTTP, a WebSocket Service is an architectural style and has no defined standards making the need for a contract between UI developers and server side developers in order to keep things sane. This blog post defines a WebSocket Service API Contract that I use for my projects akin to the REST API Contract I use in my projects.

Objectives

Like the REST API Contract I start with the important ones (i.e. the target platform) and work from there.

  • Ensure it works with AngularJS as that is the UI framework being used for my development.
  • Ensure it works with JAX-RS 2.0 as that is the REST framework being used for my development.
  • Only use text messages and only transmit JSON object data.
  • Use no more than a single endpoint per page.
  • Do not use WebSockets to transmit resources; HTTP GET must be used to get resources from the server.

Limit to text

Though binary messages may be more efficient, creating a binary transport library that works with the UI and Java EE server adds undue complications making things harder to debug. As such, simple JSON object data is the only allowed message to be transmitted.

Resource retrieval is not done on WebSockets as no user agent caches what is retrieved in WebSocket connections. Resource retrievals must be done with HTTP GET which may call a REST API, this allows for caching of the response data.

Single endpoint vs Multiple endpoints

The main concern with using single endpoint and multiple endpoints are that multiple endpoints may create multiple TCP connections to the server and may exhaust it’s connection pool. I had experimented using Glassfish and looking at the network activity using tcptrack. From my experiments it seems that a new TCP connection is established per endpoint which will exhaust the connections possible from a server.

As such the application needs to handle the messages rather than relying on an API to do it for them. So an established design pattern called Envelope Wrapper where messages are wrapped in an envelope before transmitting.

Message envelope

A message that gets sent over the wire looks like this.

{
  "_" : "message type",
  ...
}

The only reserved key is “_” which is used to pass a message type that is understood by the UI and the server and is used to dispatch to the proper handler. “_” is used just to reduce the size of the message going back and forth. The rest of it represents the message contents.

Abstract message types

There are some common message patterns that get sent as well. The following lists some of the envelope structures that get sent.

Request/response patterns to and from the server

{
  "_" : "requestResponse",
  "id" : "messageId",
  ... this is the message that gets sent originally...
}

{
  "_" : "requestResponse",
  "id" : "response messageId",
  "cid" : "messageId in the request",
  ... this is the message is the reply and 
  ... is associated with the original message 
  ... ID via correlation ID "cid"
}

Client to client request response message structures. This allows for multiple targets and ensures messages are correlated correctly.

{
  "_" : "clientToClientRequestResponse",
  "id" : "messageId",
  "to" : [ 'target1', 'target2' ]
  ... this is the message that gets sent originally to the server
  ... the targets are not session IDs, but principals or groups ...
}

{
  "_" : "clientToClientRequestResponse",
  "id" : "messageId",
  "from": "source"
  ... this is the message that gets sent by the server to the other client
  ... the from value is determined on the server side and not actually
      passed by the source
}

{
  "_" : "clientToClientRequestResponse",
  "id" : "response messageId",
  "to" : [ "source" ]
  "cid" : "messageId in the request",
  ... this is the message is the reply from the receiver and 
  ... is associated with the original message 
  ... ID via correlation ID "cid"
}

Ping/pong messages. Though more heavy weight than just the Ping/Pong WebSocket messages, this prevents having to create another socket as only one message type is supported per session. This would be useful to keep the connection alive for long periods if needed.

{
  "_" : "ping",
  "id" : "ping messageId",
  "ts" : timestamp
}

{
  "_" : "ping",
  "cid" : "ping messageId",
  "ts" : timestamp"
}

Conclusion

WebSockets is a pretty new standard and it is also a low-level standard that has no application semantics. As such a contract between the UI and the server needs to be designed to ensure things work correctly. By limiting to JSON messages over text endpoints, we simplify the development of the UI, but we need to have a corresponding JavaScript and Java version of the dispatcher logic and message handling mechanisms to support web sockets.

WebSockets can replace the unsafe POST methods in the REST API and prevents polling for new data or waiting for a POST operation to complete. However, WebSockets cannot replace the GET methods as it does not support caching which will help reduce the network utilization for your application.

The contract above was designed primarily to simplify development on both sides of the fence rather than being speedy or secure by using a binary protocol. Security is delegated to TLS by using the “wss://” scheme.


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images