Custom JavaScript: Exemplos
Aqui, você pode ver exemplos de scripts para adicionar aos seus interceptores personalizados JavaScript.
Abortar requisições para recursos antigos
Este script pode ser usado para barrar o acesso a uma URL antiga, mas com uma mensagem mais amigável para desenvolvedores que ainda estejam usando essa URL.
Coloque a URL desejada no campo URL Pattern
e use os seguintes scripts:
Esse trecho indicará que o gateway não irá aceitar o request. Deve ser executado no fluxo de requisição.
$call.decision.setAccept(false);
Adicione em seguida o trecho que modificará a resposta, setando o status 404 e um corpo fixo.
Deve ser executado no ponto after-response
.
$call.response.setStatus(404);
$call.response.getBody().setString(
'{"message": "Este resource foi removido. Use /orders/status no lugar."}', "utf-8"
);
Adicionar header a partir do extraInfo de um token
Este script pode ser usado para adicionar um header a uma requisição.
O conteúdo desse header será obtido do extraInfo
de um dos tokens usados na requisição.
No exemplo abaixo, um header X-Customer-Id
será adicionado, contendo o ID do cliente representado pelo access token atual.
var access_token = $call.accessToken;
if (access_token) {
$request.setHeader("X-Customer-Id", access_token.extraInfo.get('customerId'));
}
Para testar o script acima, faça a requisição abaixo.
Este teste assume que existe um access token com código mycustomer
, contendo um extraInfo
chamado customerId
e com valor 123
.
curl -H "access_token: mycustomer" http://10.0.0.5:8080/example
Entre os headers recebidos pelo backend, deve existir:
...
"headers": {
...
"X-Customer-Id": "123"
...
}
Observe que no script acima assumimos que sempre existirá um access token. Se o script for executado no fluxo de requisição e o access token for obrigatório (como tipicamente é), então essa premissa é sensata, pois o gateway barraria o acesso se o token não fosse informado.
Se o token for opcional, no entanto, devemos lidar com o caso de ele não ser informado. O exemplo abaixo insere um header indicando que a app está sendo testada em ambiente de sandbox, mas pode ser que a app não seja informada.
var app_token = $call.app;
if (app_token && app_token.extraInfo.get('isSandbox') == "true") {
$request.setHeader("X-Is-Sandbox", "true");
}
Para testar o script acima, faça o request abaixo.
Este teste assume que existe uma app com código myapp
, contendo um extraInfo
de nome isSandbox
e valor true
.
curl -H "client_id: myapp" http://10.0.0.5:8080/example
Entre os headers recebidos pelo backend, deve existir:
...
"headers": {
...
"X-Is-Sandbox": "true"
...
}
Adicionar header fixo
Este script pode ser usado para adicionar um header a uma requisição.
No exemplo abaixo, estamos inserindo um header Content-Type: application/json
apenas se a requisição não tiver um Content-Type
.
if ( $call.request.getHeader( "Content-Type" ) == null )
$call.request.setHeader( "Content-Type", "application/json" );
Adicionar query params de paginação quando ausentes
Neste exemplo, temos um backend que sempre espera receber parâmetros de paginação na query-string das chamadas (ex: /products?page=5&page_size=10
).
Mas queremos que requisições sem esses parâmetros sejam executadas com valores-padrão sensatos (page=0
e page_size=10
, por exemplo).
Observe também que não iremos adicionar parâmetros se eles já existirem.
if ( ! $request.getQueryParam("page") )
$request.setQueryParam("page", "0");
if ( ! $request.getQueryParam("page_size") )
$request.setQueryParam("page_size", "20");
Também queremos nos proteger contra chamadas que especifiquem parâmetros de paginação fora do aceitável, então continuamos o script acima com:
var page = parseInt($request.getQueryParam("page"));
if (page > 100 || page < 0)
$request.setQueryParam("page", 0);
var pageSize = parseInt($request.getQueryParam("page_size"));
if (pageSize > 100 || pageSize < 1)
$request.setQueryParam("page_size", 20);
Alterar a rota de acordo com o extraInfo de um token
Neste exemplo, a rota a ser seguida é diferente dependendo de uma flag no extraInfo
de um access token, indicando se ele é um legado (devendo ser encaminhado para http://legacy.mycompany.com
) ou não (devendo ser encaminhado para http://api.mycompany.com
).
Observe que pelo menos uma rota precisa estar definida. Caso contrário, o gateway irá considerar a requisição como mal-formada e irá retornar HTTP 404 antes de termos a chance de executar este script.
var access_token = $call.accessToken;
if (access_token && access_token.extraInfo.get('isLegacy') == "true") {
var newDest = 'http://legacy.backend.com';
$call.setDestinationUri(new Packages.java.net.URI(newDest));
$call.request.setHeader('Host', $call.destinationUri.getHost());
}
Para testar, crie uma app com o extraInfo
isLegacy = true
e faça uma requisição.
Depois, modifique a flag (ou crie outra app com isLegacy = false
) e faça uma nova requisição.
curl -H 'client_id: mynewapp' http://10.0.0.5:8080/example/api
curl -H 'client_id: mylegacyapp' http://10.0.0.5:8080/example/api
A primeira requisição, feita por uma app moderna, deve atingir http://example.demo.sensedia.com/example/api
.
A segunda requisição, feita por uma app legada, deve atingir http://legacy.backend.com
.
Converter corpo da resposta de JSON para XML
Neste exemplo, temos uma API no backend que retorna uma resposta JSON, e queremos montar um XML equivalente para devolver para o cliente.
O interceptor default JSON to XML pode ser utilizado para esta transformação. |
Executaremos o seguinte script no fluxo de resposta:
// Faz o parse do json recebido
var json = JSON.parse( $call.response.getBody().getString("utf-8") );
// Esta função converte um objeto para uma representação XML.
// Observe que ela não lida com sub-objetos nem coleções.
var toXml = function(jsonNode, rootName) {
// Usaremos o JDOM para montar o XML.
var result = new Packages.org.jdom.Element(rootName);
// Cada propriedade no jsonNode vira um sub-elemento no elemento acima.
for ( var key in jsonNode ) {
var value = jsonNode[key];
var element = new Packages.org.jdom.Element(key);
element.setText(value.toString());
result.addContent(element);
};
return result;
};
// Dispara o filtro no node raiz.
// Observe que estamos assumindo que o resultado é sempre um objeto e não uma lista.
var root = toXml( json, "root" );
// Serializa e seta no response
$call.response.getBody().setString( $jdom.stringify(root), "utf-8" );
Com um pouco mais de código, podemos fazer a função toXml()
lidar com listas de objetos, objetos compostos, etc.
Converter corpo da requisição de text para JSON
Este exemplo recebe um request no formato properties (um subset do formato YAML), como exibido abaixo:
invoice : 34843
customer: Benjamin
date : 2001-01-23
tax : 251.42
total : 4443.52
Queremos converter para um objeto JSON como o abaixo:
{
"invoice": 34843,
"customer": "Benjamin",
"date": "2001-01-23",
"tax": 251.42,
"total": 4443.52
}
Para isso, vamos executar o seguinte script no fluxo de requisição:
// Sempre especificamos o encoding.
// Neste caso estamos forçando utf-8,
// mas poderíamos consultar headers da requisição para descobrir isto.
var text = $call.request.getBody().getString("utf-8");
var newBody = "{";
text.split("\n").forEach(function(line) {
var pieces = line.split(":");
if (pieces[0].trim() == 'invoice' || pieces[0].trim() == 'tax' || pieces[0].trim() == 'total')
newBody += '"' + pieces[0].trim() + '"' + ':' + pieces[1].trim() + ',';
else
newBody += '"' + pieces[0].trim() + '"' + ':' + '"' + pieces[1].trim() + '",';
});
if ( newBody.length > 1 )
newBody = newBody.substring(0,newBody.length -1);
newBody += '}';
// Seta o novo corpo da requisição
$call.request.getBody().setString(newBody, "utf-8");
$call.request.setHeader("Content-Type", "application/json");
O interceptor default TXT to JSON pode ser utilizado para esta transformação. |
Criar um XML e adicioná-lo à resposta
Este script cria um XML utilizando JDOM e o adiciona à resposta.
var result = new org.jdom.Element("sensedia");
result.setText("xml");
$call.response.getBody().setString( $jdom.stringify(result), "utf-8" );
Descompactar o corpo da requisição com gzip
O código abaixo descompacta o corpo da requisição compactado com gzip.
Essa transformação deve ser aplicada no fluxo de requisição.
var decompressed = $gzip.decompress( $call.request.getBody().getBytes() );
var json = JSON.parse(decompressed);
json.test = 2;
$call.request.getBody().setString( JSON.stringify(json) , "utf-8" );
Executar outros serviços durante a transformação
A melhor forma de executar outros serviços é usar o interceptor Service Mashup. Porém, também é possível executá-los com interceptores personalizados.
Neste exemplo, realizaremos uma orquestração de serviços. A chamada de serviços pode ser utilizada em qualquer fluxo (requisição/resposta).
Exemplos:
if($http.get("http://sensedia.com").status == 200)
{
$http.get("http://sensedia.com/blog")
}
if($http.get("http://sensedia.com").status == 200)
{
var header = { 'Content-Type' : 'application/json' }
var body = { "hello": "world" }
$http.post("http://www.mocky.io/v2/551018c499386d1a0b53b04b", header, body)
}
Interromper o fluxo de execução na requisição e retornar a resposta para o cliente
Neste exemplo, um novo atributo no objeto $call
foi incluído, possibilitando interromper o fluxo da requisição em qualquer ponto e retornando a resposta para o cliente.
Para interromper a execução da requisição e retornar a resposta sem ir ao backend e sem executar o fluxo de resposta, basta executar:
$call.stopFlow = true;
$call.decision.setAccept( false );
$call.response = new com.sensedia.interceptor.externaljar.dto.ApiResponse();
$call.response.setStatus( 400 );
Para interromper a execução da requisição ou resposta, fazendo a requisição para o backend, basta executar:
$call.stopFlow = true;
Manipulação de billing
Este é um script para manipular billing.
$call.billing = true;
$call.billingValue = 5.85;
$billing.execute($call);
Observações:
-
O atributo
billingValue
trabalha com precisão Double, por isso, é possível que tenha possíveis arredondamentos ou perdas de precisão em casas decimais. -
Para controle e bloqueio de consumo, deve ser selecionada a opção Abort request if fail no editor do interceptor, além de incluir o tratamento de exceção no próprio custom interceptor ou no Raise Exception do fluxo.
Manipulação de body
Renomear um campo no corpo da requisição
var json = JSON.parse( $call.request.getBody().getString( "utf-8" ) );
if ( json['fatherId'] != null ) {
json['parentId'] = json['fatherId'];
delete json['fatherId'];
}
$call.request.getBody().setString( JSON.stringify(json), "utf-8" );
Converter corpo da resposta de JSON para XML
var json = JSON.parse($call.response.getBody().getString("utf-8"));
var toXml = function (jsonNode, rootName) {
var result = new Packages.org.jdom.Element(rootName);
for (var key in jsonNode) {
var value = jsonNode[key];
if (value) {
var element = new Packages.org.jdom.Element(key);
element.setText(value.toString());
result.addContent(element);
}
};
return result;
};
var root = toXml(json, "root");
$call.response.getBody().setString($jdom.stringify(root), "utf-8");
Converter corpo da requisição de texto para JSON
var text = $call.request.getBody().getString("utf-8");
var newBody = "{";
text.split("\n").forEach(function(line) {
var pieces = line.split(":");
if (pieces[0].trim() == 'invoice' || pieces[0].trim() == 'tax' || pieces[0].trim() == 'total')
newBody += '"' + pieces[0].trim() + '"' + ':' + pieces[1].trim() + ',';
else
newBody += '"' + pieces[0].trim() + '"' + ':' + '"' + pieces[1].trim() + '",';
});
if ( newBody.length
>
1 )
newBody = newBody.substring(0,newBody.length -1);
newBody += '}';
$call.request.getBody().setString(newBody, "utf-8");
$call.request.setHeader("Content-Type", "application/json");
Obter um parâmetro da URI e colocar no corpo da requisição
if ( $call.request.getQueryParam("userId") != null )
{
var json = JSON.parse($call.request.getBody().getString("utf-8"));
json["userId"] = String($call.request.getQueryParam("userId"));
$call.request.getBody().setString(JSON.stringify(json), "utf-8");
$call.request.setHeader("Content-Type", "application/json");
}
Descompactar o corpo da requisição com gzip
var decompressed = $gzip.decompress( $call.request.getBody().getBytes() );
var json = JSON.parse(decompressed);
json.test = 2;
$call.request.getBody().setString( JSON.stringify(json) , "utf-8" );
Transformação com subelementos JSON e com JSON array
var json = JSON.parse( $call.response.getBody().getString("utf-8") );
var toXml = function(jsonNode, elementName) {
var result = new Packages.org.jdom.Element(elementName);
for ( var key in jsonNode ) {
var value = jsonNode[key];
if(value != null && value != 'null' && value != undefined){
if(value.toString().indexOf('[object Object]') == -1 ){
var element = new Packages.org.jdom.Element(key);
element.setText(value.toString());
result.addContent(element);
}else{
try{
var subElement = toXml(value, key);
result.addContent(subElement);
}catch(err){
try{
for ( var keyArray in value ) {
var valueArray = value[keyArray];
var subElementArray = toXml(valueArray, key);
result.addContent(subElementArray);
}
}catch(err){
var elementError = new Packages.org.jdom.Element(key);
elementError.setText(err);
result.addContent(elementError);
}
}
}
}
};
return result;
}
var root = toXml( json, "root" );
$call.response.getBody().setString( $jdom.stringify(root), "utf-8" );
$call.response.setHeader("Content-Type", "application/xml");
Manipulação de header
Adicionar header fixo (Content-Type)
if ( $call.request.getHeader( "Content-Type" ) == null )
$call.request.setHeader( "Content-Type", "application/json" );
Adicionar header a partir do extraInfo de um app e access token
var access_token = $call.accessToken;
if ( access_token != null )
$request.setHeader( "X-Customer-Id", access_token.extraInfo.get('customerId') );
var app = $call.app;
if ( app != null && "true" == app.extraInfo.get("isSandbox") )
$request.setHeader( "X-Is-Sandbox", "true" );
Modificar header authorization
var auth = $call.request.getHeader( "Authorization" )
if ( auth != null ) {
if ( auth.toLowerCase().indexOf( "basic" ) == 0 )
auth = auth.substring("Basic".length).trim();
var plain = $base64.atob(auth);
var withoutWhitespace = plain.trim();
var base64 = $base64.btoa(withoutWhitespace);
$call.request.setHeader( "Authorization", base64 );
}
Chamar um serviço que retorne 302 e juntar os headers da resposta com os headers do próximo serviço para retornar ao cliente
var destination = $call.destinationUri.toString();
var requestHeaders = {};
var requestHeaderskeyArray = $call.request.getAllHeaderNames().toArray();
for( var i = 0; i < requestHeaderskeyArray.length; i++ ) {
var key = requestHeaderskeyArray[i];
if ( key != 'host' && key != 'content-length' ) {
requestHeaders[key] = $call.request.getHeader(key);
}
}
$call.response = new com.sensedia.interceptor.externaljar.dto.ApiResponse();
$call.decision.setAccept( false );
var firstResponse = $http.post( destination, requestHeaders, $call.request.getBody().getString( 'UTF-8' ) );
var firstResponseHeaderskeyArray = firstResponse.getHeaders().keySet().toArray();
for( var i = 0; i < firstResponseHeaderskeyArray.length; i++ ) {
var key = firstResponseHeaderskeyArray[i];
$call.response.setHeader( key, firstResponse.getHeaders().get( key ) );
}
if ( firstResponse.getStatus() == 302 ){
destination = firstResponse.getHeaders().get( 'Location' );
var secondResponse = $http.post( destination, requestHeaders, $call.request.getBody().getString( 'UTF-8' ) );
var secondResponseHeaderskeyArray = secondResponse.getHeaders().keySet().toArray();
for( var i = 0; i < secondResponseHeaderskeyArray.length; i++ ) {
var key = secondResponseHeaderskeyArray[i];
$call.response.setHeader( key, secondResponse.getHeaders().get( key ) );
}
$call.response.setStatus( secondResponse.getStatus() );
$call.response.getBody().setString( secondResponse.responseText, 'UTF-8' );
} else {
$call.response.setStatus( firstResponse.getStatus() );
$call.response.getBody().setString( firstResponse.responseText, 'UTF-8' );
}
Remover um atributo de header da requisição antes de encaminhar a chamada para o backend
try{
$call.request.getAllHeaders().remove("seu-header");
} catch(e){
$call.tracer.trace(e);
}
Manipulação de extraInfo
Validar URL contra extraInfo
Neste exemplo, vamos criar um script a ser executado apenas nas URLs do tipo /projects/*
.
Este padrão deve ser colocado no campo URL Pattern
.
Esta API retorna a lista de membros de um certo projeto.
Porém, cada access token só pode ver alguns projetos.
A lista de projetos permitidos é armazenada no extraInfo
do token, no momento do cadastro:
access_token.extraInfo = new Packages.java.util.HashMap();
access_token.extraInfo.put('allowedProjects', 'marketing-site,product-support');
Se o token acima for usado para chamar /projects/marketing-site
ou /projects/product-support
, o acesso deve ser permitido, mas se for usado para chamar /projects/ui-redesign
, queremos que seja barrado com erro "HTTP 403 Forbidden" e uma mensagem explicativa.
Como precisamos do token já extraído e validado, vamos colocar o script para rodar no fluxo de requisição:
var accessToken = $call.accessToken;
var extraInfo = accessToken.extraInfo;
// O valor é uma lista separada por vírgulas.
var allowedProjects = ( extraInfo.get('allowedProjects') || "*" ).split(",");
var allowedCall = false;
// Verifica se a URL chamada coincide com algum projeto permitido.
var url = $call.request.getRequestedUrl().getPath();
for ( var i = 0; i < allowedProjects.length; i++ ) {
// Um asterisco significa que este token pode ser usado para qualquer projeto.
if ( allowedProjects[i] == "*" ){
allowedCall = true;
break;
}
// Verifica se a URL é permitida.
// Se for, basta sair do script sem fazer nenhuma alteração.
if ( url.startsWith("/projects/" + allowedProjects[i]) ){
allowedCall = true;
break;
}
}
if ( !allowedCall ){
// Chega aqui se a URL chamada não é de nenhum projeto permitido.
$call.decision.setAccept( false );
$call.response.setStatus( 403 );
var body = {
message: "Este token so pode ser usado para os seguintes projetos: " + allowedProjects.join(",")
};
// Observe o uso do utilitário JSON.stringify(),
// que retorna uma string com a representação JSON de um objeto.
$call.response.getBody().setString( JSON.stringify(body), "utf-8" );
}
Com esse script e token, os resultados esperados são:
GET /projects/marketing-site => HTTP 200
GET /projects/product-support => HTTP 200
GET /projects/ui-redesign => HTTP 403
Obter token a partir de extraInfo
Neste exemplo abaixo, temos alguns clientes legados que não podem modificar seus sistemas para enviar Access Tokens OAuth 2.0.
Ao invés disso, eles precisam continuar enviando um par nome-de-usuário/senha em um header proprietário X-Usuario-Senha
.
Queremos recuperar esse header, extrair os dados, e montar um novo header Authorization com códigos que já conhecemos.
Para o gateway, tudo acontece como se o sistema legado tivesse enviado um header Authorization, como os demais sistemas. Por isso, este script precisa ser executado no fluxo de requisição. Como sabemos que apenas três sistemas legados estão dessa forma, faremos uma validação hard-coded das credenciais.
var oldHeader = $call.request.getHeader("X-User-Password");
oldHeader = $base64.atob(oldHeader);
var legacySystems = {
"system1:password1": "abc123",
"system2:password2": "def456",
"system3:password3": "ghi789"
}
var correctToken = legacySystems[oldHeader];
if ( correctToken == null ) {
$call.decision.setAccept( false );
$call.response.setStatus( 403 );
var body = { message: "Bad username/password" };
$call.response.getBody().setString( JSON.stringify(body), "utf-8" );
} else {
$call.request.setHeader( "Authorization", "Basic " + correctToken );
}
Alterar a rota de acordo com o extraInfo de um token
var extraInfo = $call.accessToken.extraInfo || new Packages.java.util.HashMap();
var isLegacy = extraInfo.get("isLegacy");
if ( isLegacy == "true" ) {
var newDest = 'http://legacy.backend.com';
var newUrl = new java.net.URI(newDest)
$call.setDestinationUri(newUrl);
$call.request.setHeader('Host', $call.destinationUri.getHost());
}
Comparar o valor do extraInfo com o valor do recurso da API
try {
var pass = false;
var url = $call.request.getRequestedUrl().getPath().split("/v1/");
var resource = url[1];
//Pega extrainfos e percorre todos, comparando o valor com o valor
//dos resources da API em questão que estão tentando ser consumidos.
var extraInfos = $call.app.extraInfo;
if(extraInfos){
var extraInfosArray = extraInfos.values().iterator();
while(extraInfosArray.hasNext()){
if (resource == extraInfosArray.next()){
pass = true;
}
}
}
if(!pass){
$call.response = new com.sensedia.interceptor.externaljar.dto.ApiResponse();
$call.decision.setAccept(false);
$call.response.setStatus(403);
$call.response.getBody().setString('{"message": "Forbidden"}','utf-8');
}
} catch (e) {
$call.tracer.trace(e);
}
Manipulação de query params
Adicionar query params de paginação quando ausentes
if ( ! $request.getQueryParam("page") )
$request.setQueryParam("page", "0");
if ( ! $request.getQueryParam("page_size") )
$request.setQueryParam("page_size", "20");
var page = parseInt($request.getQueryParam("page"));
if (page > 100 || page < 0)
$request.setQueryParam("page", 0);
var pageSize = parseInt($request.getQueryParam("page_size"));
if (pageSize > 100 || pageSize < 1)
$request.setQueryParam("page_size", 20);
Manipulação de respostas
Criar um XML e adicionar à resposta
var result = new org.jdom.Element("sensedia");
result.setText("xml");
$call.response.getBody().setString( $jdom.stringify(result), "utf-8" );
Interromper o fluxo de execução na requisição e retornar a resposta para o cliente
$call.stopFlow = true;
$call.decision.setAccept( false );
$call.response = new com.sensedia.interceptor.externaljar.dto.ApiResponse();
$call.response.setStatus( 400 );
Tratar exceções do backend
var respBody = $call.response.getBody().getString("utf-8") || "";
respBody = respBody.trim();
if ($call.response.getStatus() > 400 &&
respBody.length() > 0 &&
respBody[0] != '[' &&
respBody[0] != '{') {
respBody = JSON.stringify({message: "Ocorreu um erro no servidor."});
}
Modificar header "Authorization"
Este é um script para modificar um header Authorization
.
Neste exemplo, o cliente está enviando um header Authorization
cujo conteúdo é Basic YWJjZGVmCg==
.
Decodificando o valor em Base64, obtemos abcdef
, mas com um newline (\n
) no final.
Iremos remover o trecho Basic
, decodificar o valor restante em Base64, tirar o newline, e codificar novamente:
var auth = $call.request.getHeader( "Authorization" )
if ( auth != null ) {
// Remove o prefixo "Basic: "
if ( auth.toLowerCase().indexOf( "basic" ) == 0 )
auth = auth.substring("Basic".length).trim();
// Decodifica, remove newline e codifica novamente.
// Observe o uso do utilitario $base64.
// Veja outros utilitarios na referencia do desenvolvedor de hooks.
var plain = $base64.atob(auth);
var withoutWhitespace = plain.trim();
var base64 = $base64.btoa(withoutWhitespace);
// Sobrescreve o valor original do header
$call.request.setHeader( "Authorization", base64 );
}
Obter token a partir de um cookie
Neste exemplo, temos uma requisição que envia o access token como um cookie — isto é, misturado aos demais cookies enviados para o servidor. A requisição HTTP é da seguinte forma:
GET http://api.company.com/resources
Cookie: cookie1=value1; cookie2=value2; access_token=abcdef
Observe que existem três tokens no header Cookie
, e queremos que o restante do processamento do API Gateway trate a requisição como se o AccessToken
abcdef
tivesse sido enviado em um header access_token
.
Executaremos o script no fluxo de requisição, pois é durante a validação que os tokens serão realmente extraídos e validados.
// parseRequestCookieValues só funciona para a requisição.
// Para interpretar cookies na resposta,
// veja os demais métodos da classe utilitária $cookies.
// O resultado é uma Map case-insensitive de nomes de cookies para seus valores.
var allCookies = $cookies.parseRequestCookieValues($call.request.getHeader("Cookie"));
$call.request.setHeader( "access_token", allCookies.get("access_token") );
Renomear um campo no corpo da requisição
Neste exemplo, o cliente envia uma requisição em um formato ligeiramente antigo; no formato novo, um campo mudou de nome. Queremos apenas traduzir o nome velho para o novo:
old format: new format:
{ {
"id" : 123, "id" : 123,
"fatherId": 456 "parentId": 456
} }
O script deve ser executado no fluxo de requisição, para que ocorra antes do encaminhamento para o backend:
var json = JSON.parse( $call.request.getBody().getString( "utf-8" ) );
if ( json['fatherId'] != null ) {
json['parentId'] = json['fatherId'];
delete json['fatherId'];
}
$call.request.getBody().setString( JSON.stringify(json), "utf-8" );
O script pode ser testado apontando para um endpoint que ecoe o que foi recebido:
curl -H 'Content-Type: application/json' -d '{"fatherId": 123}' http://10.0.0.5:8080/example
O resultado deve incluir o corpo recebido:
...
"body" : "{\"parentId\":123}",
...
Suprimir informações sensíveis antes de enviar métricas
Em alguns casos, temos APIs que transferem dados sigilosos entre o backend e o cliente (como números de cartão de crédito), e não queremos expor esses dados nem mesmo para eventuais administradores de sistemas que utilizam o API Manager para investigar problemas.
Neste exemplo, usaremos um script que é executado no ponto before-metric
para mascarar esses campos.
As requisições e respostas não são modificadas pelo script abaixo; apenas as cópias desses objetos, enviadas para armazenamento e análise no Manager, são afetadas. O backend continua recebendo o número de cartão de crédito que foi enviado pelo cliente, e o cliente continua recebendo o número na resposta. |
var maskField = function(s) {
if ( s == null ) return null;
return "****-****-****-" + s.substring( 15 );
}
var maskFieldsInBody = function(bodyString) {
var json = JSON.parse( bodyString );
json["creditCard"] = maskField( json["creditCard"] );
return JSON.stringify( json );
}
// Modificamos apenas os dados em $call.metric.
// $call.request e $call.response não são modificados.
$call.metric.requestBody = maskFieldsInBody( $call.metric.requestBody );
$call.metric.responseBody = maskFieldsInBody( $call.metric.responseBody );
Transformar o método PUT em GET
if ( $call.request.getMethod() == "PUT" )
{
$call.request.setMethod( "GET" );
}
Tratar exceções do backend
Neste exemplo, temos um backend que, em caso de erros, retorna um stacktrace em formato HTML ou texto simples.
Ao invés disso, queremos montar uma mensagem apropriada para o cliente.
Vamos executar o script abaixo no ponto after-response
.
var respBody = $call.response.getBody().getString("utf-8") || "";
respBody = respBody.trim();
if ($call.response.getStatus() > 400 &&
respBody.length() > 0 &&
respBody[0] != '[' &&
respBody[0] != '{') {
respBody = JSON.stringify({message: "Ocorreu um erro no servidor."});
}
Uma outra opção seria retornar a mensagem padrão de erro dentro de um JSON.
Para isso, execute o código abaixo no ponto after-response
:
if($call.response.getStatus() == 401){
var errorBody = $call.response.getBody().getString("utf-8");
var jsonError = {};
jsonError.status = String($call.response.getStatus());
jsonError.message = String(errorBody);
$call.response.getBody().setString(JSON.stringify(jsonError), "utf-8");
$call.response.setHeader("Content-Type", "application/json");
}
Share your suggestions with us!
Click here and then [+ Submit idea]