- Example CloudMine Server Code Snippet
- Implementation Notes
This is an example of how to structure your NodeJS project for deployment and execution on CloudMine's Logic Engine.
The lib folder contains Snippets which are just pieces of NodeJS code. The index.js file is responsible for starting a mini-web server which routes inbound Snippet requests, as well as collating and exposing the named methods which form the basis of your CloudMine API.
- In
index.js, themodule.exportscall must occur before the.startmethod is called, otherwise Logic Engine will not be able to identify public snippets available for invocation. CloudMineNode.startrequires the current scope, the root file, and has a callback to let you know when the package is ready for inbound requests.
In order to run your CloudMine Snippets locally, please follow the below instructions:
- Ensure that all NPM module dependencies are defined in
package.json. - Run
npm installfrom the project's root directory to ensure that the dependencies are included into the project. - Next, run
npm startto start the server from the command line. - Finally,
curl,wget, or use your favorite method of running HTTP commands using the below examples.
Request:
localhost:4545/names
Response:
["basic","async"]
Request:
localhost:4545/v1/app/{appid}/run/basic
Response:
{"success":"Basic was called"}
Historically, CloudMine snippets use the data environment variable, and the exit function in order to reply to inbound requests. With Logic Engine, both a new environment variable and exit function are included: req and reply, respectively.
console.log(req.payload.request.method);
Output:
POST
console.log(req.payload.request.body);
Output:
{ objId: { key1: 'value1', key2: 'value2' } }
console.log(req.payload.request.headers);
Output:
{ x-cloudmine-apikey: 'myapikey', x-custom-header: 'mycustomheader' }
console.log(req.payload.params);
Output:
{ objId: { key1: 'param1', key2: 'param2' },
queryStringParam1: 'queryStringValue1',
queryStringParam2: 'queryStringValue2' }
console.log(req.payload.request.originating_ip)
Output:
166.171.56.242
console.log(req.payload.session)
Output:
{ api_key: '4fb3caf6fa53442fb921dd93ae0c98e6',
app_id: '3f4501961d62bc4eb388d9dc6dfdd1e5',
session_token: '6c160b8140fc43e28ff9bf7bb00f198e',
user_id: 'bd027836e4744391ba2aabf6aacdc828' }
Note: in order for the session_token and user_id values to populate, the X-CloudMine-SessionToken request header must be present in the original request and the session_token must be valid.
process.env.CLOUDMINE may be used to determine whether the code is running locally (false) or in the CloudMine Logic Engine environment (true). Example usage is below:
var isCloud = process.env.CLOUDMINE;
var local_config = {};
local_config = {
"api_key":"localEnvApiKey",
"app_id":"localAppId"
};
var ApiKey = isCloud ? req.payload.session.api_key : local_config.api_key;
var AppId = isCloud ? req.payload.session.app_id : local_config.app_id;
console.log(req.payload.request.headers)
Output:
{
"host": "api.cloudmine.me",
"x-real-ip": "10.45.1.56",
"x-forwarded-for": "108.16.228.74, 127.0.0.1, 10.45.1.56",
"connection": "close",
"user-agent": "curl/7.51.0",
"accept": "*/*",
"content-type": "application/json",
"x-cloudmine-apikey": "3e3f6e4796b745c78f2769a93ca1d08e",
"x-forwarded-proto": "https",
"x-ssl-version": "TLSv1.2",
"x-ssl-cipher": "ECDHE-RSA-AES128-GCM-SHA256",
"x-unique-id": "7F000001:988A_7F000001:22B8_59400240_0C66:250A",
"my-custom-header: true"
}
There are two types of values that may be passed into the reply function: Strings and Ints as well as JSON objects.
When using the reply function with only a String or Integer, the value will be returned as part of the result key.
Example:
var a = 6;
reply(a);
or
var b = "This is a string!";
reply(b);
Output:
{
"result": 6
}
or
{
"result": "This is a string!"
}
When replying with a JSON shape, the contents of the object will be nested within the result shape.
Example:
setTimeout(function() {
reply({text: 'This took 5 seconds!'});
}, 5000);
Output:
{
"result": {
"text": "This took 5 seconds!"
}
}
There are options that can be used to control the response from the snippet beyond the reply interface.
By specifying unwrap_result=true in the query string of the snippet execution request, the output of the snippet will not be wrapped in a result attribute.
Suppose you have a snippet that calls reply('I called a snippet!') to complete execution. With the default behavior the response payload would be:
{
"result": "I called a snippet!"
}
By specifying unwrap_result=true in the query string of the snippet request the response payload will become:
I called a snippet!
The Accept header can be used in the snippet execution request to change the Content-Type header of the response as well as the format of the payload. There are two supported values for the Accept header:
text/plainapplication/xml
If text/plain is used, the payload does not change as all json payloads are already delivered as text, but the Content-Type on the response will be set to text/plain.
If application/xml is used the payload will be converted to XML based on the rules below, and the Content-Type on the response will be set to application/xml.
Any other value in the Accept header will be ignored and the Content-Type on the response will be application/json.
- Object property names will become XML tags that wrap the value of that property
- Properties with values null, undefined, or empty string will be represented with an empty tag (e.g.
<Name/>) - Each element in an array will be wrapped in an
<element>tag
If you would have received a JSON response such as:
{
result: {
str: "a string",
bool: true,
num: 1289,
arr: ['uno', 2, false],
empty: '',
undef: undefined
}
}
as XML it would become:
<?xml version="1.0" encoding="UTF-8" ?>
<result>
<str>a string</str>
<bool>true</bool>
<num>1289</num>
<arr>
<element>uno</element>
<element>2</element>
<element>false</element>
</arr>
<empty/>
<undef/>
</result>
The unwrap_result query param and the Accept header can be combined to have any plain text response that you would like. For example, if you would like to create an XML output that does not use the same rules as described above you could build this XML as a string in the snippet. If you pass the unwrap_result query param to the request and simultaneously specify application/xml or text/plain in the Accept header you will receive the exact XML string you output in your snippet. Note that if your snippet output is any non-object, non-array value and application/xml is specified in the Accept header, no transformation or validation will be done on the value. CloudMine assumes you are doing this purposefully and it is up to you to ensure the XML is valid.
When uploading your ZIP package to CloudMine's servers, please be sure that:
- the
node_modulesfolder is removed, and - all
.gitfiles are removed
To help with this process, we have included a ZIP CLI example below:
zip -r code.zip code-folder/ -x *.git* -x *node_modules*
Notes
code.ziprefers to the final package namecode-folderrefers to the root folder of the package