Connecting to the Streaming API

Overview

The streaming API is built on GraphQL over WebSocket protocol. This protocol defines that a given stream (identified by application key, URL, and chainCode) can only be consumed by one application/process/thread. Therefore, do not use multithreading when connecting to the Streaming API.

Prerequisites

Streaming Business Events from OPERA Cloud requires a minimum version of OPERA Cloud 22.3.0.1.

Before connecting to consume Business Events from the WebSocket, verify the following prerequisites are met:
  • Onboard to OHIP by following the steps in Getting Started for Partners.

  • Create an application by following the steps in Registering an Application.

  • Take a note of the application key.

    Note:

    It is important that you write down the application key.

    You can only connect to the streaming API from one application at a time using the same application key. Using a single application key to simultaneously access the API from multiple applications will stop the streaming service.

  • Add an environment from which to consume events. For more information, see Environments (Gateways and Credentials). Take note of the following:
    • ClientId and ClientSecret — These are needed to obtain the oAuth token.

    • Gateway URL

  • Check that the environment is streaming enabled. It will have a label "Streaming Enabled" if this is the case.

  • Set up the template of events. For more information, see Working with Events and Creating a Template of Events for an Application.

  • Subscribe to consume the events from an environment. For more information, see Working with Events and Subscribing to Events.

If the environment is the partner sandbox or an environment owned by your organization, the request to consume events is automatically approved. If not, environment owners (usually customers) must approve the request to consume events from their environment. To do this, following the process in Working with Events and Approving Events.

Once the request to consume events is approved, the event is listed as "Approved" on the Developer Portal.

GraphQL

The streaming API uses GraphQL subscriptions delivered via WebSocket. To learn more about this technology, read our blog post.

WebSocket Authorization

Access to the streaming API is protected by oAuth and an application key. The application key comes from the application you created in Registering an Application.

To obtain the oAuth token, follow the processes described in Using the Oracle Hospitality APIs and in Authenticating to Oracle Hospitality Property APIs. For an example of the oAuth token, visit the Get OAuth Token page on the Postman API Platform site at https://www.postman.com/hospitalityapis/workspace/oracle-hospitality-apis/request/15729853-58d0804e-b607-4c37-bf2f-0656c254573c.

Information required to call the WebSocket

To connect to the streaming API, the following pieces of information are required:

Note:

If the URL listed on the Environment panel in the Developer Portal is "https://www.oracle.com," the URL for the streaming API should be "wss://www.oracle.com/subscriptions." The change from "https" to "wss" is required for connection via WebSocket.

Browsing the OHIP Schema

The Documentation Explorer is located on the right-side of the screen.

  1. Click the Subscription link to browse the schema for creating the subscription.

    The Subscription object requires you to specify a "NewEventInput" object containing the chainCode and the offset.

  2. Click NewEventInput to view the data type and limits on these fields.

  3. Click the Subscription arrow to go back to the definition of the Subscription object.

    Returned in the response to this subscription is the type called "EventHeader."

  4. Click the EventHeader to view details of the fields that can be returned (if included in the query).

  5. Click any of these fields to see the object definition, data types, and limits on the fields.

    One of the response fields is the "detail" array, which includes fields such as newValue, oldValue, and elementName (that is, the name of the data element that changed).

  6. Compose your GraphQL query using the left-side of the screen, which includes intellisense to speed up the completion of the query.

  7. Click Start to open the WebSocket connection. Any events meeting the subscription configured in the Developer Portal are sent and appear on the right-side of the screen, but include only those fields specified in the subscription query on the left-side of the screen.

    The right-side of the screen only shows the latest event. Since many events will be sent at once, use the developer tools in the browser to view the full list of sent events.

  8. Click Stop to disconnect the WebSocket.

Note:

When the Auth Token expires, the connection must be severed and then reestablished with a fresh Auth Token every hour.

Connecting to the Streaming API via GraphiQL

To better visualize the streaming API, a playground application is available that uses a tool called GraphiQL. The GraphiQL tool is often utilized with GraphQL APIs. It is available as a standalone web page from our public Github repository.

Note:

The GraphiQL page has a limitation that a single browser can only stream events from one application at a time. GraphiQL cannot be open in multiple tabs or windows consuming events from different applications.

