An easy-to-use Back-end-as-a-service (BaaS) can make rapidly developing your app not only a possibility, but an enjoyable experience. A good BaaS will work for simple "CRUD-based" (or "forms-over-data") apps as well as more complicated scenarios. The trouble is that when your app outgrows the simpler scenarios, you often need "hooks" on the server side for things like validation, record transformation and more. When you're using Everlive, this is where "Cloud Code" comes in.
"Cloud Code" enables you to execute JavaScript before or after "CRUD" (Create-Read-Update-Delete) operations in Everlive. So that means the following events have hooks to where you can execute "Cloud Code":
(Sensing a pattern here? :-))
As you'd expect, any of the Before events are executed before the request is processed. Conversely, any After events are executed after the request has been processed.
These CRUD hooks are available on any Content Type you create (as well as the built-in Users Content Type).
While you can upload JavaScript files to Everlive, most of the time (at least initially), you will be using Everlive's web interface to add cloud code. To use the web interface, simply follow these steps:
You'll then see a code editor open, pre-populated with the Everlive Cloud Code event hooks:
If this is the first time you've edited Cloud Code for this Content Type, you'll see the following JavaScript stubbed out for you:
Everlive.Events.beforeRead(function(request, context, done) { //Enter your custom code here //Call done() once you are finished done(); }); Everlive.Events.afterRead(function(request, response, context, done) { done(); }); Everlive.Events.beforeCreate(function(request, context, done) { done(); }); Everlive.Events.afterCreate(function(request, response, context, done) { done(); }); Everlive.Events.beforeUpdate(function(request, context, done) { done(); }); Everlive.Events.afterUpdate(function(request, response, context, done) { done(); }); Everlive.Events.beforeDelete(function(request, context, done) { done(); }); Everlive.Events.afterDelete(function(request, response, context, done) { done(); });
Looking at the above code, we can see that:
request
, context
and done
.request
, response
, context
and done
.done
argument to the callbacks is itself a callback that you should invoke when your logic is complete. This is how you tell Everlive that it can move on and finish processing the request (not invoking it will result in your request timing out!).For both types of events, the request
argument contains data about the current request, and the context
argument is used to pass data from a "before" event (ex. - beforeRead) to the corresponding "after" event (ex - afterRead). The response
argument in an "after" event is exactly that - the response Everlive is returning to the client.
Enough talk - let's see this in action.
Bordering on the "contrived" side of examples (let's roll with it, though), let's pretend we have a content type that includes a field to store a country code, and we want to ensure that it's always upper-case (of course, we could do this on the client instead/as well). It's as simple as editing the beforeCreate
hook as follows:
Everlive.Events.beforeCreate(function(request, context, done) { if(request.data.CountryCode) { request.data.CountryCode = request.data.CountryCode.toUpperCase(); } done(); });
Easy, huh?
So - let's say it's a Monday for you and you're really tired of people not including a valid country code. You know it might be a bit harsh, but the power of Cloud Code is at your fingertips, so you decide to cancel requests that do not contain a country code:
Everlive.Events.beforeCreate(function(request, context, done) { if(!request.data.CountryCode) { Everlive.Request.cancel(); } done(); });
After your badly needed Monday morning coffee, you realize that cancelling requests missing a country code was a bit severe. Instead, you decide to modify the response returned to the client by adding a message that your client-side framework can interpret in order to show a friendly notification to the user:
Everlive.Events.beforeCreate(function(request, context, done) { if(!request.data.CountryCode) { context.missingCountryCode = true; } done(); }); Everlive.Events.afterCreate(function(request, response, context, done) { if(context.missingCountryCode) { response.additionalData.message = "Show some national pride and include your country code sometime!"; } done(); });
In the above example, we used the context
argument of our beforeCreate
event to pass information on to our afterCreate
event (in this case, if they left of the country code we set missingCountryCode
to true
). For any users that leave off the country code, the response to their request will include a message
property (in addition to the usual Result
property) that contains the string message above.
I know, right? The Country Code example was just to whet your appetite. You can do record transformation and validation inside Everlive's Cloud Code hooks if you like, but there are other use cases that you may run across first.
You can provide querying expressions in a beforeRead
hook to customize how/what gets returned to the client. For example, this would only return the UserName and CountryCode fields (in addition to the ID, which is always returned):
Everlive.Events.beforeRead(function(request, context, done) { request.fieldsExpression = { UserName : 1, CountryCode : 1 }; done(); });
Maybe you'd like to sort the results by CountryCode before returning it to the client - no problem!
Everlive.Events.beforeRead(function(request, context, done) { request.sortExpression = { CountryCode : 1 }; done(); });
Aside from sorting and limiting results to certain fields, several other query expressions are supported. See the docs for more info on querying.
It's very possible that you'll run into a situation where you need to call out to an external web service from within your Cloud Code. You can so this by using the Everlive.HTTP.request(method, url, options, callback)
method in your code cloud:
Everlive.Events.beforeRead(function(request, context, callback) { Everlive.Http.request('GET', 'http://some/external/api', {}, function(error, response) { if(error){ request.data.error = error; } else { request.data.otherInfo = response; } done(); }); });
Everlive.Http
also provides convenience methods (get
, post
, delete
, and put
), so the above snippet could be changed to:
Everlive.Events.beforeRead(function(request, context, callback) { // signature is get(url, options, calback) Everlive.Http.get( 'http://some/external/api', {}, function(error, response) { if(error){ request.data.error = error; } else { request.data.otherInfo = response; } done(); }); });
Just be careful, though - Cloud Code execution needs to happen in 5 seconds or less - otherwise a timeout will occur. Slow external services will definitely put you at risk here.
We've just covered a few examples of how Cloud Code can be useful to you. I highly recommend checking out our documentation for even more examples. It covers things like using Cloud Code to send emails & SMS messages, as well as sending custom data in HTTP Headers from your client that can be used in special logic in Cloud Code.
Everlive has a lot of flexibility and power available to you - and no doubt a feature like Cloud Code will come into play as your needs grow. The fact that there are Everlive SDKs for .NET, JavaScript, Windows Phone and iOS clients means that your needs can grow across multiple platforms, all easily sharing data and Cloud Code logic.
Jim Cowart is an architect, developer, open source author, and overall web/hybrid mobile development geek. He is an active speaker and writer, with a passion for elevating developer knowledge of patterns and helpful frameworks.