Service Mashup

O Service Mashup é um agregador de Service Callouts configurados como assíncronos. Por permitir a execução de chamadas externas em paralelo, o Service Mashup oferece uma vantagem em relação ao tempo de execução da chamada da API centralizadora por melhor aproveitar o tempo, como demonstrado abaixo.

Configurando o interceptor

A imagem abaixo apresenta as informações que compõem a configuração do interceptor.

mediation service mashup
  • _ Service callouts to wait_: lista todos os Service Callouts assíncronos disponíveis que não sejam do tipo Fire and Forget e que não estejam contidos em outro Service Mashup.

  • Timeout (ms): determina o tempo limite de espera em milissegundos. Caso nenhum valor seja inserido, será considerado o maior tempo limite configurado entre os Service Callouts selecionados.

  • Abort if any request fails: aborta a requisição se algum dos Service Callouts selecionados falhar. Caracteriza-se uma falha quando o status code da resposta é diferente do esperado.

Funcionamento

Para mostrar o funcionamento do Service Mashup, vamos considerar o seguinte caso:

Uma organização, a LSA (Lost Souls' Alliance), irá desenvolver uma API central, a LSA Communication, que será capaz de enviar, via POST, uma mesma mensagem (ou comando) para pessoas de dentro e de fora da organização. Essa API será registrada sob o domínio lsa.org.mx.

A mensagem, enviada como um JSON no body da chamada, será:

{
  "message": "Join or Die! Viva la revolución!",
  "author": "Salvador Limones"
}

O caso da comunicação interna foi tratado no funcionamento do Internal API Call. O caso da externa, no funcionamento do Service Callout. Agora vamos combinar essas duas comunicações em uma única chamada.

As imagens a seguir mostram, respectivamente, a sequência dos interceptores no fluxo da API e as configurações utilizadas no interceptor Service Mashup, que aguarda as respostas dos dois interceptors de Service Callout para continuar o fluxo:

mediation service mashup flow
mediation service mashup config

As configurações utilizadas para o interceptor Internal API Call são as mesmas descritas no seu funcionamento. As utilizadas para os dois interceptors de Service Callout também são as mesmas descritas no seu funcionamento, com a diferença de que o campo Asynchronous foi marcado e, por isso, passa a ser necessário o uso do Service Mashup.

Diferentemente do caso em que os dois interceptors de Service Callout foram configurados para atuar de forma síncrona, agora ambos são executados em paralelo. Para aproveitar o tempo de espera, o Internal API Call é chamado depois deles, sendo executado enquanto as outras duas chamadas estão em andamento.

Ao final da execução do Internal API Call, a resposta retornada, que é um objeto do tipo ApiResponse, é armazenada nas variáveis de contexto. Em seguida, o Service Mashup espera as respostas retornadas pelos dois interceptors de Service Callout, que são objetos do tipo RESTResponse, e também armazena essas respostas nas variáveis de contexto. Para recuperar todas as respostas, é necessário criar um custom interceptor que acesse $call.contextVariables.get(“Variable Name”).

Abaixo está o código do custom JavaScript interceptor que será usado para capturar todas as respostas e incluir o bodies e os status na resposta final:

// Captura a resposta do Internal API Call
var respRadio = $call.contextVariables.get('radioMessages');

// Captura as respostas dos Service Callouts
var respManny = $call.contextVariables.get('mannyMessage');
var respMeche = $call.contextVariables.get('mecheMessage');

// Cria um objeto ApiResponse para essa chamada
$call.response = new com.sensedia.interceptor.externaljar.dto.ApiResponse();
$call.response.addHeader('Content-Type', 'application/json');

// Template JSON para as mensagens retornada
var respBody = JSON.parse(`
    {"radio": {"status": 0, "body": {}},
     "pigeonManny": {"status": 0, "body": {}},
     "pigeonMeche": {"status": 0, "body": {}}}
`);

// O status retornado é um Object, não um Number
var statusRadio = respRadio.getStatus();
var statusManny = respManny.getStatus();
var statusMeche = respMeche.getStatus();

// O método intValue é chamado para obter um objeto Number
respBody.radio.status = statusRadio.intValue();
respBody.pigeonManny.status = statusManny.intValue();
respBody.pigeonMeche.status = statusMeche.intValue();

// O body é inserido apenas se o status retornado for 200
// Extrai o body de um ApiResponse
if (statusRadio == 200){
    respBody.radio.body = JSON.parse(respRadio.getBody().getString("UTF-8"));
}

// Extrai o body de um RESTResponse
if (statusManny == 200){
    respBody.pigeonManny.body = JSON.parse(respManny.getResponseText());
}

if (statusMeche == 200){
    respBody.pigeonMeche.body = JSON.parse(respMeche.getResponseText());
}

// Injeta o body modificado na ApiResponse
$call.response.getBody().setString(JSON.stringify(respBody), "UTF-8");

// Define o status de retorno como 200
$call.response.setStatus(200);

Por fim, o body da resposta da chamada POST ao recurso all-messages da LSA Communication será:

{
  "radio": {
    "status": 200,
    "body": {
      "messages": [
        {
          "message": "I've already joined, Sal, a year ago. Is this just a test message?",
          "author": "Eva"
        }
      ]
    }
  },
  "pigeonManny": {
    "status": 200,
    "body": {
      "message": "I'm already dead...",
      "author": "Manuel Calavera"
    }
  },
  "pigeonMeche": {
    "status": 200,
    "body": {
      "message": "Only if it has cars, as I was given one purpose, one skill, one desire: to DRIVE!",
      "author": "Glottis"
    }
  }
}
Thanks for your feedback!
EDIT
How useful was this article to you?