Connecting via GraphiQL

  1. Enter the URL (see the ‘Information required to call the WebSocket’ section in WebSocket Authorization).

  2. Enter an Auth Token as described in WebSocket Authorization.

  3. Enter the API key as it is listed in the Developer Portal.

    This is the not the sha256 hash of the API key.

  4. Click the Start button.

    • This stores the values on your machine not on the server. Only you can view these saved values.

    • This populates the Socket Key.

    The connection is open if you see the three boxes appear below the Start button.

    • The left-hand box holds the subscription request. By default, this includes a getHelp query and an example subscription.

    • The middle box holds the latest response.

    • The right-hand box is a navigable representation of the GraphQL schema showing the fields you can include in the subscription.

    Since the middle box holds only the latest response, you should open developer tools in your browser, usually the Network tab, so that all events sent on the stream are visible.

  5. Click the play button to open the WebSocket connection. By default, this returns the getHelp query with useful links to this guide.

  6. Comment out the getHelp query and remove the comments in front of the example subscription.

    Use CTRL + / to comment or uncomment.

  7. Optionally, add elements from the GraphQL schema into the subscription. Press CTRL + space to list fields from the schema.

  8. Click the play button to open the WebSocket connection. All events that occurred after the subscription was approved are now sent with the latest event shown in the middle pane. The WebSocket connection remains open until you click the stop button. This means if any of the events chosen in the Developer Portal occur in the subscribed hotel(s), the events are immediately sent on the streaming API and appear in the middle pane.

Note:

When the Auth Token expires, the connection must be severed by clicking the stop button and then reestablished with a fresh Auth Token every hour. As noted in the Broken Connections topic, OHIP sends any events that occurred between stopping and restarting the WebSocket connection.

Viewing Historic Events

To view historic events, use your web browser's developer tools. For example:

  1. In Mozilla Firefox, press F12 to open developer tools.

  2. Click the Network tab.

  3. Click WS to show only WebSocket requests.

  4. After clicking the play button, click the last web service request sent.

  5. When the details appear, click the Response tab.

You will see all the sent business events. You can view each business event inside the developer tools by clicking it, or you can copy it by right clicking the business event in the list of responses and clicking Copy Message.

Connecting to the Streaming API with Postman

Postman can be accessed online or from the Postman API Client https://www.postman.com/product/api-client/. You must be signed in to a Postman workspace to use WebSocket APIs in Postman.

Note:

While it is possible to support WebSocket via Postman, it is not yet possible to save WebSocket requests in Postman except while signed in to a Postman workspace.

You can connect to a given stream from only one application and thread at a time. Ensure the stream (identified by the application key, URL, and chainCode) is not being used by any other applications.

Postman does not support the sending of a ping, so any postman connection closes after 5 minutes.

Consuming Events in Postman

To consume events in Postman, follow one of the two options below:

Option A
  1. Fork this Postman collection and fork this Postman environment file.

  2. Use this oAuth API example to first obtain an oAuth token.

Option B
  1. Select New and then select WebSocket Request.

  2. Enter the URL in the following format: wss://www.oracle.com/subscriptions (as described in ‘Information required to call the WebSocket’).

  3. Add the query parameter (see the ‘Query Parameters’ section).

  4. Add the headers (see the ‘Headers’ section).

  5. Send the Authentication message.

  6. Send the subscription message within 10 seconds of the Authentication message.

  7. View the events returned.

Query Parameters

The GraphQL subscription resource has one mandatory query parameter named "key." The value is a sha256 hash of the application key obtained from Registering an Application.

If LINUX environments are running, echo-n ABC-123 | sha256sum (where "ABC-123" is the application key) will return the required hash. In Microsoft Windows environments, use a code snippet or download GitBash or Windows Subsystem for Linux. To run this command, visit the Install WSL page on the Microsoft website at https://docs.microsoft.com/en-us/windows/wsl/install. Alternatively, you can use an online sha256 hash generator.

Note:

Ensure only lowercase hashes are used.

To add this to Postman:
  1. In Postman, click the Params tab

  2. In the first column, enter the value "key."

  3. In the second column, enter the value of the 256 hash that was calculated above.

Headers

The Oracle Hospitality streaming API uses the GraphQL-WS protcol passed in headers:
  1. In Postman, click the Headers tab.

  2. In the first column. enter the value "Sec-WebSocket-Protocol."

  3. In the second column, enter the value "graphql-transport-ws."

ID

All messages, except the "ping" message (see Keeping the Stream Open), require you to specify an ID in the request payload.

The ID should be a GUID to avoid collision with other consumers.

The same ID value must be used throughout a stream's life.

Authentication Message

