OpenAPI

This article provides guidelines for performing simple request/response operations against OpenAPI endpoints. The first part discusses OpenAPI requests and the second part deals with OpenAPI responses, including the possible HTTP response codes being returned.

The article uses Fiddler for taking snapshots of of actual request/responses, but any other web debugging tools such as curl or postman can also be used.

To follow the examples in the article, you will need an OpenAPI access token. When building a real application you would have followed one of the authorization flow described under OAuth Based Authentication Flows for getting the access token.

Structure of an OpenAPI request (headers, body, authorization)

The complete list of available OpenAPI endpoints is provided in the reference documentation. Using this information we decide to send a request to get the balance for the client associated with the current login user. A snapshot of the most simple request & response is given below. (Please note here that we are sending Authorization header with the access token, this is required since using this access token only OpenAPI Service will give access to publicly exposed endpoints):

Headers

HTTP headers are the core part of HTTP requests and responses, and they carry information about the client browser, the requested page, the server and more. Some important HTTP headers in the context of OpenAPI Services are described below:

Accept-Encoding

Consumers of OpenAPI services can indicate through this header in the HTTP request what encoding schemes they support. OpenAPI only supports gzip & deflate compression. If a client sends an Accept-Encoding for an unsupported compression like "sdch" then it ignores the compression header and sends an uncompressed response.

The example shown below sends a GET request for fetching the details of current logged in user and specified Accept-Encoding as deflate , as can be seen in the below response snapshot the request sent by the server is encoded.

 


Authorization

Authorization header should be set with a valid Bearer token for accessing OpenAPI services, More info on this can be found here. Snapshot of a sample request is shown below:


Content-Type 

Consumers need to specify this header for POST,PUT,PATCH requests as this indicates what type of data is getting posted back to the server. In the snapshot shown below since JSON object (request body) is getting posted back , you have to specify Content-Type header as application/json. Content-Type headers are also used for specifying batch requests, More information can be found here.

Supported Verbs

The reference documentation list all the supported Http verbs for a particular resource, so prior to sending the request please refer reference documentation to find out whether that verb is available or not.

Verbs not allowed by firewalls and proxies

Some firewalls and proxies are known to block PUT, PATCH, and DELETE requests and return HTTP status code 405 to the client before the request reaches the server. To work around that, OpenAPI supports HTTP method overrides so that a POST request can be used to simulate a PUT, PATCH, or DELETE request.

To simulate a PUT request, the client should create a POST request with the following extra header:

    X-HTTP-Method-Override: PUT

instructing the OpenAPI service to interpret the request as a PUT. The same pattern applies to PATCH and DELETE.

There is a live sample on diagnostics and method overrides (with source).

CORS(Cross Origin Resource Sharing)

All OpenAPI Services have CORS enabled for all origins, headers and methods.

Query Options

OpenAPI provides query options like top, skip, next etc on based on OData protocol on some endpoints (To find out which endpoints support query option and what options it support please refer to OpenAPI reference documentation). Let's take examples on how to use querying option while querying OpenAPI Services:

Using top & skip option

Example : getting top 3 exchanges after skipping 2 records (request and Response snapshot shown below), don't worry about the _next link shown in the response it is described in detail in the response section of the article.

There is a live sample on query options (with source).

Using fieldGroups

FieldGroups provide a option to send a list or a single fieldGroup column which is desired in the response. Let's explore this with the examples given below:

example 1: project positions data based on DisplayAndFormat fieldGroup, request/response snapshot given below:

As can be seen in the below snapshots we are sending filter 'fieldGroups=DisplayAndFormat' in the request and getting the fieldGroup DisplayAndFormat in the response.

example 2 : lets send multiple fieldGroup DisplayAndFormat,PositionView in the fieldGroups filter and check the response, request/response snapshot given below.As can be seen in the below snapshots we are sending filter 'fieldGroups=DisplayAndFormat,PositionView' in the request and getting both the fieldGroup data in the response.


OpenAPI Request Examples 

GET 

Request/Response snapshot of a sample Get request to the Vas service is given below. This request will bring the price alerts data for current logged in user

POST

Post request for creating a new pricealert definition is shown in the snapshot below.

PUT

Put request for updating the IsRecurring field of price alert definition with id = 532997. (PS: In this request we are sending the full price alert request object in the body)

PATCH

Patch request for changing the culture from "en-GB" to "en-US" is shown below.
(Please note that we are not passing the full object as was the case with the PUT example above - hence PATCH is considered to be more efficient than PUT):

DELETE

Delete request for removing a price alert definition with id= 532875 is shown below:

Structure of an OpenAPI Response

We need to refer to reference documentation for finding out the OpenAPI Response structure. The Reference documentation has detailed information about the response structure as well as samples to get you started. Let's say you want to get the exchange from OpenAPI Service, then go to the reference documentation  and click exchanges under resources section (on the left hand side) as is shown below:

