Server-side Plugin - Pre-Request Script

Hi There;

Do you have any information about the pre-request script? The following questions and answers are passed between the developer, me and some bubble staff. Somehow the developer couldn’t solve the problem. Is there anyone who can help?

Dev.

I have tried several alternative to make the plugin in bubble but since Iyzico API, is having pre-request script, this script is executed before API call. But in bubble there is no support for a pre-request script.

Bubble
Thanks for reaching out. Plugins have an object called ‘context’ with some Bubble utilities. For example context.async – call context.async with a function that kicks off an asynchronous operation, taking a callback taking (err, res). Returns res or else throws error. Would that way of doing a callback work for your use case?

Dev
I am developing a bubble plugin for a payment gateway, but before running an API call there is a pre-request script that is executed , this script provides the Authorization header value.

But I am not understanding where should I put the script in the plugin editor and get value of the API Authorization header in the API section of the plugin editor.

Bubble

f your question is more around the plugin editor, you can add a server-side action (snapshot below) with the custom script to return a value then use that in the next step which is an API call defined in the API tab of the plugin editor as an action.

Dev
I need to add the following script -
"
var apiKey = “sandbox-pvY8iL8GbralWyf3rbzqqvP0SSouP6sQ”;
var secretKey = “sandbox-cVojNOhBjRqVjhhOThOFfv4cy35zKmC5”;

function nullClear(obj){
for (var member in obj) {

    if(obj[member] === null) {    
        delete obj[member];
    }
    else if (typeof obj[member] === 'object'){
        obj[member]=nullClear(obj[member]);
        if(Object.keys(obj[member]).length===0){
            delete obj[member];
        }
    }
}

return obj;

}

function jsonToObj(jsonString, obj) {
var parsedJsonString = JSON.parse(jsonString);
for(var key in parsedJsonString) {
if(parsedJsonString.hasOwnProperty(key)) {
if (typeof parsedJsonString[key] === ‘object’) {
if(Array.isArray(parsedJsonString[key])){
for(var i = 0; i < parsedJsonString[key].length; i++){
if(key ==“basketItems”){
obj[key].push(new BasketItem());
obj[key][i]=jsonToObj(JSON.stringify(parsedJsonString[key][i]), obj[key][i]);
}else {
obj[key][i] = parsedJsonString[key][i];
}
}
}else{
obj[key] = jsonToObj(JSON.stringify(parsedJsonString[key]), obj[key]);
}
}else{
obj[key] = parsedJsonString[key];
}

    }
}
obj = nullClear(obj);

return obj;

}

function generateRequestString(obj) {
var isArray = Array.isArray(obj);

var requestString = '[';
for (var i in obj) {
    var val = obj[i];
    if (!isArray) {
        requestString += i + '=';
    }
    if (typeof val === 'object') {
        requestString += generateRequestString(val);
    } else {
        requestString += val;
    }
    requestString += isArray ? ', ' : ',';
}
requestString = requestString.slice(0, (isArray ? -2 : -1));
requestString += ']';
return requestString;

}

function generateAuthorizationString(obj) {
var requestString = generateRequestString(obj);
var hashSha1 = CryptoJS.SHA1(apiKey+request.headers[“x-iyzi-rnd”]+secretKey+requestString);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hashSha1);
var authorization = “IYZWS”+" “+apiKey+”:"+hashInBase64;
postman.setGlobalVariable(“pkiString”, apiKey+request.headers[“x-iyzi-rnd”]+secretKey+requestString);
console.log(authorization,“authorization”);
return authorization;
}

var checkoutFormRetrieve = {
locale: null,
conversationId: null,
token: null
};

var requestModel = checkoutFormRetrieve;
requestModel = jsonToObj(request.data, requestModel);
var authorization = generateAuthorizationString(requestModel);
postman.setEnvironmentVariable(“authorization”, authorization);
"
This script generates the authorization header, that I want to use in API calls. But I dont know how to implement this.

Bubble
I checked with our engineering team and they recommended not using the API tab in the plugin editor for this and instead use the plugin actions tab with a server side action. This method will give you access to the request object.

Dev
I have analysed, the server side action in the plugin editor. And tried to apply the API. But I am not able to find out how to run the pre-request script in server side action, and after the script is applied then how use the authorization in the plugin API call. Since the pre-request script is executed prior to the API call is made and then the authorization value is returned to API call header, and then using the value the API call is made. But in bubble I am not able to understand, how to apply the pre-request script and get the authorization value and pass it to the API call header.

I’d be more than happy to help anyone with this information.
Please help

Eren

If I’m understanding correctly, you need to combine IYZWS + apiKey + base64 string to give you an Authorization key string. Is that correct?

Do you already have all of the necessary data, or do you have to make a call to get extra data before generating the Authorization key?

Hi @Kfawcett

When I couldn’t get an answer from here, I asked about it somewhere else. From there the questions and answers are as follows. I also invite the developer. Thank you for your interest

@himanshu.s

It’s best to use one post to get an answer. @ mention someone if you think they could help in this post instead of posting in other topics.

@himanshu.s could you please answer my questions above?

1 Like

I can get the API key and IYZWS, but for base64 we need to apply some encryption technique, and I want to prepare the script for the same and execute it in bubble plugin editor to get the Authorisation key necessary for making API call.

There’s a few different ways you could encode the string before using the API call. Two that I have used in the past are:

  1. Create another API, outside of the API you’re building for the payment gateway, that calls a Webtask.

Before Bubble allowed us to build server-side plugins, the only way for us to perform logic like this was by creating it in something like Webtask.io or AWS Lamba and creating an API to call that service and process the data.

