Como funcionam os retornos de chamada assíncronos de serviços externos
As operações assíncronas de serviços externos são descritas em uma especificação compatível com OpenAPI 3.x com uma operação de retorno de chamada. As operações assíncronas são registradas pelo sistema como um tipo especial de ação invocável que permite tempos de resposta mais longos. Por outro lado, as operações síncronas dos serviços externos atingem o tempo limite após 120 segundos. Com operações assíncronas, você usa o Apex para definir o retorno de chamada e o tempo limite da resposta assíncrona atrasada.
Edições obrigatórias
| Disponível em: Lightning Experience |
| Disponível em: Edições Enterprise, Performance, Unlimited e Developer |
Exemplo de especificação de API com operação de retorno de chamada
Este exemplo de especificação de API apresenta uma operação de retorno de chamada dentro de um processo de solicitação de hipoteca para a empresa fictícia "Acme Mortgages". As definições relacionadas ao retorno de chamada estão em negrito. Voltaremos a esse exemplo em outros tópicos desta seção.
{
"openapi": "3.0.0",
"servers": [{
"url": "/"
}],
"info": {
"version": "1.0",
"title": "Acme Mortgages",
"description": "Acme Mortgages"
},
"paths": {
"/applications": {
"post": {
"operationId": "SubmitApplication",
"description": "Submit a new mortgage application",
"parameters": [{
"name": "callbackUrlForErrorCases",
"in": "query",
"schema": {
"type": "string"
}
}],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"applicant": {
"$ref": "#/components/schemas/Contact"
},
"callbackUrlForOutcomes": {
"type": "object",
"properties": {
"approved": {
"type": "string"
},
"rejected": {
"type": "string"
}
}
}
}
}
}
}
},
"responses": {
"201": {
"description": "Mortgage loan application submission initial response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"applicationNumber": {
"type": "string"
}
}
}
}
}
}
},
"callbacks": {
"applicationOutcomeApproved": {
"$ref": "#/components/callbacks/ApplicationApproved"
},
"applicationOutcomeRejected": {
"$ref": "#/components/callbacks/ApplicationRejected"
},
"applicationError": {
"{$request.query.callbackUrlForErrorCases}": {
"post": {
"parameters": [{
"in": "header",
"name": "applicationNumber",
"schema": {
"type": "string"
}
}],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MortgageApplicationError"
}
}
}
},
"responses": {
"200": {
"description": "Mortgage application callback error accepted"
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"MortgageApplication": {
"required": [
"applicationNumber",
"status"
],
"properties": {
"applicationNumber": {
"type": "string"
},
"status": {
"description": "One of pending, approved, rejected",
"type": "string"
},
"approvedAmount": {
"type": "number"
}
}
},
"Contact": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
},
"address": {
"type": "string"
}
}
},
"MortgageApplicationError": {
"properties": {
"errorMessage": {
"type": "string"
},
"applicationNumber": {
"type": "string"
}
}
}
},
"callbacks": {
"ApplicationApproved": {
"{$request.body#/callbackUrlForOutcomes/approved}": {
"post": {
"description": "Application has been approved.",
"operationId": "approvedCallback",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MortgageApplication"
}
}
}
},
"responses": {
"200": {
"description": "Approved application callback result has been retrieved successfully."
}
}
}
}
},
"ApplicationRejected": {
"{$request.body#/callbackUrlForOutcomes/rejected}": {
"post": {
"description": "Application is rejected",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MortgageApplicationError"
}
}
}
},
"responses": {
"200": {
"description": "Rejected application callback result has been retrieved successfully."
}
}
}
}
}
}
}
}
Exemplo de interface do Apex com operações assíncronas
Quando registrado, o serviço externo AcmeMortgages é prestado automaticamente no Apex pelos serviços externos. A interface do Apex para AcmeMortgages aparece na página Classes do Apex em Configuração, conforme mostrado aqui. O conteúdo adicional que define as operações assíncronas está em negrito. Não são mostrados os objetos dinâmicos do Apex que representam tipos de dados de objetos de esquema que são iguais às ações invocáveis.
Cada retorno de chamada pertence à sua operação assíncrona pai. Um URL de retorno de chamada exclusivo e somente leitura é determinado pelo Salesforce (na primeira chamada).
global class AcmeMortgages {
// Acme Mortgages SubmitApplication asynchronous operation
global SubmitApplication_Response SubmitApplication(
SubmitApplication_Request input,
SubmitApplication_Callback callback,
DateTime callbackTimeout
) {...}
global class SubmitApplication_Request {
global AcmeMortgages_SubmitApplication_IN_body body {get; set;}
// [REQUEST] Callback URL for asynchronous operation: callbackUrlForErrorCases
global String callbackUrlForErrorCases {get;}
}
// Synchronous response - here getting the application docket number
global class SubmitApplication_Response {
global Integer responseCode {get; set;}
global AcmeMortgages_SubmitApplication_OUT_201 Code201 {get; set;}
// Get invocation ID for this asynchronous response to query callback status
global String invocationId {get;}
}
global class SubmitApplication_ResponseException {
global Integer responseCode {get; set;}
global String defaultResponse {get; set;}
}
// Asynchronous response callback handler for SubmitApplication.
// Each method corresponds to the schema's declared callback key.
// Default implementations throws an exception alerting that a non-implemented callback was called.
global virtual class SubmitApplication_Callback {
global virtual void applicationOutcomeApproved(
List<SubmitApplication_applicationOutcomeApproved_Callback> callbacks) {
throw new SubmitApplication_ResponseException(404,
'Callback not handled: applicationOutcomeApproved');
}
global virtual void applicationOutcomeRejected(List<SubmitApplication_applicationOutcomeRejected_Callback> callbacks) {...}
global virtual void applicationError(List<SubmitApplication_applicationError_Callback> callbacks) {...}
}
// Asynchronous callback response payloads for callback applicationOutcomeApproved
global class SubmitApplication_applicationOutcomeApproved_Callback {
global SubmitApplication_Request request {get; set;}
global DateTime submitTime {get; set;}
global DateTime callbackTimeout {get; set;}
global CallbackStatus callbackStatus {get; set;}
global SubmitApplication_applicationOutcomeApproved_CallbackResponse response {get; set;}
}
global class SubmitApplication_applicationOutcomeApproved_CallbackResponse {
global AcmeMortgages_MortgageApplication body {get; set;}
}
global class SubmitApplication_applicationOutcomeRejected_Callback {...}
global class SubmitApplication_applicationOutcomeRejected_CallbackResponse {...}
global class SubmitApplication_applicationError_Callback {...}
global class SubmitApplication_applicationError_CallbackResponse {...}
}
Exemplo de fluxo de dados de retorno de chamada
Neste exemplo, um desenvolvedor do Salesforce Apex usa serviços externos para registrar a especificação da API da solicitação de hipoteca de um banco. A especificação contém operações de retorno de chamada, pois são esperados atrasos de até um dia entre o envio e a aceitação do envio.
O desenvolvedor do Apex grava um cliente Apex com um manipulador de retorno de chamada. O cliente Apex especifica que depois que o Salesforce receber a resposta atrasada do sistema externo, ele usará a lista resultante de nomes e outras informações da solicitação de hipoteca para criar contatos automaticamente.
Este diagrama de sequência demonstra o fluxo de dados funcional entre o Apex code do desenvolvedor ("Cliente/Manipulador Apex" no diagrama), o Salesforce e o ponto de extremidade da API da solicitação de hipoteca do banco ("Serviço da Web externo" no diagrama).
Existem duas respostas do serviço da Web externo. A primeira é síncrona e é a resposta ACK inicial típica. A segunda é a resposta assíncrona e atrasada (tecnicamente uma solicitação) que inclui a carga útil do resultado no corpo da solicitação.
Primeiro, o desenvolvedor do Apex envia uma solicitação HTTP (uma chamada) ao servidor do banco (um serviço externo) com o cliente Apex.
O serviço da Web externo envia imediatamente uma resposta HTTP confirmando o recebimento da solicitação. Esta primeira confirmação expira após 120 segundos. O desenvolvedor do Salesforce monitora o status da solicitação usando a página Operações em segundo plano ou o log de depuração do Apex.
O banco inicia seu processo interno para ingerir a solicitação de hipoteca, aprová-la ou negá-la e, eventualmente, preparar um resultado final (no diagrama como "Atraso assíncrono").
Dentro de um dia, o banco envia o resultado concluído de volta ao desenvolvedor do Apex como uma solicitação HTTP. Os dados do resultado (valor aprovado, status e assim por diante) da solicitação de hipoteca estão contidos no corpo da solicitação. O Salesforce recebe o resultado e o processa de acordo com a implementação do manipulador de retorno de chamada do Apex.
O Salesforce retorna uma confirmação de resposta HTTP ao serviço da Web externo. Se o Salesforce processar os dados com sucesso (neste caso, para criar contatos), ele enviará uma resposta ao serviço da Web externo com um código de status 200 e uma mensagem de sucesso.
Se o Salesforce encontrar um erro, ele enviará um código de status 404, 408 ou 500 para o serviço da Web externo com uma mensagem de erro genérica. O desenvolvedor do Apex pode ver mais detalhes da mensagem de erro usando a página Operações em segundo plano ou com o log de depuração do Apex.

