Motor de Qualidade de Dados

Motor de Qualidade de Dados ou MQD é a ferramenta de código aberto que avalia a qualidade dos dados que são compartilhados entre os participantes do Open Finance, assegurando assim a integridade das informações.

A Sensedia disponibiliza ferramentas para facilitar a integração entre a Sensedia API Platform, Events Hub e MQD, permitindo que os dados sejam processados de forma eficiente.

O diagrama ilustra essa integração:

Fluxo de integração entre MQD

O diagrama apresenta um fluxo de integração do Open Finance, no qual a Sensedia API Platform atua como publicadora de APIs elegíveis ao MQD — como contas, cartões e empréstimos.

Os eventos gerados por essas APIs são publicados de forma assíncrona no Sensedia Events Hub, que os consome, aplica políticas, classifica e os encaminha, por meio da MQD Subscriber API, ao proxy da Instituição Financeira.

Esse processo garante a entrega eficiente, segura e controlada dos dados.

Confira abaixo o passo a passo para realizar a integração:

Etapa 1: Configurando o Events Hub

Context

  1. Crie um contexto, como mostra a imagem a seguir:

Tela de criação do contexto do MQD

Confira mais informações sobre a configuração de contexts no Events Hub.

Handler

  1. Crie um handler, por exemplo: MQD Handler.

  2. Na etapa Topics:

    1. Adicione os tópicos do cliente: accounts, consents, creditCardAccounts, etc. Você deve configurar um tópico para cada API de dados elegível para o MQD.

      Configuração do tópico do MQD

    2. Habilite o contexto em cada tópico clicando na lupa.

      Cada tópico cria uma URL de publicação, que deverá estar configurada no interceptor Custom JS das APIs de dados.

      Veja o exemplo de uma URL criado pelo Events Hub:

      Exemplo de URL do tópico do MQD

  3. Na etapa Policy:

    1. Crie uma política de IP Filtering Validation, que é específica para os IPs de saída da Sensedia API Platform.

      Para consultar os IPs da Sensedia API Platform, acesse o Gerenciador de Infraestrutura:

    2. Preencha os campos das configurações de entrega (delivery settings):

      • Quantidade de retentativas,

      • Códigos para retentativas automáticas: 500, 502, 503, 504,408 e

      • Request timeout.

Após cadastradas, as informações devem aparecer assim:

Política de IP Filtering Validation

Confira mais informações sobre a configuração de handlers no Events Hub.

Subscriber

  1. Crie um subscriber para o MQD, que será a API MQD subscriber.

    MQD Subscriber cadastrado

  2. Na etapa Security:

    1. Valide a chave e crie um token estático para o subscriber (opcional).

  3. Na etapa Topics:

    1. Selecione o MQD Handler e depois selecione os tópicos do cliente. Habilite a opção Publish.

    2. Preencha o campo Subscriber URL com o endpoint da API MQD subscriber.

    3. Adicione o código de status 200 no campo correspondente.

Configuração do subscriber do MQD

Se a API estiver inativa no momento do cadastro, o status do subscriber aparecerá na cor cinza, mas isso não significa que estará inativa.
Confira mais informações sobre a configuração de subscribers no Events Hub.

Etapa 2: Configurando a API MQD subscriber

Configure uma API MQD subscriber que fará o proxy com o ambiente da instituição financeira. Essa API será responsável por receber os dados do Events Hub e encaminhá-los para o MQD.

Ao configurar esta API:

  1. Na etapa Resources:

    1. Adicione um recurso, por exemplo: v1/report-data.

  2. Na etapa Flows:

    1. Insira a URL que será o destino da API, que varia de acordo com a API que se quer expor.

      Configuração do destino da API

    2. Adicione os seguintes interceptores:

      • IP Filtering: com os IPs de saída do Events Hub (consulte os IPs com o time de suporte).

      • Access Token Validation: o mesmo inserido no Events Hub.

      • Custom JS: manipulará o header para o formato do MQD. Você pode customizar para o cliente removendo alguns headers que não serão necessários.

        Confira o interceptor Custom JS no fluxo da API:

        Interceptor JS na API MQD Subscriber

        Você pode configurar o interceptor JS da seguinte forma:

        const scriptName = String("MQD - Event Subscriber Interceptor ");
        const scriptVersion = String("1.0.0");
        try {
            $call.tracer.trace(">Sensedia debug => Custom javascript: Name [ "+scriptName+" ] version [ "+scriptVersion+" ]." );
            var json = JSON.parse( $call.request.getBody().getString( "utf-8" ) );
            $request.setHeader("endpointName", json.mqd.endpointName);
            $request.setHeader("serverOrgId", json.mqd.serverOrgId);
            $request.setHeader("x-fapi-interaction-id", json.mqd.fapiInteractionId);
        
            delete json['mqd'];
            $call.request.getBody().setString( $json.stringify(json), "utf-8" );
        
            $call.request.getAllHeaders().remove("x-clientname-webhooks-signature");
            $call.request.getAllHeaders().remove("access-token");
        
        
        } catch (exception) {
            $call.tracer.trace("Exception message => " + exception.message + " <= in line => " + exception.stack);
            $console.debug(">sensedia => Exception", exception);
        }
        Confira mais informações sobre a criação de APIs na Sensedia API Platform.