Here is one I built for creating an encode string for a Cryptocurreny exchange at Webtask.io.

   /**
* @param context {WebtaskContext}
*/
module.exports = function(context, req, res) {
  var crypto = require('crypto');
  var secret = context.data.secret;
  var timestamp = context.data.timestamp;
  var requestPath = context.data.requestPath;
  var method = context.data.method;
  
  var what = timestamp + method + requestPath;
  var key = Buffer(secret, 'base64');
  var hmac = crypto.createHmac('sha256', key);
  var message = hmac.update(what).digest('base64');
  var getMessageObj = {
    // having to combine the timestamp and message. I'm using regex find/replace in Bubble to split these into the two fields
    "result": message
  };
  
  
  res.writeHead(200, {'Content-Type' : 'application/json'});
  switch(req.method){
    case 'GET':
      res.end(JSON.stringify(getMessageObj));
      break;
      case 'POST':
        res.end(JSON.stringify(postMessageObj));
      break;
  }
  res.end(message);
};

And here is the API a created on the Bubble side

Then I would use the returned value from the above API in the second plugin that I built.

In your Bubble workflow editor, as your first step, you would make a call to the first API to create the encoded string, then your second step would call the second API and in whatever field it needs to go in you would put “Result of Step 1”.

  1. Now that Bubble allows you to build server side plugins. You could build a plugin to handle the encoding.

Here is one such plugin that I built, and is available for you to review since I release it as open source. It’s fairly simple and you could do something similar.
image

It has one input field and one output field.

So in your Bubble workflow it would look like this.

2 Likes

How, to make this script, functional using your technique-
"var apiKey = “sandbox-RBOqEKtbc8L7iyqyrq903tSSSJV1HRzj”;
var secretKey = “sandbox-Fz7DTQ2IqaxbOSnXwHIhRic86qAwl6yE”;

function nullClear(obj){
for (var member in obj) {

    if(obj[member] === null) {    
        delete obj[member];
    }
    else if (typeof obj[member] === 'object'){
        obj[member]=nullClear(obj[member]);
        if(Object.keys(obj[member]).length===0){
            delete obj[member];
        }
    }
}

return obj;

}

function jsonToObj(jsonString, obj) {
var parsedJsonString = JSON.parse(jsonString);
for(var key in parsedJsonString) {
if(parsedJsonString.hasOwnProperty(key)) {
if (typeof parsedJsonString[key] === ‘object’) {
if(Array.isArray(parsedJsonString[key])){
for(var i = 0; i < parsedJsonString[key].length; i++){
if(key ==“basketItems”){
obj[key].push(new BasketItem());
obj[key][i]=jsonToObj(JSON.stringify(parsedJsonString[key][i]), obj[key][i]);
}else {
obj[key][i] = parsedJsonString[key][i];
}
}
}else{
obj[key] = jsonToObj(JSON.stringify(parsedJsonString[key]), obj[key]);
}
}else{
obj[key] = parsedJsonString[key];
}

    }
}
obj = nullClear(obj);

return obj;

}

function generateRequestString(obj) {
var isArray = Array.isArray(obj);

var requestString = '[';
for (var i in obj) {
    var val = obj[i];
    if (!isArray) {
        requestString += i + '=';
    }
    if (typeof val === 'object') {
        requestString += generateRequestString(val);
    } else {
        requestString += val;
    }
    requestString += isArray ? ', ' : ',';
}
requestString = requestString.slice(0, (isArray ? -2 : -1));
requestString += ']';
return requestString;

}

function generateAuthorizationString(obj) {
var requestString = generateRequestString(obj);
var hashSha1 = CryptoJS.SHA1(apiKey+request.headers[“x-iyzi-rnd”]+secretKey+requestString);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hashSha1);
var authorization = “IYZWS”+" “+apiKey+”:"+hashInBase64;
postman.setGlobalVariable(“pkiString”, apiKey+request.headers[“x-iyzi-rnd”]+secretKey+requestString);
return authorization;
}

var buyer = {
id: null,
name: null,
surname: null,
identityNumber: null,
email: null,
gsmNumber: null,
registrationAddress: null,
city: null,
country: null,
ip: null
};

var shippingAddress = {
address: null,
contactName: null,
city: null,
country: null
};

var billingAddress = {
address: null,
contactName: null,
city: null,
country: null
};

var basketItem = {
id: null,
price: null,
name: null,
category1: null,
itemType: null,
subMerchantKey:null,
subMerchantPrice: null
};

function BasketItem() {
this.id= null;
this.price= null;
this.name=null;
this.category1= null;
this.itemType=null,
this.subMerchantKey=null;
this.subMerchantPrice= null;
}

var basketItems = [];

var enabledInstallments = [];

var checkoutFormInitialize = {
locale: null,
conversationId: null,
price: null,
installment: null,
basketId: null,
paymentGroup: null,
buyer: buyer,
shippingAddress: shippingAddress,
billingAddress: billingAddress,
basketItems: basketItems,
callbackUrl:null,
paymentSource:null,
currency: null,
paidPrice: null,
cardUserKey: null,
enabledInstallments: enabledInstallments
};

var requestModel = checkoutFormInitialize;
requestModel = jsonToObj(request.data, requestModel);
var authorization = generateAuthorizationString(requestModel);
postman.setEnvironmentVariable(“authorization”, authorization);
console.log(“authorization”,authorization);"
for base64 encryption do I need to use your plugin, or need to make one for mine usage.

1 Like