Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Experimenting With Cloud Functions for Use in Web Push

DZone's Guide to

Experimenting With Cloud Functions for Use in Web Push

Google Cloud Functions aren't just for serverless architecture. You can use them to integrate features that might give you trouble, like Web Push.

· Cloud Zone
Free Resource

Linkerd, the open source service mesh for cloud native applications. Get the complete guide to using Linkerd and Kubernetes to build scalable, resilient applications.

I’ve been building out a quick sample that lets you quickly hook up Web Push with a simple cURL request. The principle being that I would like to get integrations with third party APIs that currently don’t support Web Push in any way.

The thing about webhooks is that they are not standardized in any way other than you will most likely get a blob of data in a POST HTTP request.

For example, Travis CI application/x-www-form-urlencoded encodes the request data, whereas GitHub will just put a JSON object as the POST payload. Neither is wrong, they are just different and each other webhook service will be different in their own way too and I need to be able to handle that.

I decided to implement a small piece of functionality that would allow me to receive arbitrary web requests from a service (such as Travis or Github) and to apply custom logic on the messages so that I can output the data that is required for the web push notification.

The requirements that I had were:

  • I wanted to contain logic for each type of data in its own module.
  • I wanted process isolation so that anyone malicious message wouldn’t bring down my service.
  • I wanted to be able to be able to scale quickly to an unknown number of requests.
  • I didn’t want to have to manage infrastructure.

Given that I am on Google Compute Engine and I am always curious, I felt that Google Cloud Functions might be a good fit. GCFs are the same as Amazon Lambdas and they let me create a small unit of processing and scale it when the relevant system event happens (in my case, when a web hook request is received).

The architecture that I decided upon was roughly as follows.

Requests come into the front end, are forwarded to the correct transformation function in Google Cloud Functions and finally sent to the user.

I would have named queues for each service integration and a dedicated cloud function for each data processor.

The front end is not amazingly complex. It takes the web request that was sent via a POST request to /send-raw and pushes the data onto the relevant queue for processing by the cloud function that knows how to transform the data.

The code is relatively straightforward: receive the message, send it on for processing.

// parse application/x-www-form-urlencoded 
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json 
app.use(bodyParser.json())

app.post('/send-raw', (req, res) => {
  const message = req.body;
  const id = req.query.id;
  const processor = req.query.processor;

  // Topic must exist
  const rawTopic = pubsub.topic(`projects/${project_id}/topics/send-${processor}`);
  rawTopic.publish({
      id: id,
      processor: processor,
      message: message
    })
    .then(() => res.send('ok'))
    .catch(() => res.send('error'))
});


The function is set up as a subscription to the relevant queue and when a message is on the bus, it triggers the run function. The code, again, is not too complex as Cloud Functions is taking care of all the scaling and all I have to do is implement the naive transform from Travis CI’s data payload to the format I need to send the web push message.

/**
 * Triggered from a message on a Cloud Pub/Sub topic.
 *
 * @param {!Object} event The Cloud Functions event.
 * @param {!Function} The callback function.
 */
exports.run = function subscribe(event, callback) {
  // The Cloud Pub/Sub Message object.
  const pubsubMessage = event.data;
  const data = JSON.parse(Buffer.from(pubsubMessage.data, 'base64').toString());
  const id = data.id;
  const msgObject = JSON.parse(data.message.payload);

  const sendTopic = pubsub.topic(sendTopicId);
  const transformedMessage = {
    "title": `Travis: ${msgObject.repository.name} ${msgObject.status_message}`,
    "description": `${msgObject.status_message}`,
    "url": `${msgObject.build_url}`
  };

  // Send the push to the push sending service
  sendTopic.publish({
    id: id,
    message: transformedMessage
  });

  // Don't forget to call the callback.
  callback();
};


And voila!

A message.

Linkerd, the open source service mesh for cloud native applications. Get the complete guide to using Linkerd and Kubernetes to build scalable, resilient applications.

Topics:
serverless architecture ,google cloud functions ,cloud ,web push service

Published at DZone with permission of Paul Kinlan, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}