Use the Continuation
class in Apex to make a long-running request to an external Web service. Process the response in a callback method.
Continuations use the @AuraEnabled
annotation as @AuraEnabled(continuation=true)
.
Before you can call an external service, you must add the remote site to a list of authorized remote sites in the Salesforce user interface (New Remote Site).
If the callout specifies a named credential as the endpoint, you don’t need to configure remote site settings. In your code, specify the named credential URL instead of the service URL.
To make a long-running callout, define an Apex method that returns a Continuation object.
@AuraEnabled(continuation=true cacheable=true)
public static Object startRequest() {
// Create continuation. Argument is timeout in seconds.
Continuation con = new Continuation(40);
// more to come here
return con;
}
Set the callback method to be invoked after the callout completes in the continuationMethod
property of the Continuation object. In this example, the callback method is processResponse
. The callback method must be in the same Apex class: con.continuationMethod='processResponse';
Set the endpoint for a callout by adding an HttpRequest
object to the Continuation
object. A single Continuation object can contain a maximum of 3 callouts.
HttpRequest req = new HttpRequest();
req.setMethod('GET');
req.setEndpoint(LONG_RUNNING_SERVICE_URL);
con.addHttpRequest(req);
Set data to pass to the callback method in the state
property of the Continuation
object. The state property has an Object type so you can pass in any data type that’s supported in Apex: con.state='Hello, World!';
Code the logic in the Apex callback. When all the callouts set in the Continuation
object have completed, the Apex callback method, processResponse
, is invoked. The callback method has two parameters that you can access: public static Object processResponse(List<String> labels, Object state)
labels
—A list of labels, one for each request in the continuation. These labels are automatically created.state
—The state that you set in the state
property in your Continuation
object.Get the response for each request in the continuation. For example: HttpResponse response = Continuation.getResponse(labels[0]);
public with sharing class SampleContinuationClass {
// Callout endpoint as a named credential URL
// or, as shown here, as the long-running service URL
private static final String LONG_RUNNING_SERVICE_URL =
'<insert your callout URL here>';
// Action method
@AuraEnabled(continuation=true cacheable=true)
public static Object startRequest() {
// Create continuation. Argument is timeout in seconds.
Continuation con = new Continuation(40);
// Set callback method
con.continuationMethod='processResponse';
// Set state
con.state='Hello, World!';
// Create callout request
HttpRequest req = new HttpRequest();
req.setMethod('GET');
req.setEndpoint(LONG_RUNNING_SERVICE_URL);
// Add callout request to continuation
con.addHttpRequest(req);
// Return the continuation
return con;
}
// Callback method
@AuraEnabled(cacheable=true)
public static Object processResponse(List<String> labels, Object state) {
// Get the response by using the unique label
HttpResponse response = Continuation.getResponse(labels[0]);
// Set the result variable
String result = response.getBody();
return result;
}
}
<aside> 🔥 An asynchronous callout made with a continuation doesn’t count toward the Apex limit of 10 synchronous requests that last longer than 5 seconds.
</aside>
@AuraEnabled
Annotations for continuationsContinuations use the @AuraEnabled
annotation for Apex code. Here are the rules for usage.
@AuraEnabled(continuation=true)
**An Apex controller method that returns a continuation must be annotated with @AuraEnabled(continuation=true)
.@AuraEnabled(continuation=true cacheable=true)
**To cache the result of a continuation action, set cacheable=true
on the annotation for the Apex callback.<!-- continuationCmp.html -->
<template>
<lightning-button label="Call Continuation" onclick={callContinuation}>
</lightning-button>
<div>
@wire(startRequest) result: {formattedWireResult}
</div>
<div>
Imperative result: {formattedImperativeResult}
</div>
</template>
import { LightningElement, track, wire } from 'lwc';
import startRequest from '@salesforce/apexContinuation/SampleContinuationClass.startRequest';
export default class ContinuationComponent extends LightningElement {
@track imperativeContinuation = {};
// Using wire service
@wire(startRequest)
wiredContinuation;
get formattedWireResult() {
return JSON.stringify(this.wiredContinuation);
}
// Imperative Call
callContinuation() {
startRequest()
.then(result => {
this.imperativeContinuation = result;
})
.catch(error => {
this.imperativeContinuation = error;
}
);
}
get formattedImperativeResult() {
return JSON.stringify(this.imperativeContinuation);
}
}