Making Requests

Since the ICWS API follows the Representational State Transfer (REST) design pattern, requests to the API are HTTP requests with JSON data as the message body of the request. This page describes how to format these requests.

This topic contains the following sections:

General Requests

The ICWS provides both an HTTP and HTTPS endpoints for requests. For security reasons, HTTPS is recommended (see Encrypted Communication Over HTTPS for more information on recommended practices). The following TCP ports are used:

  • HTTP - 8018
  • HTTPS - 8019

HTTP requests consist of the following parts:

  • HTTP method
  • URI
  • Header parameters
  • Optional message body

The HTTP method, header parameters, and the structure of the JSON for the message body are all defined in the documentation for each API. The URI is constructed by the client application using the resource path defined in the documentation and any query string parameters the client application is sending. Most of the resource paths defined in the API contain substitution points, or template substitutions. These template sections are replaced with data values when generating the URI. See Resource URIs for more information.

The following is an example of the raw HTTP request for getting the version information from the server named "icwsServer" using HTTPS.

GET /icws/connection/features HTTP/1.1
Host: icwsServer:8019


Back to top

Session Requests

Most ICWS APIs require a session to be established before making requests to those APIs. These APIs require 3 important pieces of information to be successful:

  • The session ID which will be used as a template parameter in the URI.
  • The CSRF token which will be sent in the request as the ININ-ICWS-CSRF-Token header parameter.
  • The HTTP Cookie value.

When establishing a connection, the session ID and CSRF token will be provided both in the response body and in the response header. The HTTP Cookie will be sent according to RFC 6265. For web browser based applications, the HTTP Cookie will not be accessible from JavaScript to protect against Session Hijacking and Cookie Theft.

Note

For web browser applications that are using Cross-Origin Resource Sharing (CORS) to access the ICWS API using the XMLHttpRequest, the withCredentials property must be set to true in order for the HTTP cookie to be sent with these requests.

If a request is made to one of these resources that require a session and the session is either invalid or one of these pieces of data is missing, the request will be rejected with a 401 - Unauthorized response. Details about why the request was rejected will be included in the response.

The following example shows setting a users status using the PUT /icws/{sessionId}/status/user-statuses/{userId} API. This example assumes the following:

  • An HTTPS connection to "icwsServer".
  • The session ID is "1234".
  • The CSRF token is "abcd".
  • The user's ID is "user1".
  • The status ID is "At Lunch".
PUT /icws/1234/status/user-statuses/user1 HTTP/1.1
Host: icwsServer:8019
Content-Length: 23
ININ-ICWS-CSRF-Token: abcd
Cookie: icws_1234=dba2f460-58ce-47ba-85b3-1bcf4e1e526e

{"statusId":"At Lunch"}


Enabling Response Compression

The ICWS API will utilize HTTP compression for responses if the response size is large enough to warrant compression and if the request indicates that the client supports compression. When clients can support HTTP compression, clients should specify the Accept-Encoding with the content codings separated by commas (according to the HTTP 1.1 specification). For web browser based applications, the browser is responsible for setting this.

Accept-Encoding: gzip,deflate

The API supports gzip and deflate as defined in RFC 2616 Section 3.5.

Note

The ICWS API adheres to the HTTP specification for the definition of deflate. The deflate content coding as defined by RFC 2616 is the zlib format (RFC 1950) using the deflate compression algorithm defined in RFC 1951. Because of the confusion between the two "deflate" formats, some clients will not use the correct zlib compression. For this reason, no "qvalues" for Accept-Encoding are defined, or if the values for gzip and deflate are equal, ICWS will prefer gzip as recommended by RFC 2616.

JavaScript Example

The following provides a simple example of sending a request from JavaScript. The example includes constants for the parts of an ICWS request URI. It also includes an example helper method for sending requests to those APIs that require a session.

var ICWS_URI_SCHEME = 'http://';
var ICWS_URI_PORT = '8018';
var ICWS_URI_PATH = '/icws';
var ICWS_REQUEST_TIMEOUT_MS = 60000;