Send the authentication "Connection Initialization" message before sending the subscription message.

  1. In Postman, click the area marked New Message and enter the following:

{
  "id": "<GUID>"
  "type": "connection_init",
  "payload": {
      "Authorization": "Bearer <OAUTH TOKEN>
      "x-app-key": "<APPLICATION KEY>"
   }
}
Where: Once the authentication message is successfully received, the following "Connection Acknowledged" message is returned:
{
   "type": "connection_ack",
   "payload": {
         "applicationName":"<APPLICATION NAME>"
   }
}

Where APPLICATION NAME is the name of the application that corresponds to the application key. This validates that the correct application is being used.

In Postman, the connection will show as "CONNECTED."

Subscription Message

  1. Send the subscription message within the next 10 seconds now that the connection is authenticated and connected.

  2. In Postman, overwrite the Authentication message request body with the following request body:

    {
       "id": "<GUID>",
       "type": "subscribe",   
       "payload": {       
           "variables": {},        
           "extensions": {},       
           "operationName": null,        
           "query": "subscription { newEvent(input: { chainCode: \"OHIPCN\" }) { metadata { offset } moduleName eventName detail { oldValue newValue elementName } } }"   
        }
    }

    The "query" is the GraphQL query formatted against the OHIP schema. It contains the fields to be returned along with business events.

    For the full schema of what can be sent in the Subscribe request body, consult the Documentation navigator in GraphiQL.

  3. For the chainCode, specify the "tenant" entered when creating the integration user. Refer to step 1 in Authenticating to Oracle Hospitality Property APIs. This is also prefixed on your integration username.

  4. Click the Send button.

Viewing the Events Returned

In Postman, messages from the server begin with a down arrow.

To see the JSON response payload:
  1. Click to expand the message.

The payload includes only those elements from the "query" specified in the Subscription message.

When multiple events are pending subscription, each event is returned in sequence.

Keeping the Stream Open

To keep the connection open, you must send a "ping" request at least every 15 seconds on the WebSocket (see the below JSON example). 

{"type":"ping"}

Note:

You are not charged for this "ping" request.

An example implementation is listed on GitHub in the Recipes section under ‘Client usage with ping/pong timeout and latency metrics.’

The server also sends pings to the client.  It is important that as soon as it receives a "ping" from the server the client return a "pong" message to this request from the client as documented in the Protocol:

{"type":"pong"}

Updating Authentication

The streaming API is secured by an oAuth token whose life is limited to one hour (sixty minutes). To continue receiving events, you must keep the stream open by doing the following:
  1. Close the WebSocket (see Disconnecting the WebSocket for more information).
  2. Request a new oAuth token from the oAuth API.
  3. Reopen the websocket and specify the new "access_token" received from the oAuth API.

Disconnecting the WebSocket

WebSockets are designed to stay open. When planning to disconnect from a WebSocket (refer to the Broken Connections topic), be aware of the following:
  • Events will queue up while disconnected, but only 7 days of events are retained. This can be a large volume of events, so before reconnecting, verify your consuming architecture can support the volume.

  • Send the "Complete" message (see the example below).

Sending the Complete Message

Before disconnecting, ensure you send the below Complete message (see the protocol for more information):
{
    "id": "<GUID>",
    "type": "complete"
}
You must send the Complete message to connect to the stream (identified by the application key, URL, and chainCode). Failure to send the Complete message will make it impossible to connect to the stream. If a subscribe message is sent to a stream that has not yet received a complete message, a 4409 error will occur.

Reconnecting after Complete

Ensure there is a minimum of 500 ms between sending the "Complete" message to close a WebSocket connection and sending the next "Subscribe" message to reopen a WebSocket connection.

Streaming Best Practices

Note:

You must connect to the WebSocket at least once every 24 hours. If not, then you must send the optional "offset" input parameter together with the value of the last offset you received.

Ensure there is a minimum of 500 ms between sending the "complete" message to close one WebSocket connection and the next "subscribe" message to reopen a WebSocket connection.

The Streaming API is not throttled. As events are produced, they are immediately sent out. Potentially, this means many events will be pushed at the same time and create a backpressure.

To cope with this potential backpressure, it is essential the consuming architecture can scale, for example, by buffering before writing to back-end systems. If the backpressure exceeds the ability of the consuming architecture to scale, you can disconnect the WebSocket and then restart it later once more capacity is available in the consuming architecture. Any events that occurred since the WebSocket disconnect will be sent as soon as you reconnect.

