A JavaScript User-Defined Function (UDF) is a type of Single Message Transform (SMT). UDFs provide a flexible way to implement custom transformation logic within Pub/Sub, similar to BigQuery JavaScript UDFs.
UDFs accept a single message as input, perform the defined actions on the input, and return the result of the process.
UDFs have the following key properties:
Code: The JavaScript code that defines the transformation logic.
Function name: The name of the JavaScript function within the provided code that Pub/Sub applies to messages.
Create the JavaScript function
The UDF code must contain a function with the following signature:
/**
* Transforms a Pub/Sub message.
* @return {(Object<string, (string | Object<string, string>)>|* null)} - To
* filter a message, return `null`. To transform a message, return a map with
* the following keys:
* - (required) 'data' : {string}
* - (optional) 'attributes' : {Object<string, string>}
* Returning empty `attributes` will remove all attributes from the message.
*
* @param {(Object<string, (string | Object<string, string>)>} - Pub/Sub
* message. Keys:
* - (required) 'data' : {string}
* - (required) 'attributes' : {Object<string, string>}
*
* @param {Object<string, any>} metadata - Pub/Sub message metadata.
* Keys:
* - (optional) 'message_id' : {string}
* - (optional) 'publish_time': {string} YYYY-MM-DDTHH:MM:SSZ format
* - (optional) 'ordering_key': {string}
*/
function <function_name>(message, metadata) {
// Perform custom transformation logic
return message; // to filter a message instead, return `null`
}
Inputs
The function takes the following inputs:
messageargument: A JavaScript object representing the Pub/Sub message. It contains the following properties:data: (String, required) The message payload.attributes: (Object<String, String>, optional) A map of key-value pairs representing message attributes.
metadataargument: A JavaScript object containing immutable metadata about the Pub/Sub message:message_id: (String, optional) The unique ID of the message.publish_time: (String, optional) The message's publish time in RFC 3339 format (YYYY-MM-DDTHH:mm:ssZ).ordering_key: (String, optional) The message's ordering key, if applicable.
Outputs
The function must return one of the following:
To transform a message, edit the contents of
message.dataandmessage.attributes, and return the alteredmessageobject.To filter a message, return
null.
Input / Output Requirements
- If the UDF transforms the message payload, the payload input and output must be UTF-8 encoded strings.
- If the UDF does not transform the message payload, the payload may use any encoding.
- Attribute key-value pairs must be UTF-8 encoded strings.
How UDFs transform a message
The result of running a UDF on a message can be one of the following:
The UDF transforms a message.
The UDF returns
null.Topic SMTs: Pub/Sub returns success to the publisher and includes a message ID in the response for the filtered messages. Pub/Sub does not store the message or send it to any subscribers.
Subscription SMTs: Pub/Sub acknowledges the message delivery without sending the message to a subscriber.
The UDF throws an error.
Topic SMTs: Pub/Sub returns the error to the publisher and does not publish any of the messages.
Subscription SMTs: Pub/Sub negatively acknowledges the message.
Create a UDF SMT
SMTs can be configured on Pub/Sub topics or subscriptions.
- Topic SMTs are executed before Pub/Sub stores the message, and the results are available to all subscribers.
Subscription SMTs are executed before the message is delivered, and the results are only available for that subscription.
Console
In the Cloud de Confiance console, go to the Pub/Sub Topics page.
Create either a topic or a subscription.
To create a topic, click Create topic. The Create topic page opens.
To create a subscription:
Click the name of the topic where you want the subscription.
Click Create subscription. The Add subscription to topic page opens.
Under Transforms, click Add a transform.
For Transform type, select JavaScript UDF.
In the Function name field, enter the name of the JavaScript function that the SMT calls. Example:
redactSSN.In the text area, enter the code for the UDF. Example:
function redactSSN(message, metadata) { const data = JSON.parse(message.data); delete data['ssn']; message.data = JSON.stringify(data); return message; }The code must contain a function whose name matches the Function name field.
If you don't want the SMT to be active immediately, select Disable transform. When this option is selected, the SMT is created with the topic, but isn't executed on incoming messages. After the topic is created, you can edit the topic to enable the SMT.
To create the topic or subscription, click Create.
gcloud
Create a definition file
Create a YAML or JSON file that defines the UDF SMT.
YAML
- javascriptUdf:
code: { FUNCTION_CODE }
functionName: FUNCTION_NAME
JSON
{
"javascriptUdf": {
"code": {
FUNCTION_CODE
}
"functionName": FUNCTION_NAME
}
}
Replace the following:
FUNCTION_CODE: The Javascript code for the UDF. The code must contain a function whose name matches the
functionNamefield. Example:function redactSSN(message, metadata) { const data = JSON.parse(message.data); delete data['ssn']; message.data = JSON.stringify(data); return message; }FUNCTION_NAME: The name of the JavaScript function that the SMT calls. Example:
redactSSN.
Create a topic or subscription
To create a topic, run the
gcloud pubsub topics create
command.
gcloud pubsub topics create TOPIC_ID \
--message-transforms-file=TRANSFORMS_FILE
Replace the following:
- TOPIC_ID: The ID or name of the topic you want to create.
- TRANSFORMS_FILE: The path to the definition file.
To create a subscription, run the
gcloud pubsub subscriptions create
command.
gcloud pubsub subscriptions create SUBSCRIPTION_ID \
--topic=projects/PROJECT_ID/topics/TOPIC_ID \
--message-transforms-file=TRANSFORMS_FILE
Replace the following:
SUBSCRIPTION_ID: The ID or name of the subscription to create.
PROJECT_ID: The ID of the project that contains the topic.
TOPIC_ID: The ID of the topic to subscribe to.
TRANSFORMS_FILE: The path to the definition file.
Optionally, you can validate and test the SMT before you create it. For more information, see the following pages:
Limitations
Pub/Sub enforces resource limits on UDFs to ensure efficient transformation operations. The limitations include:
- A maximum of 20 KB of code per UDF
- A maximum of 500 ms of execution time per message
- Support for only ECMAScript standard built-ins
- No calls to external APIs
- No imports of external libraries
Sample UDFs
Here are some sample UDFs for publishing and subscribing. You can find additional samples in the UDF library.
Function: Convert a day of the week integer to the corresponding string
When you add the following UDF to a topic or a subscription, the following changes take place during message publish or delivery:
Pub/Sub applies the function to the message. If the message does not have a JSON payload, the UDF throws an error.
The UDF looks for a field called
dayOfWeekand if the value of this field is a number between 0 and 6, converts it to a corresponding day of the week such asMonday. If the field does not exist or the number is not in the range of 0 to 6, the code sets thedayOfWeekfield toUnknown.The UDF serializes the modified payload back into the message.
Pub/Sub passes the updated message to the next step in your pipeline.
function intToString(message, metadata) {
const data = JSON.parse(message.data);
switch(`data["dayOfWeek"]`) {
case 0:
data["dayOfWeek"] = "Sunday";
break;
case 1:
data["dayOfWeek"] = "Monday";
break;
case 2:
data["dayOfWeek"] = "Tuesday";
break;
case 3:
data["dayOfWeek"] = "Wednesday";
break;
case 4:
data["dayOfWeek"] = "Thursday";
break;
case 5:
data["dayOfWeek"] = "Friday";
break;
case 6:
data["dayOfWeek"] = "Saturday";
break;
default:
data["dayOfWeek"] = "Unknown";
}
message.data = JSON.stringify(data);
return message;
}
Function: Redact a social security number
When you add the following UDF to a topic or a subscription, the following changes take place during message publish or delivery:
Pub/Sub applies the function to the message. If the message does not have a JSON payload, the UDF throws an error.
The UDF removes the field
ssnfrom the message payload (if it exists).The UDF serializes the modified payload back into the message.
Pub/Sub passes the updated message to the next step in your pipeline.
function redactSSN(message, metadata) {
const data = JSON.parse(message.data);
delete data['ssn'];
message.data = JSON.stringify(data);
return message;
}
Function: Filter out and auto-ack specific messages
When you add the following UDF to a topic or a subscription, the following changes take place during message publish or delivery:
Pub/Sub applies the function to the message. If the message does not have a JSON payload, the UDF throws an error.
The UDF checks if the payload contains a field called
region.If the value of the
regionfield is notUS, the function returns null, causing Pub/Sub to filter the message.If the value of the
regionfield isUS, Pub/Sub passes the original message to the next step in your pipeline.
function filterForUSRegion(message, metadata) {
const data = JSON.parse(message.data);
if (data["region"] !== "US") {
return null;
}
return message;
}
Function: Validate message content to ensure the amount is not greater than 100
When you add the following UDF to a topic or a subscription, the following changes take place during message publish or delivery:
Pub/Sub applies the function to the message. If the message does not have a JSON payload, the UDF throws an error.
The UDF checks if the message contains a field called
amount.If the value of the
amountfield is greater than100, the function throws an error.If the value of the
amountfield is not greater than100, the function returns the original message.Pub/Sub then either marks the message as failed, or passes the original message to the next step in your pipeline.
function validateAmount(message, metadata) {
const data = JSON.parse(message.data);
if (data["amount"] > 100) {
throw new Error("Amount is invalid");
}
return message;
}
What's next
Explore additional samples in the UDF library