Etapa 3: Configurando o interceptor Custom JS no flow das APIs de dados

Na Sensedia API Platform, selecione as APIs de dados elegíveis para o MQD:

  1. Adicione o interceptor Custom JS na etapa de Flows. Havendo mais de uma API, coloque o interceptor uma vez em cada API existente.

  2. No campo Resources mantenha a opção "All".

Adição do Interceptor JS no Flow

Você pode configurar o interceptor Custom JS da seguinte forma:

const scriptName = String("MQD - Event Producer Interceptor");
const scriptVersion = String("1.1.0");

try {

    $call.tracer.trace(">Sensedia debug => Custom javascript: Name [ "+scriptName+" ] version [ "+scriptVersion+" ]." );
    $console.debug("responseStatusCode", $call.response.getStatus());

    if ($call.response.getStatus() == 200 && $call.request.getMethod() == "GET") {

        const url = String($call.request.getRequestedUrl().getPath());

        const apiName = extractApiNameByUrl(url);

        $console.debug("apiName", apiName);

        const mqdTopicUrl = String($call.environmentVariables.get('mqd-'+ apiName +'-topic-handler-url'));

        $console.debug("mqdTopicUrl", mqdTopicUrl);

        if(mqdTopicUrl) {

            let jsonResponse = JSON.parse( $call.response.getBody().getString("UTF-8") );

            jsonResponse.mqd = {};
            jsonResponse.mqd.endpointName = substituirPathPorPathId(url);
            jsonResponse.mqd.serverOrgId = $call.request.getHeader("x-organisation-id");
            jsonResponse.mqd.fapiInteractionId = $response.getHeader("x-fapi-interaction-id");

            const response =  $http.post(mqdTopicUrl, $call.response.getHeaders(), $json.stringify(jsonResponse));

            $console.debug("response", response.responseText);
            $console.debug("response status", response.getStatus());

            $call.tracer.trace("Custom javascript: Name [ "+scriptName+" ] version [ "+scriptVersion+" ].Envio para MQD Finalizado." );

        } else {
            $call.tracer.trace("Custom javascript: Name [ "+scriptName+" ] version [ "+scriptVersion+" ]. ATENCAO!  environmentVariable >'mqd-"+ apiName +"-topic-handler-url'< nao configurada! Ignorando envio para topico MQD." );
        }
    }
} catch (exception) {
    $call.tracer.trace("Exception message => " + exception.message + " <= in line => " + exception.stack);
    $console.debug(">sensedia => Exception", exception);
}


function substituirPathPorPathId(urlSearch) {

  function substituir(match, pathAnterior) {
      // Remover o último caractere "s" do path anterior
      const pathId = pathAnterior.slice(0, -1) + 'Id';
      // Retornar o pathId entre chaves
      return '/' + pathAnterior + '/{'+pathId+'}';
  }
  //regex uuid padrão para os recursos api de dados
  let regex = /\/([^\/]+)\/([a-f0-9-]+)(?=\/|$)/g;

  //se for api consents o regex sera diferente
  if(apiName === "consents"){
    regex = /\/([^\/]+)\/(urn:[a-zA-Z0-9-]+:[a-f0-9-]+)(?=\/|$)/g;
  }

  // Substituir o nome do path anterior mais "Id" pelo string dentro das chaves
  const novaUrl = urlSearch.replace(regex, substituir);

  return novaUrl.match(/open-banking(.+)/)[1];
}

function extractApiNameByUrl(url) {
  const start = "open-banking/";
  const startIndex = url.indexOf(start);

  if (startIndex === -1) {
    return "";
  }

  const endIndex = url.indexOf("/", startIndex + start.length);
  if (endIndex === -1) {
    return url.substring(startIndex + start.length);
  }

  return url.substring(startIndex + start.length, endIndex);
}

No interceptor Custom JS:

  • O método utilizado será sempre o GET, e a resposta será 200, pois o interceptor JS será acionado quando a API de dados receber uma resposta com sucesso.

  • Configure variáveis de ambiente com a URL do tópico do Events Hub. Os tópicos criam URLs de publicação para cada um deles (a quantidade de URLs varia conforme a quantidade de APIs).

Com essa configuração, os interceptores pegam as respostas elegíveis para o MQD e publicam em um tópico do Events Hub.

Confira mais informações sobre a configuração de interceptores e sobre o interceptor JS na Sensedia API Platform.
Thanks for your feedback!
EDIT

Share your suggestions with us!
Click here and then [+ Submit idea]