Custom script examples
Last updated
Last updated
This page includes scripts that may be useful either in and of themselves or as a starting point for your own scripting work:
This script takes an XML input string, loads it into an XmlDocument
, and then converts that XML to a JSON string using the Newtonsoft.Json
library.
using System;
using System.Xml;
using Newtonsoft.Json;
public class FunctionHandler
{
public string Handle(string input)
{
var xmlDoc = new XmlDocument();
// Set up XML namespace manager
var namespaceManager = new XmlNamespaceManager(xmlDoc.NameTable);
namespaceManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
namespaceManager.AddNamespace("", "http://api.jdplc.com/schemas/mc/pim/feproducts");
// Load the XML string into XmlDocument
xmlDoc.LoadXml(input);
// Convert the XML to JSON
string jsonText = JsonConvert.SerializeXmlNode(xmlDoc, Newtonsoft.Json.Formatting.Indented, true);
return jsonText;
}
}
The script below demonstrates the handling of variables, logging, updating response codes, and modifying payloads.
The script below demonstrates how to convert a JSON file to XML, using JavaScript.
The script below demonstrates how to convert a CSV file to JSON, using Python.
The script below demonstrates how helper functions can be used, with the handle()
function acting as the main driver.
package function
import (
"encoding/json"
"fmt"
)
type Variables map[string]string
func (v *Variables) UnmarshalJSON(bytes []byte) error {
if string(bytes) == "[]" {
*v = make(Variables)
} else {
d := make(map[string]string)
err := json.Unmarshal(bytes, &d)
if err != nil {
return err
}
*v = d
}
return nil
}
type Request struct {
Payload string `json:"payload"`
Variables Variables `json:"variables,omitempty"`
Flow Flow `json:"flow,omitempty"`
ResponseCode int `json:"response_code,omitempty"`
Message string `json:"message,omitempty"`
Logs []string `json:"logs,omitempty"`
}
func (r *Request) GetVariable(name string) (string, bool) {
if r.Variables == nil {
return "", false
}
value, ok := r.Variables[name]
return value, ok
}
func (r *Request) AddLog(log string) {
r.Logs = append(r.Logs, log)
}
func (r *Request) DeserializePayload() (interface{}, error) {
var payload interface{}
err := json.Unmarshal([]byte(r.Payload), &payload)
if err != nil {
return nil, err
}
return payload, nil
}
type Flow struct {
Variables Variables `json:"variables"`
}
func (f *Flow) GetVariable(name string) (string, bool) {
if f.Variables == nil {
return "", false
}
value, ok := f.Variables[name]
return value, ok
}
// Handle
// handles a serverless request
// example payload:
//
// {
// "payload": "",
// "meta": null,
// "variables": [],
// "flow": {
// "variables": []
// },
// "response_code": 0,
// "message": "",
// "logs": []
// }
func Handle(request []byte) (string, error) {
r := &Request{}
err := json.Unmarshal(request, r)
if err != nil {
return "", fmt.Errorf("failed to deserialize request: %s", err)
}
if r.Variables != nil && len(r.Variables) > 0 {
for k, v := range r.Variables {
r.AddLog(fmt.Sprintf("variable: %s=%s", k, v))
}
} else {
r.AddLog("no variables")
}
if r.Flow.Variables != nil && len(r.Flow.Variables) > 0 {
for k, v := range r.Flow.Variables {
r.AddLog(fmt.Sprintf("flow variable: %s=%s", k, v))
}
} else {
r.AddLog("no flow variables")
}
r.ResponseCode = 12
r.AddLog("updated response code")
r.Variables["key1"] = "value1"
r.Variables["key2"] = "value2"
r.AddLog("added 2 variables (key1, key2)")
var p interface{}
if p, err = r.DeserializePayload(); err != nil {
return "", fmt.Errorf("failed to deserialize payload: %s", err)
}
var ok bool
var m map[string]interface{}
if m, ok = p.(map[string]interface{}); !ok {
r.Payload = "not a json object"
} else {
m["key1"] = "value1"
m["key2"] = "value2"
var result []byte
result, err = json.Marshal(m)
if err != nil {
return "", fmt.Errorf("failed to serialize payload: %s", err)
}
r.Payload = string(result)
}
d, err := json.Marshal(r)
if err != nil {
return "", err
}
return string(d), nil
}
/**
* @param data
* @param {string} data.payload the payload as a string|null
* @param {Object.<string, any>} data.variables any variables as key/value
* @param {Object.<string, any>} data.meta any meta as key/value
*/
module.exports = async function (data) {
var obj = JSON.parse(data.payload)
function jsonToXml(jsonObj, rootName = 'root') {
let xml = '';
const buildXml = (obj, parentName) => {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key];
if (typeof value === 'object') {
xml += `<${key}>`;
buildXml(value, key);
xml += `</${key}>`;
} else {
xml += `<${key}>${value}</${key}>`;
}
}
}
};
xml += `<?xml version="1.0" encoding="UTF-8"?>`;
xml += `<${rootName}>`;
buildXml(jsonObj, rootName);
xml += `</${rootName}>`;
return xml;
}
const xmlData = jsonToXml(obj, 'data');
const jsonString = JSON.stringify(xmlData);
return {"payload":jsonString};
};
<?php
function handle($data) {
// Decode the JSON string into an array
$dataArray = json_decode($data['payload'], true);
if ($dataArray === null) {
// JSON decoding failed
return 'Failed to decode JSON.';
}
// Create an empty array to store the CSV rows
$csvRows = [];
// Add the CSV headers
if (!empty($dataArray)) {
$headers = array_keys($dataArray[0]);
$csvRows[] = $headers;
}
// Add the CSV rows
foreach ($dataArray as $row) {
$csvRows[] = array_values($row);
}
// Generate the CSV string
$csvString = '';
foreach ($csvRows as $row) {
$csvString .= implode(',', $row) . "\n";
}
// Return the CSV string or error message
return ['payload' => !empty($csvString) ? $csvString : 'Failed to convert JSON to CSV'];
}
# class Request:
# """
# The class representing the request.
# Attributes
# ----------
# payload : str
# the payload as a string or null
# variables : object
# any variables as key/value
# meta : object
# any meta as key/value
# """
def handle(req):
import json, io, csv
data = json.loads(req)
reader = csv.DictReader(io.StringIO(data['payload']), delimiter=';')
json_data = json.dumps(list(reader))
return json.dumps({'payload':json_data})
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use crate::GenericError;
use serde::de::{Deserializer, Error as SerdeError, Unexpected};
/// Custom deserializer that converts `[]` into `{}` (empty HashMap)
fn deserialize_variables<'de, D>(deserializer: D) -> Result<HashMap<String, String>, D::Error>
where
D: Deserializer<'de>,
{
match Value::deserialize(deserializer)? {
Value::Object(map) => {
let mut hashmap = HashMap::new();
for (key, value) in map {
if let Value::String(s) = value {
hashmap.insert(key, s);
} else {
return Err(D::Error::custom(format!(
"Expected string values in HashMap, found: {:?}",
value
)));
}
}
Ok(hashmap)
}
Value::Array(arr) if arr.is_empty() => Ok(HashMap::new()), // Convert `[]` to `{}`
other => Err(D::Error::invalid_type(
Unexpected::Other(&format!("{:?}", other)),
&"a map of strings or an empty array",
)),
}
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct RequestBody {
pub payload: Option<String>,
pub meta: Vec<Value>,
#[serde(default, deserialize_with = "deserialize_variables")]
pub variables: HashMap<String, String>,
pub flow: FlowData,
#[serde(default)] // Default value if missing
pub response_code: i32,
#[serde(default)] // Default empty string if missing
pub message: String,
#[serde(default)] // Default empty list if missing
pub logs: Vec<String>,
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct FlowData {
#[serde(default, deserialize_with = "deserialize_variables")]
pub variables: HashMap<String, String>,
}
#[allow(dead_code)]
impl RequestBody {
/// Creates a new `RequestBody` with default values
pub fn new() -> Self {
Self {
payload: None,
meta: Vec::new(),
variables: HashMap::new(),
flow: FlowData {
variables: HashMap::new(),
},
response_code: 0,
message: String::new(),
logs: Vec::new(),
}
}
/// Create a `RequestBody` from `Bytes`
pub fn from_bytes(body_bytes: Bytes) -> Self {
let body_str = String::from_utf8_lossy(&body_bytes);
println!("Received body: {}", body_str); // Debugging output
match serde_json::from_slice(&body_bytes) {
Ok(body) => body,
Err(err) => {
println!("Deserialization error: {}", err); // Print exact deserialization error
let mut default_body = Self::new();
default_body.add_log("Failed to deserialize RequestBody; using default.");
default_body
}
}
}
/// Add a log entry
pub fn add_log(&mut self, message: &str) {
self.logs.push(message.to_string());
}
/// Get the payload as a `String`
pub fn get_payload(&self) -> Option<&String> {
self.payload.as_ref()
}
/// Set a new payload
pub fn set_payload(&mut self, payload: &str) {
self.payload = Some(payload.to_string());
self.add_log(&format!("Payload set to: {}", payload));
}
/// Deserializes the payload into a generic struct if the payload is present and valid JSON
pub fn deserialize_payload<T: for<'de> serde::Deserialize<'de>>(&self) -> Option<T> {
match &self.payload {
Some(payload) if !payload.trim().is_empty() => {
match serde_json::from_str::<T>(payload) {
Ok(deserialized) => Some(deserialized),
Err(err) => {
eprintln!("Failed to deserialize payload: {}", err);
None
}
}
}
_ => {
// Log explicitly that the payload was empty or null
println!("Skipping deserialization: payload is null or empty.");
None
}
}
}
/// Serialize and update the payload from a given struct
pub fn update_payload<T: serde::Serialize>(&mut self, new_payload: &T) {
match serde_json::to_string(new_payload) {
Ok(serialized) => {
self.payload = Some(serialized);
self.add_log("Payload updated successfully.");
}
Err(err) => {
eprintln!("Failed to serialize new payload: {}", err);
self.add_log("Failed to update payload.");
}
}
}
/// Iterate over variables
pub fn variables_iter(&self) -> impl Iterator<Item = (&String, &String)> {
self.variables.iter()
}
/// Add a variable
pub fn add_variable(&mut self, key: &str, value: &str) {
self.variables.insert(key.to_string(), value.to_string());
self.add_log(&format!("Variable added: {} = {}", key, value));
}
/// Get a variable by key
pub fn get_variable(&self, key: &str) -> Option<&String> {
self.variables.get(key)
}
/// Add a flow variable
pub fn add_flow_variable(&mut self, key: &str, value: &str) {
self.flow.variables.insert(key.to_string(), value.to_string());
self.add_log(&format!("Flow variable added: {} = {}", key, value));
}
/// Get a flow variable by key
pub fn get_flow_variable(&self, key: &str) -> Option<&String> {
self.flow.variables.get(key)
}
/// Clear all logs
pub fn clear_logs(&mut self) {
self.logs.clear();
self.add_log("Logs cleared.");
}
/// Reset all variables
pub fn reset_variables(&mut self) {
self.variables.clear();
self.add_log("All variables cleared.");
}
}
#[derive(Deserialize, Serialize, Debug)]
struct CustomPayload {
test: bool,
name: Option<String>,
}
#[allow(unused_mut)]
pub fn handle(body_bytes: Bytes) -> Result<Bytes, GenericError> {
// Deserialize bytes into the `RequestBody` struct
let mut body = RequestBody::from_bytes(body_bytes);
// Check if payload exists and is non-empty before deserializing
if let Some(payload) = &body.payload {
if !payload.trim().is_empty() {
// Attempt to deserialize the payload into `CustomPayload`
if let Some(mut custom_payload) = body.deserialize_payload::<CustomPayload>() {
body.add_log(&format!("Deserialized payload: {:?}", custom_payload));
// Modify the payload
custom_payload.test = !custom_payload.test;
custom_payload.name = Some("Updated Name".to_string());
// Serialize the updated payload back to JSON
body.update_payload(&custom_payload);
} else {
body.add_log("Failed to deserialize payload.");
}
} else {
body.add_log("Payload is empty, skipping deserialization.");
}
} else {
body.add_log("Payload is null, skipping deserialization.");
}
// Add and retrieve variables
body.add_variable("Key1", "Value1");
body.add_variable("Key2", "Value2");
// Collect variables into a temporary Vec to avoid borrowing conflicts
let variables: Vec<(String, String)> = body
.variables_iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect();
for (key, value) in variables {
body.add_log(&format!("Iterated variable: {} = {}", key, value));
}
// Serialize the updated body back to JSON and return
let response_body = serde_json::to_vec(&body).unwrap();
Ok(Bytes::from(response_body))
}