/**
 * Sends a request to an existing ICWS session.
 * @param {String} server The server name where ICWS is available.
 * @param {String} sessionId The ICWS session ID.
 * @param {String} icwsCsrfToken The ICWS CSRF token.
 * @param {String} method The HTTP method of the request. (ex: GET, POST, PUT, DELETE)
 * @param {String} requestPath The uri fragment for the request.  The part after the sessionId template parameter.  (ex: /messaging/messages)
 * @param {Object|String} payload The payload to send with the request, as a string or JSON.
 * @param {resultCallback} resultCallback The callback to invoke with the response details.  If there is no existing session, the callback will be invoked with a 0 status and empty object.
 */
function sendRequest(server, sessionId, icwsCsrfToken, method, requestPath, payload, resultCallback) {
    var xmlHttp, uri;

    // Use an XHR to make the web service request.
    xmlHttp = new XMLHttpRequest();

    // Once it's available, process the request response.
    xmlHttp.onreadystatechange = function() {
        if (xmlHttp.readyState === 4) {
            sendRequestCompleted(xmlHttp, sessionId, resultCallback);
        }
    };

    // Create the base URI, using the ICWS port, with the specified server and session ID.
    uri = ICWS_URI_SCHEME + server + ':' + ICWS_URI_PORT + ICWS_URI_PATH;
    // Once a session has been established, subsequent requests for that session require its session ID.
    // (This is not provided when establishing the initial connection.)
    uri += '/' + sessionId;
    
    // Add the specific ICWS request to the URI being built.
    if (requestPath.substring(0, 1) !== '/') {
        uri += '/';
    }
    uri += requestPath;

    // Open the HTTP connection.
    xmlHttp.open(method, uri, true);

    // Specify that credentials should be used for the request, in order to work correctly with CORS.
    xmlHttp.withCredentials = true;

    xmlHttp.timeout = ICWS_REQUEST_TIMEOUT_MS;

    // If the ICWS request is for an existing session, then the session's CSRF token must be set as
    // a header parameter.
    // (This is not provided when establishing the initial connection.)
    xmlHttp.setRequestHeader('ININ-ICWS-CSRF-Token', icwsCsrfToken);

    // The ICWS content-type must be specified.
    xmlHttp.setRequestHeader('Content-type', ICWS_MEDIA_TYPE + ';' + ICWS_MEDIA_CHARSET);

    // Allow JSON to be provided as an option, then convert it to a string.
    if (typeof payload !== 'string' && !(payload instanceof String)) {
        payload = JSON.stringify(payload);
    }
    
    // Send the request.
    xmlHttp.send(payload);
}

/**
 * The callback for receiving the result from {@link sendRequest} or {@link sendSessionlessRequest}.
 * @callback resultCallback
 * @param {Number} status The HTTP status code of the response.
 * @param {Object} jsonResponse The JSON response payload.
 * @param {String} sessionId The ICWS session ID.
 */

/**
 * Process the response to an ICWS request.
 * @param {Object} xmlHttp The XMLHttpRequest instance for the request.
 * @param {String} sessionId The session ID that was used, if any.
 * @param {resultCallback} resultCallback The callback to invoke with the result.
 */
function sendRequestCompleted(xmlHttp, sessionId, resultCallback) {
    var status, responseText, response;
    
    status = xmlHttp.status;
    
    // Handle 401 failures as server disconnects.
    if (status === 401) {
        connectionStateChanged({
                                newConnectionState: 'down',
                                reason: 'No connection to server.'
                               });
    }

    // Process the response body.
    responseText = xmlHttp.responseText;
    if (responseText) {
        try {
            response = JSON.parse(responseText);
        } catch(e) {
            /* If the JSON cannot be parsed, use an empty object for response. */
            response = {};
        }
    } else {
        response = {};
    }
    
    // Signal the request result to the caller's callback.
    resultCallback(status, response, sessionId);
}

Back to top