How to Generate a JSONP Response

This article provides a script policy that will generate a JSONP response on demand. It is driven by two things:

  1. The Accept Header—if Accept is set to application/javascript, this will generate JSONP.
  2. The JSONP query param—if there is a JSONP query param present, this script uses the param value as the wrapping function name. If not, it defaults to jsonFunction.

There are a few subtleties in this script.

  1. It has to use information that is only available on the request, in the response processing, so it extracts these things (the accept header and the JSONP param) during request message processing and stores them in the exchange.

  2. If the returned content isn't already JSON, it mediates it to JSON by normalizing it to XML and then serializing it.

  3. If the returned content is already application/javascript the script doesn't do anything.

To make this work, you simply need to create an operational script policy using the following self-contained script, and then attach this policy to your virtual service.

// Get the message and the exchange
var msg = messageContext.getMessage();
var exg = messageContext.getExchange();

// Are we dealing with a request, response or fault
switch(messageContext.getParameterType())
{
  case 0:
    auditLog.debug("Request Message");

    // Get the Accept header and store it in the exchange
    var accept = String(msg.getTransportHeaders().get("Accept").getValue());
    exg.setProperty("accept.header", accept);

    // See if there is a JSONP query param
    var queryString = String(msg.getProperty("com.soa.message.TRANSPORT_QUERY"));
    var jsonpFunction = queryString.match(/jsonp=([^\&]*)/im);
    if (! jsonpFunction) {
      jsonpFunction = ["empty", "jsonpFunction"];
    }
    // store the JSONP function name in the exchange
    exg.setProperty("jsonp.function", jsonpFunction[1]);

    break;
  case 1:
    auditLog.debug("Response Message");

    // Get the Accept Header from the exchange
    var accept = exg.getProperty("accept.header");

    // If the header is looking for application/javascript then we will mediate
    if (accept == "application/javascript") {
      // if we don't already have JavaScript content
      if (msg.getContentType() != "application/javascript") {
        // make sure we have JSON
        if (msg.getContentType() != "application/json") {
          var content = msg.normalize();
          var jsonContent = serializer.read(content.getContentAsString());
          msg.setStringContent(jsonContent);
        }
        // Wrap the JSON result in the JSONP function name
        var jsonpContent = exg.getProperty("jsonp.function") + "(" + msg.getContentAsString() + ");";
        msg.setStringContent(jsonpContent);
        msg.setContentType("application/javascript");
      }
    }

    break;
  default:
    auditLog.debug("Fault");
    
}

Happy JSONP Generation.