Custom JavaScript: Ejemplos

Aquí tenemos ejemplos de scripts para agregar a sus interceptores personalizados JavaScript.

Abortar requests a recursos antiguos

Este script puede ser usado para bloquear el acceso a una URL obsoleta, pero con un mensaje más agradable para los desarrolladores que todavía usan esta URL. Introduzir la URL deseada en el campo URL Pattern y usar los siguientes scripts:

Esto extracto indicará que el gateway no aceptará la petición. Debe ser ejecutado en el flujo de petición (request).

$call.decision.setAccept(false);

Añadir el siguiente fragmento, modificando la respuesta para establecer un código de estado 404 y un cuerpo fijo. Debe ser ejecutado en el paso after-response.

$call.response.setStatus(404);
$call.response.getBody().setString(
  '{"message": "Este recurso ha sido eliminado. Usar /orders/status en su lugar."}', "utf-8"
);

Agregar header desde el extraInfo de un token

Este script puede ser usado para añadir un header a una petición. El contenido de este header será tomado del extraInfo de un de los tokens de acceso utilizados en la petición.

En el ejemplo siguiente, un header X-Customer-Id será añadida, y contiene la identificación del cliente representado por el access token actual.

var access_token = $call.accessToken;
if (access_token) {
    $request.setHeader("X-Customer-Id", access_token.extraInfo.get('customerId'));
}

Para probar el guión anterior, hacer la siguiente petición. Esta prueba supone que hay un token de acceso con un código mycustomer, que contiene un campo extraInfo llamado customerId y con un valor de 123.

curl -H "access_token: mycustomer" http://10.0.0.5:8080/supermock

Entre los headers recibidos por el servidor, debe existir:

...
"headers": {
    ...
    "X-Customer-Id": "123"
    ...
}

Tenga en cuenta que en el script anterior asumimos que siempre habrá un token de acceso. Se el script se ejecuta en el flujo de petición (request) y se requiere un token de acceso (como suele ser el caso), entonces esta suposición es sensata, ya que el gateway impediría el acceso si el token no fuera informado.

Sin embargo, si el token es opcional, debemos ocuparnos del caso de que no sea informado. En el ejemplo siguiente, se añade un header que indica que esta aplicación se está probando en un entorno de pruebas, pero puede ser que la aplicación no esté informada.

var app_token = $call.app;
if (app_token && app_token.extraInfo.get('isSandbox') == "true") {
    $request.setHeader("X-Is-Sandbox", "true");
}

Para probar el guión anterior, hacer la siguiente petición. Esta prueba supone que hay una aplicación con un código myapp, que contiene un campo extraInfo llamado isSandbox y con un valor de true.

curl -H "client_id: myapp" http://10.0.0.5:8080/supermock

Entre los headers recibidos por el servidor, debe existir:

...
"headers": {
    ...
    "X-Is-Sandbox": "true"
    ...
}

Agregar header fijo

Este script puede ser usado para añadir un header a una petición. En el ejemplo siguiente, añadimos un header Content-Type: application/json sólo si la petición no contiene un header Content-Type.

if ( $call.request.getHeader( "Content-Type" ) == null )
    $call.request.setHeader( "Content-Type", "application/json" );

Agregar query params de paginación cuando estén ausentes

En este ejemplo, hay un servidor que siempre que siempre espera recibir parámetros de paginación en la query-string de las llamadas (ejemplo: /products?page=5&page_size=10). Pero queremos que las peticiones sin estos parámetros se ejecuten con valores estándar sensatos (page=0 y page_size=10, por ejemplo).

También tenga en cuenta que no añadiremos parámetros si ya existen.

if ( ! $request.getQueryParam("page") )
    $request.setQueryParam("page", "0");

if ( ! $request.getQueryParam("page_size") )
    $request.setQueryParam("page_size", "20");

También queremos protegernos contra llamadas que especifican parámetros de paginación inaceptables, así que debemos continuar el script anterior con:

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 la ruta de acuerdo con el extraInfo de un token