The above snapshot shows two endpoints exposed on this resource. The first is to get all the exchanges and second is to get a specific exchange. Let's say you are interested in getting all the exchanges and find out more about this endpoint as to what the request parameters are going to be and what's the response structure going to be, Click Quick view to see the response structure as shown below:

Versioning Policy

Please refer Versioning and Obsolescence Policy page to know about the versioning policy of OpenAPI.

”Null fields are generally ‘left out’”

Response from OpenAPI Services generally ignores null fields and those do not get serialized. For example, in the above snapshot of Exchanges, if the service did not have a value for the "Name" field, then there would not be a "Name" property in the response object.

When writing a client application always take into consideration that some fields may not be returned in the response object. Your application should be able to handle this gracefully.

__next... /Data...

while using OpenAPI Query options(like $top,$skip etc) as is specified above in OpenAPI Request section, OpenAPI response sends response packed into two fields

a.  Data: this will give data based on the request and filtering options specified in the request.

b. _next: will give the link for accessing the next page of items in the feed, So if we send a request https://developer.saxobank.com/sim/openapi/ref/v1/exchanges?$top=3&$skip=2 (for getting top 3 items after skipping first 2) next link will be https://developer.saxobank.com/sim/openapi/ref/v1/exchanges?$top=3&$skip=5 ( since next page will be top 3 items after skipping 5 items).


Response Codes

OpenAPI end points may return any of the following HTTP response codes:

Response codeDomain Error CodeDescription
200
Ok, for GET and Options requests.
201
Created, for POST requests. Additional data is returned in the response.
204
Succes, No content for DELETE, PATCH and PUT requests.
400YesBad Request, See domain error code for additional information.
401
Unauthorized.
403
Forbidden
404
Not Found
429
Too many requests. Returned if request quotas are exceeded. 
500
Internal service error.
503
Service Unavailable.


Responses with response code 400 return additional information in the response body in the form of an error structure as outlined below:

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
  
{
  "ErrorCode":"InvalidModelState",  
  "Message":"One or more properties of the request are invalid!",
  "ModelState":
   {
     "$skip":["Invalid $skip query parameter value: 2s"]
   },
}

ErrorCode and Message are always returned, where as ModelState is only returned for a few specific error codes.

If included, the ModelState, is an object containing key value pairs of fields with invalid contents along with an array of error texts relevant for the individual field.


Generic and domain specific error codes

Error codes are either generic or domain specific. The generic ones are listed below., They may be returned from any endpoint.

Error codeInclude model stateDescription
InvalidRequestNoDefault error code returned when it cannot be determined which part of the request is malformed.
InvalidRequestHeaderYes

Error code returned when one or more of the request headers are invalid.
Used when the specific request header cannot be determined.

InvalidMediaTypeHeaderYesError code returned when the Accept or Content-Type headers contains an invalid media type or is malformed.
InvalidAcceptLanguageHeaderYesError code returned when the Accept-Language header contains an invalid language or is malformed.
InvalidQueryParametersYesError code returned from query end points, when query parameters are invalid.
InvalidModelStateYesError code returned when model state is invalid.
TypeConversionErrorYesError code returned when type-conversion failed (TypeConverter's and ModelBinder's).
SubscriptionLimitExceededNoError code returned when more than the maximum allowed number of subscriptions for a specified type, is exceeded
RateLimitExceededNoError code returned when a throttling policy quota has been exceeded.
FeatureNotEnabledNoError code returned when an Open Api feature has been disabled via Front Office.
InternalTimeoutNoError code returned when a timeout occurs internally in the application.
UnsupportedSubscriptionFormatYesError code returned when a subscription format that isn't supported by the publisher is requested.
RequestNotAllowedNoError code returned if a request is not allowed.
DomainValidationErrorYesError code returned when domain validation fails.


Documentation of Error Codes in the reference documentation

The Response Codes section of the reference documentation provides an overview of the possible response codes for a specific operation.

For reasons of brevity the list does not include the full list of generic error codes.

With respect to the domains specific errors, we only list the most frequently occurring error codes as well those, where it may make sense for the receiving application to make a decision. There may be more error codes returned than those listed, but for the client application, the only sensible action is really to log and/or display such errors.

HTTP Expect: 100 Continue NOT supported

A few client libraries may implement the transmission of an HTTP Expect: 100-Continue request header. The expectation is that the server will respond with a 100-Continue, and the client will subsequently send the actual request body. This two-step process is intended to save bandwidth between the client and server if the payload to be transmitted is very large (such as a file upload). In such situations the server could - for example - check for invalid authentication and reject the initial 100-Continue request, thus avoiding the subsequent file upload and thereby save bandwidth.

In our experience the same two-step process has been difficult to get to work reliable, especially as we support clients world wide, who connect to us through a multitude of network gateways and proxies. We also find that the actual bandwidth savings for the majority of API requests are limited, since most requests are quite small.

We therefore strongly recommend against using the Expect:100-Continue header, and expect you to make sure your client library does not rely on this mechanism.


See also the live sample on error handling (with source).