Velocity knowledge is useful even outside of Marketo. I’ve been waiting for a ripped-from-the-headlines example, and along came this Marketo Nation question:
I’m calling a remote service via webhook. But the results aren’t coming back in a format the Response Mappings can understand (at least not from what I’ve tried). The response JSON looks like this:
{ "car_count" : 123456, "item_count" : 117733, "item_types" : [ { "item_type" : "Blue Car", "item_type_count" : 1115, "item_type_ratio" : 12 }, { "item_type" : "Red Car", "item_type_count" : 1225, "item_type_ratio" : 14 }, { "item_type" : "Yellow Car", "item_type_count" : 1345, "item_type_ratio" : 6 } ], "item_types_ratio" : 22 }
But I need to get the item_type_count for each item_type to write to different fields. This would be easy if the JSON were like this:
{ "Blue Car" : 1115, "Red Car" : 1225, "Yellow Car" : 1345 }
In case it’s not clear, the reason the original JSON response won’t work with webhook Response Mappings is that a Response Attribute entry always uses a string property name (which could be a numeric string array index[1]).
That is, you can reference “the first member of the
item_types
array” (item_types[0]
) and get its item_type_count
: that’s item_types[0].item_type_count
.
But you can’t reference “the (first) member of the item_types
array that has the property item_type
set to Blue Car
” and get its item_type_count
. That would amount to seeking the value of a specific property in an object (not the name) and back-referencing the object. Not possible!
A value-based seek is possible in JSONPath, where you use script expressions, which are like callbacks. In JSONPath, you’d do $.item_types[?(@.item_type == "Blue Car")].item_type_count
.
Only Response Mappings don’t support JSONPath.
This is where you need an API gateway sitting between you and the original remote service:
API gateways typically emphasize their enterprise features: security, rate limits, load balancing, multiplexing, et al. But buried in nearly every feature list is something basic: a content transformer. (You can see it under “Manipulation - Transform” on KrakenD’s infographic.)
Transformers are usually marketed in terms of transforming XML to JSON or other such big promises. But sometimes you just need to transform JSON into slightly different JSON. The transformer can do that, too.
There are several players offering API-gateway-as-a-service, but I’m most familiar with Amazon’s. AWS API Gateway is cheap — free tier is a million requests per month — and it’s, well, easy enough to set up. (Not really easy,I concede.)
We’re going to build an AWS API GW definition for the remote service at https://originalendpoint.example.com
. The assumption for today is you typically GET that URL using a Marketo webhook.
First, Build a new REST API:
Confirm this is REST, not WebSocket:
Next, Create Method at the top level:
Choose GET from the dropdown:
Set the remote Integration Type to HTTP, and type the original Endpoint URL.
Now, the good stuff. Click Integration Response:
Add this simple Velocity script as the Mapping Template for the Content-Type application/json:
#set( $item_types = $input.path("$.item_types") )
{
#foreach( $type in $item_types )
"${util.escapeJavaScript($type.item_type).replaceAll("\\'","'")}" : ${type.item_type_count}#if( $foreach.hasNext ),#end
#end
}
Finally, Deploy API generates your unique Invoke URL. That’s what you swap in in the Marketo webhook definition.
The Velocity transformer code is very simple, as long as you have a little bit of Velocity experience to start with!
$input.path()
method to get a list representation of the item_types
objects. (ArrayList[2] of LinkedHashMaps, if you wanna be technical.){
of a top-level JSON object.$type
object in the list, output the quoted, JSON-encoded value of its item_type
property, then a colon :
, then the unquoted (since it’s a number) value of its item_type_count
property.,
if necessary.}
of the JSON object
You’ve thus transformed this original response:
{
"car_count" : 123456,
"item_count" : 117733,
"item_types" : [
{
"item_type" : "Blue Car",
"item_type_count" : 1115,
"item_type_ratio" : 12
},
{
"item_type" : "Red Car",
"item_type_count" : 1225,
"item_type_ratio" : 14
},
{
"item_type" : "Yellow Car",
"item_type_count" : 1345,
"item_type_ratio" : 6
}
],
"item_types_ratio" : 22
}
Into this:
{
"Blue Car" : 1115,
"Red Car" : 1225,
"Yellow Car" : 1345
}
The new JSON “shape” lets you use Response Mappings to capture the count for each color:
This post is meant to take you, say, 85% of the way toward a production API gateway hosted on AWS. There are some parts I couldn’t get to because the main thrust is about transformation using JSONPath + Velocity.
You should also require an API Key for authentication and add the corresponding X-Api-Key
header in Marketo » Webhooks Actions » Set Custom Header. And you’ll most likely need to declare URL Query String Parameters so they’re passed to the remote service.
Both of the above options are under Method Execution in the AWS Console.
[1] For you see, array indexes are actually string property names, even though we express them as integers.
[2] Even more technically, it’s a net.minidev.json.JSONArray of java.util.LinkedHashMap objects. JSONArray is a subclass of java.util.ArrayList.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.