While no option is currently available to clear the backlog of events, the "latest" parameter allows you to skip to the latest Business Event in the stream and continue processing from there.

For more information on anti-patterns and best practices on the streaming API, refer to the Anti-Patterns topic.

Streaming Troubleshooting

If you are experiencing issues consuming the Streaming API, check the following:

Environment

  • Verify the OPERA environment from which you wish to stream events is listed on the Environments tab of the developer portal.

  • Verify the OPERA environment shows as Streaming Enabled on the Environments tab of the developer portal.

  • Verify you have valid credentials to obtain the oAuth token (see API Troubleshooting for more information).

  • Verify the oAuth token is current. They expire after 60 minutes.  If not, request a new oAuth token.Check the oAuth token is current. They expire after 60 minutes.  If not, request a new oAuth token.

Configuration

Ensure your application streaming configuration is both requested and approved (see Working with Events in the Developer Portal for more information).

Postman

Postman cannot send "ping" on an open WebSocket, so the connection will automatically close. When it closes, you must resend the "init" message and then resend the "subscribe" message.

It is not yet possible to save WebSocket requests in Postman, except when signed in to a Postman workspace.

GraphiQL

If you receive errors from GraphiQL, ensure you have it opened only once. It cannot support streaming events from different applications in different tabs (see Connecting to the Streaming API via GraphiQL for more information).

Not Receiving the Expected Data

If you are not receiving the pieces of data you expected, check the subscribe message to ensure it includes the expected field.

The hotelId will always be null for chain-level entities, such as profiles, which tend to be shared across all hotels in the chain.

Verify this page lists the expected data values for the event(s) to which you are subscribed (see the ‘Business Events - Activity’ heading under the Configuring Business Events topic in the OPERA Cloud User Guide).

Receiving Unexpected Events

Keep in mind that a single action, such as checking a guest in, can trigger multiple business event notifications because that single action modifies multiple resources.

For integration partners developing against the sandbox, keep in mind that the actions taken by other partners in the sandbox will generate events.

Not Receiving Expected Events

If you are not receiving all new reservations, it is possible the customer has an external CRS setup. Request the customer to set up a "publisher" on your external system (the external system code is displayed on the Application, Events, Subscribed tab in the developer portal) following this process (see the ‘Managing External System Publishers’ heading under the Configuring External Systems topic in the OPERA Cloud User Guide).

If you are not receiving any events, it is possible you have not connected for greater than 24 hours. In this case, stop the WebSocket and reopen it, specifying in the subscribe message the last offset you received.

Verify you are not unexpectedly using the "hotelId" filter in the subscribe message.

Getting Overwhelmed with Events

The Streaming API sends events as soon as they are available, so it is important that consuming architecture can scale and potentially buffer events to avoid choking database connections (see Streaming Best Practices for more information).

Other Errors

See the Errors topic for suggested resolutions to common errors.

If the "init" request is failing, ensure you send it within 5 seconds of the HTTP upgrade request.

If the connection keep closing:
  • Ensure you send "ping" every 15 seconds (see Keeping the Stream Open for more information).

  • Postman cannot send "ping," so the connection will automatically close.

  • Wait at least 500ms between closing and re-opening the WebSocket, or you will receive 4409 errors (see Disconnecting the WebSocket for more information).

  • Ensure that only one process/thread/user is connected to a given stream (identified by application key, URL, and chainCode) at any one time.

  • Ensure you have connected only one WebSocket per application: Connecting more than one WebSocket with the same application key will result in 4409 errors.

  • If the socket closes with a 4401 error, obtain a new oAuth token before reconnecting. The socket will automatically close every one hour when the oAuth token expires (see Keeping the Stream Open for more information).

  • Receiving a 4403 error:
    • Verify the chain to which you are subscribing in the subscribe message matches the chain for the integration user that was used in the oAuth request.

  • Receiving a 4409 error:

    • Ensure only one client or process consumes events from a given gateway using a given application key and chain code.

    • Ensure you send the Complete message before disconnecting from the WebSocket.

    • Ensure you send the ping message to keep the stream open (see Keeping the Stream Open for more information).

    • Reconnect after 5 minutes.

Confused About Implementation?

We adhere to the GraphQL over WebSocket protocol, so ensure your implementation meets this protocol.

An example implementation is available on this GitHub page.

It is suggested that you create a second application using the GraphiQL tool to better distinguish between implementation and configuration issues.