En este ejemplo, la ruta a seguir difiere dependiendo de una flag en el campo extraInfo de un token de acceso, indicando si se trata de una legacy (y entonces debe ser direcionado para http://legacy.mycompany.com) o no (en este caso, enviado para http://api.mycompany.com).

Tenga en cuenta que se debe establecer al menos una ruta. De lo contrario, el gateway considerará la petición como maldormada y devolverá el código de estado HTTP 404 antes que tenhamos la oportunidad de ejecutar 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 probar el script, crear una aplicación con extraInfo isLegacy = true y hacer una petición. Después, modificar la flag (o crear una otra aplicación con isLegacy = false) y hacer otra petición.

curl -H 'client_id: mynewapp' http://10.0.0.5:8080/supermock/api

curl -H 'client_id: mylegacyapp' http://10.0.0.5:8080/supermock/api

La primera petición, hecha por una aplicación actualizada, debe alcanzar http://supermock.demo.sensedia.com/supermock/api. La segunda llamada, hecha por una aplicación heredada, deve alcanzar http://legacy.backend.com.

Convertir el cuerpo de la response de JSON a XML

En este ejemplo, tenemos una API en el servidor que devuelve una respuesta JSON, pero queremos assemblear un XML equivalente para retornar al cliente.

El interceptor default JSON to XML puede ser utilizado para esta transformación.

Ejecutaremos el siguiente script en el flujo de respuesta (response):

// Hace el análisis del JSON recibido
var json = JSON.parse( $call.response.getBody().getString("utf-8") );

// Esta función convierte un objeto en una representación XML
// Observe que no se ocupa de subobjetos ni de colecciones
var toXml = function(jsonNode, rootName) {

    // Estamos utilizando JDOM para assemblear el XML
    var result = new Packages.org.jdom.Element(rootName);

    // Cada propiedad de jsonNode se convierte en un subelemento del elemento anterior
    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 el filtro en el nodo de la raíz
// Note que estamos asumiendo que el resultado es siempre un objeto, no una lista
var root = toXml( json, "root" );

// Serializa y establece la respuesta
$call.response.getBody().setString( $jdom.stringify(root), "utf-8" );

Con un poco más de código, podemos hacer que la función toXml() se ocupe de listas de objetos, objetos complejos, etc.

Convertir el cuerpo de la request de text a JSON

Este ejemplo recibe una petición en el formato properties (un subconjunto de YAML):

invoice : 34843
customer: Benjamin
date    : 2001-01-23
tax     : 251.42
total   : 4443.52

Queremos convertirla para JSON, como a continuación:

{
  "invoice": 34843,
  "customer": "Benjamin",
  "date": "2001-01-23",
  "tax": 251.42,
  "total": 4443.52
}

Para esto, vamos a ejecutar el siguiente script en el flujo de petición (request):

// Siempre especificar la codificación.
// En este caso, estamos forzando utf-8,
// pero podríamos consultar los headers de la petición para averiguar
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 += '}';

// Establece el nuevo cuerpo de la petición
$call.request.getBody().setString(newBody, "utf-8");
$call.request.setHeader("Content-Type", "application/json");
El interceptor default TXT to JSON puede ser utilizado para esta transformación.

Crear un XML y agrégarlo a la response

Este script crea un XML usando JDOM y lo agrega a la respuesta.

var result = new org.jdom.Element("sensedia");
result.setText("xml");
$call.response.getBody().setString( $jdom.stringify(result), "utf-8" );

Descomprimir el cuerpo de la request con gzip

El código siguiente descomprime el cuerpo de la petición empaquetada con gzip.

Esta transformación debe ser ejecutada en el flujo de petición (request).

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" );

Ejecutar otros servicios durante la transformación

La mejor forma de ejecutar otros servicios es utilizar el interceptor Service Mashup. Sim embargo, es possible hacerlo también con interceptores personalizados.

En este ejemplo, realizaremos una orquestación de servicios. La llamada de servicios puede ser utilizada en cualquier flujo (petición/respuesta).

Ejemplos:

    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)
    }

Interrumpir el flujo de request y devolver la respuesta al cliente

En este ejemplo, añadimos un nuevo atributo al objeto $call, haciendo posible interrumpir el flujo de peticiones (request) en cualquier punto y devolviendo la respuesta al cliente.

Para interrumpir la ejecución de la petición y devolver la respuesta sin acceder al servidor y ejecutar el flujo de respuesta (response), ejecutar:

$call.stopFlow = true;
$call.decision.setAccept( false );
$call.response = new com.sensedia.interceptor.externaljar.dto.ApiResponse();
$call.response.setStatus( 400 );

Para interrumpir la ejecución de la petición o respuesta, haciendo la petición al servidor, ejecutar:

$call.stopFlow = true;

Manejar facturación

Este es un script para manejar las opciones de facturación.

$call.billing = true;
$call.billingValue = 5.85;
$billing.execute($call);

Observación:

  • El atributo billingValue funciona con precisión Doble, por lo que es posible que tenga un posible redondeo o pérdida de precisión hasta los decimales.

  • Para el control y bloqueo del consumo, la opción Abort request if fail debe ser seleccionada en el editor del interceptor, además de incluir el manejo de excepciones en el interceptor personalizado mismo o en el Raise Exception del flujo.

Manejar body

Renombrar un campo en el cuerpo de la petición

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" );

