Static Website Publishing to PubSub
By: Mark Scannell
Tags: Bigquery

Overview

Do you ever find yourself crafting JSON data you want to send into PubSub? Wish you had some kind of GUI, WebService, or CLI to make it easier?

How about a static webpage, hosted internally on an https endpoint, as a quick-and-easy approach?

This is also relying on GCP’s native security model. The webpage acts as a formatting tool (like a CLI!) for publishing the data using the end-users credentials using OAuth.

Show me!

These are a series of steps — small steps — to build up an HTML webpage. Error checking, user feedback, and style are all left as an exercise.

HTML Form

First we will start with a very simple HTML form. This will show a form on the screen with a message and publish button.

<!DOCTYPE html>

<html>

<head>

<meta charset='utf-8'/>

<body>

<!-- Form for submitting data to the topic -->

<form onsubmit="publish('testTopic', [window['message'].value]);

return false;">

<input type="text" id='message' name="msg"></input>

<input type="submit" value="Publish"></submit>

</form>

</body>

</html>

The only thing missing is the publish(topic, message) method.

Publish Message

The publish(topic, message) method is a thin wrapper calling this REST API endpoint. This is implemented below and it uses the gapi.client.request method — which manages OAuth — which is implemented in the next section.

<!-- Publish -->

<script type="text/javascript"> const PROJECT_ID = '<your-project>'; // Publish topic (as a promise)

async function publish(topic, messages) {

const attrs = {

'sent_by': 'publish.html'

}; // Create payload to send as per REST specification

let body = { 'messages': [] };

for (let i = 0; i < messages.length; i++) {

console.log('publishing', messages[i]);

body['messages'].push({

'data': btoa(JSON.stringify(messages[i])),

'attributes': attrs

});

}

return await gapi.client.request({

'path':'

PROJECT_ID + '/topics/' + topic + ':publish',

'method':'POST',

'headers': {},

'body': body,

});

}

</script> // Returnreturn await gapi.client.request({'path':' https://pubsub.googleapis.com/v1/projects/' PROJECT_ID + '/topics/' + topic + ':publish','method':'POST','headers': {},'body': body,});

GAPI Client Initialisation

We will use Javascript’s async/await in order to load the GAPI client, initialise it with the CLIENT_ID, Scope, and API_KEY, and, finally, sign in if needed. This is using the GAPI Javascript client API. This will prompt the user to authorise the client to act on the user’s behalf.

The CLIENT_ID and API_KEY will be detailed in the next section.



<script type="text/javascript"

src="

</script>

<script type="text/javascript">

const CLIENT_ID = '<CLIENT_ID>';

const PUBSUB_SCOPE = '

const API_KEY = '<API_KEY>'; https://apis.google.com/js/client.js</a> "> const CLIENT_ID = '<CLIENT_ID>';const PUBSUB_SCOPE = ' <a href="https://www.googleapis.com/auth/pubsub'" class="bu jj" rel="noopener ugc nofollow">https://www.googleapis.com/auth/pubsub'</a> const API_KEY = '<API_KEY>'; // Login (as a promise)

async function doLogin() { // Load auth libraries. These need to be

// wrapped in a promise to use async/await.

await new Promise((resolve, reject) => {

gapi.load('client:auth2', resolve);

}); // Await the GAPI api to initialise.

await gapi.client.init({

apiKey: API_KEY,

clientId: CLIENT_ID,

scope: PUBSUB_SCOPE,

}); // Sign in if needed

if (!gapi.auth2.getAuthInstance().isSignedIn.get()) {

await gapi.auth2.getAuthInstance().signIn();

}

} // Do the login

// Use promise results to update screen status?

doLogin(); </script>

CLIENT_ID and API_KEY

Both the Client ID and API Key come from Google Cloud’s API Services > Credentials section.

Creating the Client ID

Review Setting up OAuth 2.0 and keep the following in mind:

The authorised Javascript Origin needs to be setup for the static website. This can be localhost (can be http) or an https-enabled webserver. It must be hosted somewhere!

It is a Web Application.

Creating the API Key

Review Using API Keys and create a new API Key. The API Key can also be restricted to a certain domain and APIs to increase the key’s security.

Putting It Together

Before getting it all working keep in mind:

Create a topic with the end-user (the webpage user) with publish IAM permissions. In this example, testTopic is used.

Create a subscription for the topic that you can pull from. In this example, testSub is used.

Webpage

The webpage has a simple input and Publish. “test message!” is the message being sent.

Looking at the browser console is a good place to see if things are going wrong.

GCloud Subscription Pull

After publish, gcloud pubsub subscription pull can be used to fetch messages:

Conclusion

There is a lot of room for improvement, but creating a simple PubSub-publishing webpage is straight forward using OAuth. This isn’t recommended for public-facing solution (each PubSub message costs money!), but for internal facing tools it may just be the solution.