Overview of asynchronous calls

Synchronous calls

By default, calls made to Cloud API are synchronous. The caller application submits the request and waits for a response. This is depicted in the following diagram.



  1. The caller application sends a request to Cloud API. In the diagram, the request is a POST for a resource named someResource. The request has a set of request headers and may have a payload.
  2. Cloud API processes the request synchronously.
  3. Assuming the request is successful, Cloud API provides the response. The response also has a set of response headers and may have a payload.

Asynchronous calls

For some calls, it can be problematic to wait for a synchronous response. For example, quoting a large commercial policy may take several minutes, and the API Gateway may time out before the quote can be completed and returned to the caller.

To address these situations, you can execute a Cloud API call asynchronously. Broadly speaking, there are three phases to an asynchronous call. In practice, this could occur with fewer than or more than three calls.

Submitting the call

For an asynchronous call, the request is almost identical to a synchronous call. The only difference is that the request object includes an additional Prefer request header indicating the desire for an asynchronous response.

If the call is well-formed, Cloud API provides an initial response.

  • The status of the response is "202 Accepted", indicating that the request has been accepted.
  • The response body is empty.
  • The response includes a GW-Async-Location header. The header's value is a path for an Async API endpoint that the caller can use to retrieve information about the original request.

This is depicted in the following diagram.



  1. The caller application sends a request to Cloud API. The request object includes a request header indicating to process the call asynchronously.
  2. Cloud API accepts the request. But it does not immediately process it.
  3. Cloud API provides a response. The response includes a header with an Async API /requests path that can be used to retrieve:
    1. Information about the initial request.
    2. The response to the initial request, once it is available.

Determining when the call has been processed

After the call has been submitted, the caller application uses the Async API /requests path from the initial response to retrieve information about the original request. This path takes the form of /async/v1/requests/<asyncRequestId>.

The response to the /requests call always includes the following information:

  • The requestMethod and requestPath of the original request
  • The status of the original request, which can be set to:
    • Accepted - The request is still waiting to be processed.
    • InProgress - The request is being processed, but processing is not yet complete.
    • Complete - The request has been processed.
  • The startTime of the original request

If the original request has been completed, then the following information is also included:

  • The completionTime of the original request
  • The responseStatus and responseHeaders
  • If the response's format is application/json, then the response itself is included in the responseBodyJson field

Example response for a call that has not been completed

The following is a portion of the /requests response for a asynchronous call that has not yet been completed.

{
    "data": {
        "attributes": {
            "requestMethod": "POST",
            "requestPath": "/admin/v1/users",
            "responseStatus": 202,
            "startTime": "2022-07-12T16:53:12.365Z",
            "status": {
                "code": "Accepted",
                "name": "Accepted"
            }
        }
    }
}
Java

Example response for a call that is complete

The following is a portion of the /requests response for a asynchronous call that is complete.

{
    "data": {
        "attributes": {
            "completionTime": "2022-07-12T16:53:16.073Z",
            "requestMethod": "POST",
            "requestPath": "/admin/v1/users",
            "responseBodyJson": {
                "data": {
                    "attributes": {
                        ...
                        "username": "asyncUser99",
                        "vacationStatus": {
                            "code": "atwork",
                            "name": "At work"
                        }
                    },
                    "checksum": "321dff263827cbbd772c26676398d8ae",
                    "links": {
                    ...
                    }
                }
            },
            "responseHeaders": {
                "Cache-Control": [
                    "must-revalidate",
                    "post-check=0",
                    "pre-check=0",
                    "max-age=0",
                    "no-store",
                    "no-cache"
                ],
                "Content-Type": [
                    "application/json;charset=UTF-8"
                ],
                "GW-Checksum": [
                    "321dff263827cbbd772c26676398d8ae"
                ],
                "Location": [
                    "/admin/v1/users/pc:ScaA3kB5cImBkuh7bxjNn"
                ],
                "X-Correlation-ID": [
                    "d516344d-5769-4964-adb7-79eaca41e4a2"
                ],
                ...
            },
            "responseStatus": 201,
            "startTime": "2022-07-12T16:53:12.365Z",
            "status": {
                "code": "Complete",
                "name": "Complete"
            }
        }
        ...
    }
}
Java

Polling until the original request is complete

The caller application can poll Cloud API periodically until it receives a response whose status is Complete. This is depicted in the following diagram.



  1. The caller application sends a GET /async/v1/requests/{asyncRequestId} request to Cloud API. The path comes from the header of the initial response.
  2. The Cloud API response includes information about the original request. If the status is Accepted or In Progress, the caller application must re-submit the GET after an appropriate interval.

When the response includes a status of Complete, the caller can retrieve the response to the original request. There are multiple ways that it can be retrieved.

Retrieving the response using /requests/{asyncRequestId}

The /requests endpoint returns an AsyncRequest resource. This resource includes a responseBodyJson attribute. If the original request has a status of Complete, and if the response's type is application/json, then this attribute contains the response payload for the initial request.

This is depicted in the following diagram.



4. The caller application sends a GET /async/v1/requests/{asyncRequestId} request to Cloud API. The acyncRequestId comes from the header of the initial response.

5. The Cloud API response includes information about the original request. When the status is Complete, the response includes the original request's response if the response type is application/json.

Note that the GET /async/v1/requests/{asyncRequestId} request could return a response of Complete the first time it is submitted or on a subsequent try.

Retrieving the response from /requests/{asyncRequestId}/response

There is also a /requests/{asyncRequestId}/response endpoint. For completed requests, this endpoint returns the original response as if the call had been executed synchronously. This endpoint is useful when:

  • The response type is something other than application/json, and therefore is not included in the GET /async/v1/requests/{asyncRequestId} response.
  • The caller application wants the work with the response as it would normally appear, as opposed to having to extract it from within the responseBodyJson attribute of a larger data envelope.

This is depicted in the following diagram.



6. The caller application sends a GET /async/v1/requests/{asyncRequestId}/response request to Cloud API.

7. The Cloud API response includes the original response, as if the request had been executed synchronously.

When the original call is complete, the response to GET /async/v1/requests/{asyncRequestId}/response has the same status code, response body (if any), and response headers as if the caller were getting a synchronous response to the original request.

For example, if the original request was a POST that created a new activity, the GET request to retrieve the response might return a 201 response code and have a Location header. If the original request failed because of a validation error, the GET request to retrieve the response might have a 400 status code and a response body with details of the errors.