Convertir el cuerpo de la respuesta 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");

Convertir el cuerpo de la petición 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");

Obtener un parámetro de la URI y poner en el cuerpo de la petición

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 el cuerpo de la petición con 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" );

Transformación con subelementos JSON y con 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");

Manejar header

Añadir header fijo (Content-Type)

if ( $call.request.getHeader( "Content-Type" ) == null )
    $call.request.setHeader( "Content-Type", "application/json" );

Añadir header de extrainfo de una aplicación y token de acceso

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" );

Cambiar 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 );
}

Llamar a un servicio que devuelva 302 y unir los headers de la respuesta con los headers del servicio siguiente para devolver al 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' );

}

Eliminar un atributo de header de la petición antes de pasar la llamada al servidor

try{
   $call.request.getAllHeaders().remove("seu-header");
} catch(e){
   $call.tracer.trace(e);
}

Manejar extraInfo

Validar URL contra extraInfo

En el ejemplo siguiente, vamos crear un script que será ejecutado sólo en URL de tipo /projects/*. Este patrón deve ser insertado en el campo URL Pattern.

Esta API devuelve la lista de miembros de un proyecto determinado. Pero cada token de acceso sólo puede ver unos pocos proyectos. La lista de proyectos permitidos se almacena en el extraInfo del token en el momento de registro:

access_token.extraInfo = new Packages.java.util.HashMap();
access_token.extraInfo.put('allowedProjects', 'marketing-site,product-support');

Se el token anterior se utiliza para llamar /projects/marketing-site o /projects/product-support, se deve permitir el acceso, pero si se utiliza para llamar /projects/ui-redesign, queremos que se bloquee con un error «HTTP 403 Forbidden» y un mensaje explicativo.

Como necesitamos el token ya extraído y validado, pondremos el script para ser ejecutado en el flujo de petición (request):

var accessToken = $call.accessToken;
var extraInfo = accessToken.extraInfo;

// El valor es una lista separada por comas.
var allowedProjects = ( extraInfo.get('allowedProjects') || "*" ).split(",");
var allowedCall = false;

// Comprueba si la URL llamada coincide con algún proyecto permitido.
var url = $call.request.getRequestedUrl().getPath();
for ( var i = 0; i < allowedProjects.length; i++ ) {

    // Un '*' significa que el token puede ser usado para cualquier proyecto.
    if ( allowedProjects[i] == "*" ){
        allowedCall = true;
        break;
    }

    // Comprueba si la URL es permitida.
    // Si es, dejar el script sin hacer ningún cambio.
    if ( url.startsWith("/projects/" + allowedProjects[i]) ){
        allowedCall = true;
        break;
    }
}

if ( !allowedCall ){
    // Viene aquí si la URL llamada no es de ningún proyecto 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 el uso de la utilidad JSON.stringify(),
    // que devuelve una string con la representación JSON de un objeto.
    $call.response.getBody().setString( JSON.stringify(body), "utf-8" );
}

Con este script y token, los resultados esperados son:

GET /projects/marketing-site               => HTTP 200
GET /projects/product-support              => HTTP 200
GET /projects/ui-redesign                  => HTTP 403

Obtener token de extraInfo

En el ejemplo siguiente, tenemos algunos clientes con legacy que no pueden modificar sus sistemas para enviar tokens de acceso OAuth 2.0. En vez de eso, necesitan seguir enviando un par de nombre-de-usuario/contraseña en un header proprietario X-Usuario-Senha. ueremos recuperar este header, extraer los datos y ensamblar un nuevo header (`Authorization) con códigos que ya conocemos.

Para el gateway, todo sucede como si el sistema heredado enviara un header Authorization como los otros sistemas. Por lo tanto, este script debe ser ejecutado en el flujo de petición. Como sabemos que sólo tres sistemas heredados son así, haremos una validación hard-coded de las credenciales.

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 );
}

Cambiar la ruta de acuerdo con el extrainfo de un 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 el valor de extrainfo con el valor del recurso de la API

try {
 var pass = false;
 var url = $call.request.getRequestedUrl().getPath().split("/v1/");
 var resource = url[1];

 //Coge extrainfo y pasa por todos, comparando su valor con el valor
 //de los recursos de la API que están tratando de 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);
}

Manejar query params

Añadir query params de paginación cuándo no están

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);

Manejar respuestas

Crear un XML y añadirlo a la respuesta

var result = new org.jdom.Element("sensedia");
result.setText("xml");
$call.response.getBody().setString( $jdom.stringify(result), "utf-8" );

Para el flujo de ejecución en la petición y devolver la respuesta al cliente

$call.stopFlow = true;
$call.decision.setAccept( false );
$call.response = new com.sensedia.interceptor.externaljar.dto.ApiResponse();
$call.response.setStatus( 400 );

Tratar excepciones de servidor

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: "A server error occurred."});
}

Modificar el header «Authorization»

Este es un ejemplo de cambio de un header Authorization.

En este ejemplo, el cliente envia un header Authorization con contenido Basic YWJjZGVmCg==. Decodificando el valor en Base64, tenemos abcdef, pero con una nueva línea (\n) al final. Vamos a eliminar el fragmento Basic, sacar la nueva línea y re-codificar:

var auth = $call.request.getHeader( "Authorization" )
if ( auth != null ) {

    // Eliminar el prefijo "Basic: "
    if ( auth.toLowerCase().indexOf( "basic" ) == 0 )
        auth = auth.substring("Basic".length).trim();

    // Decodificar, sacar nueva línea y re-codificar.
    // Observe el uso de la utilidad $base64.
    // Ver otras utilidades en la referencia del desarrollador de hook.
    var plain = $base64.atob(auth);
    var withoutWhitespace = plain.trim();
    var base64 = $base64.btoa(withoutWhitespace);

    // sobrescribir el valor original del header
    $call.request.setHeader( "Authorization", base64 );
}

Esto es un script para obtener un token de acceso de una cookie. En el ejemplo a continuación, tenemos una petición que envía un token de acceso como una cookie — es decir, entre las otras cookies enviadas al servidor. La petición HTTP es la siguiente:

GET http://api.company.com/resources
Cookie: cookie1=value1; cookie2=value2; access_token=abcdef

Nótese que hay tres tokens en el header Cookie y queremos que el procesamiento del API Gateway trate la petición como si el token abcdef hubiera sido enviado en un header access_token. Ejecutaremos este script en el flujo de petición (request), ya que es durante la validación que los tokens serán extraídos y validados.

// parseRequestCookieValues sólo funciona en la petición.
// Para interpretar cookies en la respuesta,
// veer otros métodos de la clase de utilidad $cookies.
// El resultado es un mapa de nombres de cookies que no
// distingue entre mayúsculas y minúsculas para sus valores.
var allCookies = $cookies.parseRequestCookieValues($call.request.getHeader("Cookie"));
$call.request.setHeader( "access_token", allCookies.get("access_token") );

Cambiar el nombre de un campo en el cuerpo de la request

En este ejemplo, el cliente envía una petición en un formato un anticuado; en el nuevo formato, un campo ha cambiado de nombre. Solo queremos traducir el nombre antiguo al nuevo:

old format:                new format:

{                          {
  "id"      : 123,           "id"      : 123,
  "fatherId": 456            "parentId": 456
}                          }

El script debe ser aplicado en el flujo de petición (request), de modo que se ejecute antes de que la llamada se transmita al servidor.

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" );

El script se puede probar apuntando a un endpoint que haga eco de lo recibido.

curl -H 'Content-Type: application/json' -d '{"fatherId": 123}' http://10.0.0.5:8080/supermock

El resultado debe incluir el cuerpo recibido.

...
"body" : "{\"parentId\":123}",
...

Suprimir la información confidencial antes de enviar métricas

En algunos casos, hay APIs que transfieren datos sensibles entre el servidor y el cliente (como los números de las tarjetas de crédito), y no queremos exponer esos datos ni siquiera a los posibles administradores de sistemas que utilizan el API Manager para investigar posibles problemas. En este ejemplo, usaremos un script que se ejecuta en el punto before-metric para enmascarar esos campos.

Las peticiones y respuestas no son modificadas por el script; sólo las copias de estos objectos (que son enviadas para almacenamiento y análisis en el Manager) son afectadas. El servidor continúa recibiendo el número de tarjeta de rédito que envió el cliente y el cliente continúa recibiendo el número en la respuesta.
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 );
}

// Sólo modificamos los datos en $call.metric.
// $call.request y $call.response no se cambian.
$call.metric.requestBody = maskFieldsInBody( $call.metric.requestBody );
$call.metric.responseBody = maskFieldsInBody( $call.metric.responseBody );

Transformar métodos: PUT en GET

if ( $call.request.getMethod() == "PUT" )
{
    $call.request.setMethod( "GET" );
}

Tratar las excepciones de backend

En este ejemplo, hay un servidor que, en caso de error, devuelve un stacktrace em formato HTML o texto simple. En cambio, queremos elaborar un mensaje apropriado al cliente. Vamos a ejecutar el script a continuación en el punto 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: "Ha ocurrido un error de servidor."});
}

Otra opción sería devolver el mensaje de error por defecto dentro de un JSON. En este caso, ejecutar el código a continuación en el punto 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");
}
Thanks for your feedback!
EDIT

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