I have a Google Cloud Run Function (formerly Cloud Functions 2nd Gen) running TypeScript/Node.js. The documentation in the Pub/Sub tutorial shows that you get a cloudEvent
, but how can I add type safety to it?
Specifically if I want to define the the type of the attributes or the message body.
This is their example:
const functions = require('@google-cloud/functions-framework');
// Register a CloudEvent callback with the Functions Framework that will
// be executed when the Pub/Sub trigger topic receives a message.
functions.cloudEvent('helloPubSub', cloudEvent => {
// The Pub/Sub message is passed as the CloudEvent's data payload.
const base64name = cloudEvent.data.message.data;
const name = base64name
? Buffer.from(base64name, 'base64').toString()
: 'World';
console.log(`Hello, ${name}!`);
});
There are some types defined in @google-cloud/functions-framework
.
npm install @google-cloud/functions-framework@^3.3.0
Then you can define your own types with the following code:
import functions, { CloudEvent } from '@google-cloud/functions-framework'
import { RawPubSubBody } from '@google-cloud/functions-framework/build/src/pubsub_middleware'
/**
* We get them as `attributes?: { [key: string]: string }`
* But since we know the structure, we can define it as an interface
*/
interface PubSubAttributes {
myTestAttribute: string
}
/** Extend the RawPubSubBody to use PubSubAttributes */
interface FunctionPubSubBody extends RawPubSubBody {
message: {
attributes: PubSubAttributes
} & RawPubSubBody['message']
}
/** An interface that defines the shape of the body of the message */
interface PubSubBodyData {
testBodyParam: string
}
// https://cloudevents.github.io/sdk-javascript/classes/CloudEvent.html
functions.cloudEvent<FunctionPubSubBody>(
'syncAllMoviesNode',
// You don't technically need to declare this type (it's inferred from above)
async (cloudEvent: CloudEvent<FunctionPubSubBody>) => {
console.log(cloudEvent)
// The Pub/Sub message is passed as the CloudEvent's data payload.
// It's base64 encoded, so we need to decode it and parse it as JSON.
const base64Data = cloudEvent.data.message.data
const base64String = Buffer.from(base64Data, 'base64').toString()
const pubSubBody: PubSubBodyData = JSON.parse(base64String)
const pubSubAttributes: PubSubAttributes = cloudEvent.data.message.attributes
// The "Message Body" with type PubSubBodyData
console.log(pubSubBody)
// The "Attributes" as PubSubAttributes
console.log(pubSubAttributes)
}
)
This Reddit thread has some thoughts, but my takeaway is:
bodyType
which is an enum of SYNC | CLEAR
SyncMessageBody
and ClearMessageBody
But honestly you can use them however you want.