Forum Academy Marketplace Showcase Pricing Features

Server-side actions plugins. OPEN BETA

Hello everyone,

One of the big missing pieces of our plugin system is the ability to run server-side code via actions. This will enable actions to manipulate data and more importantly return data that can be used in subsequent actions, for instance to save the result (currently, client-side actions do not offer the option ‘Result of previous step’ in the Composer dropdown in subsequent actions.

We’ve been working on this for a while and are now ready to open the beta to everyone. If you create an action in a plugin, you will be able to pick ‘Server-side’ as the action type.

(note the disclaimer here, I’ll talk a bit more about this important point at the end of this post).

Once you’ve picked this type for the action, you’ll be able to define what kind of data the action should return. It should return a flat JSON object, and you need to define first the keys and types for each key/value pair. For instance, this test plugin is designed to return an object as

in other words, your code defined in the run_server function should return an object such as, for instance,

{
     keya: "sample string"
     keyb: true
     keyc: [12, 67, 23, 69]
}

The captions for each keys are defined to look good in the editor, the object you return should use the key names. Here is what using such an action in your app would look like

IMPORTANT: this feature is in early public beta. It will only work on the development version of your app, for the authorized test application. Please do not use this for production, the feature and the API could change at any time.

Having said that, the more feedback we get from you guys, the faster it’ll get out of beta, so let us know how this goes!!

22 Likes

@levon - is this what you’ve been waiting for to allow us to produce a PDF without visiting the actual page?

Hi @emmanuel, this looks promising!

What libraries or modules can we use or load for the code, for example crypto functions?

I notice there is ‘request’, is this from node’s request module?

Will you be showing us a couple of examples?

This will definitely be handy in API workflows for more complex expressions and calculations.

1 Like

What happens if we manage to crash or exit the server process? Will it automatically get restarted?

We currently don’t expose libraries, but we’re looking into ways to add them on request or let people add them themselves. And yes, the request object is the one from node.

If the system crashes, it will fail and not rerun, but that’s typically the kind of things we’ll refine as we get more feedback and use cases.

4 Likes

@patricia
yes, but the server side code still doesn’t support use of third party libraries (correct @emmanuel ?) , so it wouldn’t be possible just yet.

For the curious, this is referring to the popular Request module; not Node’s default HTTP module. :wink:

Hi fellow bubblers,

I joined bubble last week and I’m glad to see support for server side actions, exciting times!

I gave it a shot and was able to make a first action that returned some hard coded values.

The next step was to try to sum up some values stored in the DB:

  1. Make a bubbly data api call
  2. Iterate over the results and keep a running total
  3. Return that total to display it in bubble

It looks like context.request is asynchronous so I tried to use the await keyword but that did cause a syntax error (This code cannot be interpreted as javascript)

I noticed the context did contain an async function but it takes a callback so that’s probably to start an async operation, not to wait for one?

Am I approaching this wrongly? Should I return some kind of promise that will eventually resolve?

function(properties, context) {
  
  var options = {
      url: 'https://myapp.bubbleapps.io/version-test/api/1.1/obj/job',
      headers: {
        // TODO: Auth
      }
	};

  var total = 0;
  function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
      var data = JSON.parse(body);
      
      for (var i = 0; i < data.response.results.length; i++) {
        var job = data.response.results[i];
      	total += job.amount_number;    
      }
    } else {
      total = -1;
    }
  }

  // Asynchronous call, won't be finished when we return
  context.request(options, callback);
  
  // This triggers a syntax error
  // async context.request(options, callback);
  
  var result = {
    total : 100 + total
  };
  
  return result;
}
1 Like

The documentation in the plugin editor states …

request: function(requestObject: Object) - node request function, returns the response synchronously

Which means the plugin architecture is doing the equivalent of an “await” for you, so all you need is:

options = …
response = context.request(options)
munch on response

3 Likes

Hi @mishav,

I see, I must have gotten confused with the request docs!

thanks, I’ll test this tonight :slight_smile:

Would this imply somehow that we can finally write code (e.g. Node.js) as if we were using servers on Heroku or AWS?

1 Like

Is this LIVE (Production) now or it is still in BETA phase?

Thanks

1 Like

Hey,

It is in production mode.

1 Like

Hey there!
I really need more documentation on ‘async’ and ‘request’ for server-side actions.
Where can I get it?

Is the deprecated request package still used?

1 Like

Looks like it

@mishav ,

I’m struggling with the bubble-specific syntax for this http request stuff, any help? My code seems to run but I’m just not getting a response when I check the INFO part of the logs.

As you can see I’ve tried multiple attempts to get the output showing.

function(properties, context) {


const options = {
url: 'https://connect.squareupsandbox.com/v2/locations/LK1SYRC0blah/checkouts',
method: 'POST',
headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer blahmLEl89prq blah b-DnafBhiJZmblah XypJDNoe1d'
},
body: JSON.stringify({
    idempotency_key: Math.random().toString(36).substr(2, 36)+Math.random().toString(36).substr(2, 36),
    order: {
        order: {
            location_id: "LK1SYRCblah",
            line_items: [{
                quantity: "1",
                base_price_money: {
                    amount: 1000,
                    currency: "GBP"
                },
                name: "test item"
            }]
        },
    }
})


};

let response = context.request(options, function (err, res, body) {
let json = JSON.parse(body);
console.log(json.checkout.checkout_page_url);
properties.url = json.checkout.checkout_page_url;
console.log(response.body);
});

console.log('got here');

}