Thanks @Vinit Mehta for tagging me on this one. That’s correct @Ilyes, the pub/sub pattern with webhooks is very powerful to integrate systems that are oblivious from each other. As Vinit mentioned above we implemented it in Apigee by creating a facade on top of the management API. Essentially what we implemented looked like this:
Node.js API Proxy Facade ( Apigee Management API ) +
Pub/Sub API Resources
Node.js API Proxy Facade ( Apigee Management API )
Node.js API Proxy is the REST resource. The main purpose of this facade is to augment the capabilities of the Management API. For instance, when an API Proxy is deleted from production environment or a Key-Value Maps is updated, I want to receive a notification on Slack and Pagerduty.
Passthrough to Management API
All requests to the facade on all resources starting with /v1/** are to be piped to the Management API. This can be achieved by leveraging Node.js pipes. See code below:
app.all('/v1/**', function(req, res){ //listen all requests to /v1/**
var body_;
var url_parts = url.parse(req.url, true);
var p = req.pipe(request( url.resolve(apigeeConfig.management_server_url, url_parts.path), function(error, responseMgmt, body){
body_ = body;
} )).pipe( res );
For full code check this out.
The code to handle multiple subscribers on async fashion looks like this:
p.on('finish', function() { // execute after response is sent to the client
function send( body ){
async.map(
webhooksSubs.resources, //iterate through each resource under /config/webhooks-subscribers
async.apply( webHooks.forEachResource, req, body_ ),
function(err, result){
console.log(result);
return(body);
}
)
};
send(body_);
});
Take a look at the source code here.
As you may notice on p.on( ‘finish’ ) event, we can trigger fire and forget webhooks without holding the responses to the clients by leveraging finish event native streaming capabilities from Node.js.
And finally, Pub/Sub Resources
Currently, the implementation of subscribers is managed by a JSON file called webhook-subscribers.json. Essentially, this file contains a mapping between the events and the subscriber to those events.
{"resources" : [ {
"path" : "/v1/(?:organizations|o)/([A-Za-z0-9\\-\\_]+)/(?:apis)/([A-Za-z0-9\\-\\_]+)/revisions/\\d+/deployments/",
"description" : "Deploys a revision of an api proxy",
"verb" : "POST",
"subscribers" : [
{
"name" : "Slack Apigee-Webhook",
"desription" : "Incoming Webhook for apigee-webhook channel",
"url" : "https://hooks.slack.com/services/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",
"verb" : "POST",
"headers" : { "Content-Type" : "application/x-www-form-urlencoded" },
"qs" : null
}
]
}
]}
In the above code, POST events against the resource /v1/organizations/{org_id}/apis/{api_id}/revisions/{revision_id}/deployments will trigger a POST message to Slack Webhook. The logic to handle the request to Slack can either be handled by another facade or hit Slack API directly. Take a look at all the subscribers here.
Webhooks source code sample is available here.
For more use cases and discussions, please join these conversations in the community.
https://community.apigee.com/questions/12896/support-for-outbound-webhook-api-endpoints.html
https://community.apigee.com/questions/12663/using-apigee-to-push-real-time-api-insights-amazon.html
Hope it helps!
@Alex Koo, @Maruti Chand feel free to weigh in, if I’m missing anything.