OpenAPI

Introduction

Several endpoints in the API rely on the fact that the same server (in the server farm) is hit for all requests against that service. The requests have to be sticky against one server. 

In order to achieve this, the load balancer will issue a set of cookies (depending on the actual endpoints requested), that the client needs to send back to the server on every new request.

An API client must follow the rules below:

  • Each service must be called initially to get cookies for stickiness in a non-concurrent fashion
  • Every cookie returned must be sent back on every subsequent request

Note that the initial request must be completed before making any other requests.If the client initiates several concurrent requests against the API, multiple cookies can be returned and stickiness is not guaranteed.

The initial request should be done against the isalive endpoint that is available within each service:

Service endpointsIsalive endpoint
/openapi/chart/*GET /openapi/chart/isalive
/openapi/cm/*GET /openapi/cm/isalive
/openapi/cs/*GET /openapi/cs/isalive
/openapi/port/*GET /openapi/port/isalive
/openapi/root/*GET /openapi/root/isalive

/openapi/streaming/*

GET /openapi/streaming/isalive
/openapi/trade/*GET /openapi/trade/isalive
/openapi/vas/*GET /openapi/vas/isalive

The list shows the current services that require stickiness, but it is recommended to use this approach for every service. 

The isalive endpoint can be requested without an access token and the response will be textual (the actual response body can be ignored, only the cookies are needed).

Client Types

For browser clients the protocol is almost fully provided out of the box, since browsers will (typically) send all cookies associated to the domain with every request.

The only requirement left is then to ensure that the first call against the isalive endpoint is completed before any other requests to that service

For thick clients (e.g. C#) all cookies needs to be handled specifically.

Example

Requesting isalive endpoint for trade service:

Getting cookie in response:

Streaming Connections

If the client relies on establishing streaming connections against the streaming service (/openapi/streaming/connection) and the client is a non-browser client, then the above protocol ensures that a connection can be established every time.

The streaming connections currently relies on the SignalR client library which establishes the actual connection to the server. 

This happens behind the scenes by calling a negotiate endpoint and then a connect endpoint. Both endpoints must hit the same server for the connection to be established successfully (hence the request to connect must include any cookies returned on the negotiate response).

Example

Getting stickiness cookie before establishing connection (using SignalR .NET client):

Cookie handling in .NET client
	Connection connection;
	try
	{
		//Initially to get cookies for stickiness
		var isAlive = new Uri(ConfigurationManager.AppSettings["StickinessUrl"]);
		var handler = new HttpClientHandler { CookieContainer = new CookieContainer() };
		using (var client = new HttpClient(handler))
		{
			client.GetAsync(isAlive);
		}
		// Establish connection
		var transport = new AutoTransport(new DefaultHttpClient());
		var queryStringData = new Dictionary<string, string>
		{
			{ "authorization",HttpUtility.UrlEncode(accessToken) },
			{ "context", HttpUtility.UrlEncode(contextId) }
		};
		//Persist cookie for later subscription
		_cookieContainer = handler.CookieContainer;
		connection = new Connection(ConfigurationManager.AppSettings["StreamingConnectionUrl"], queryStringData)
		{
			CookieContainer = handler.CookieContainer
		};
		connection.TransportConnectTimeout = TimeSpan.FromSeconds(60);
		var writer = new StreamWriter("Log.txt");
		connection.TraceLevel = TraceLevels.All;
		connection.TraceWriter = writer;
		connection.Reconnecting += Connection_Reconnecting; ;
		// Set up event listeners
		connection.StateChanged += Connection_StateChanged;
		connection.Received += Connection_Received;
		connection.Error += Connection_Error;
		connection.Closed += Connection_Closed;
		connection.Start(transport);
	}
	catch (Exception ex)
	{
		Console.WriteLine("\nUnable to make Connection. Error: " + ex);
	}

 A successful connection seen from Fiddler:

Cookies in negotiate response:

Cookies in the connect request: