BlueNimble Developer Guide

Create an Api project

Description

You can either use BlueNimble CLI or create the structure of the api project manually

Create an Api project using the iCli

# let's create an api project for our application 'travel'
bluenimble:.> create api travel

    o Api 'travel' created! path: $ws/ travel
    -------------------------------------------
    {
        "namespace": "travel",
        "name": "travel api",
        "description": "travel description",
        "runtime": {
            "script": "scripts/Api.js"
        },
        "spi": {
            "class": "scripting.javascript:ApiSpi"
        }
    }


    Info | security scheme 'token' added to api 'travel'


    Info | security scheme 'cookie' added to api 'travel'


    o Api 'travel' updated spec
    -----------------------------
    {
        "namespace": "travel",
        "name": "travel api",
        "description": "travel description",
        "runtime": {
            "script": "scripts/Api.js"
        },
        "spi": {
            "class": "scripting.javascript:ApiSpi"
        },
        "security": {
            "schemes": {
                "token": {
                    "auth": {
                        "bucket": "security.tokens"
                    }
                },
                "cookie": {
                    "auth": {
                        "bucket": "security.tokens"
                    }
                }
            }
        }
    }


    /--> 'Signup' Service
    |
    +--+   spec file created 'services/security/Signup.json'


    Imporant | An activation email html file was created! 'templates/emails/signup.html' It's used by the Signup service
            Make sure that the email feature is added to your space in order to send emails.
            Use command 'add feature' to add an smtp server config


    /--> 'Activate' Service
    |
    +--+   spec file created 'services/security/Activate.json'


    /--> 'Login' Service
    |
    +--+   spec file created 'services/security/Login.json'


    /--> 'ChangePassword' Service
    |
    +--+   spec file created 'services/security/ChangePassword.json'


    /--> 'OAuth' Service
    |
    +--+   spec file created 'services/security/OAuth.json'


    Imporant | Make sure that your clientId and sercretId are set in your oauth providers.
            See service spec file resources/services/security/OAuth.json


                                    

The create api command generates the following directory structure under your iCli workspace

api.json the api specification file
resources
   services where all your services specification files are stored
   scripts where all your services javascript files (business logic) are stored
   messages (Optional) your i18n multi-lang application messages are stored
   templates (Optional) where you can store html templates for signup emails, or any other puspose

For every service created, there are 2 files (We'll assume that both files are required for the moment). Later on, we will see when is it possible to have only the .json without the .js file

  • the specification/definition (.json) of the service under the services folder
  • the javascript logic (.js) to be executed when the service is called

The create api command, by default, enables api security by adding 2 authentication schemes

  • Token scheme
  • Cookie scheme

If you open the api.json file, you'll find a section called 'security' where both security schemes were added


    {
    
        ...
        ...
        
        "security": {
            "schemes": {
                "token": {
                    "auth": { "secrets": "default" }
                },
                "cookie": {
                    "auth": { "secrets": "default" }
                }
            }
        }
        
    }


                                    


The create api command, also, creates the following on-boarding/authentication services based on BlueNimble Identity Management Out-Of-The-Box api

Signup allows your application users to signup using the user/password method
Activate signup could be configured to send an activation pin by email to your users in order to validate their email address and activate their account
Login allows your application users to login using the user/password method
ChangePassword allows your application users to change their password when using Signup and Login services
OAuth allows your application users to signup/login using OAuth 2.0 compliant providers. By default, the iCli generates configurations for facebook, linkedin, google plus and github. You can add or delete based on your application need
Create an Api project manually

The iCli 'create api' command isn't a requirement to create an api project. You can create the directory structure, explained above, yourself. Only the api.json file is required for an api to be valid.

The benefit of using the iCli is to avoid mistakes and also to generates the efault authentication services.

Create a new service

Description

You can either use BlueNimble CLI or create the service spec file (.json) and script file (.js) yourself.

The iCli creates ready to use database-aware services based on application model objects. But there are many situations where you'll need to create the services manually such as those to handle file uploads, downloads, specific business logic without database interaction or services to integrate with other cloud services such as 'salesforce', 'google', or enterprise ERPs...

Create a service using the iCli

    # create a service for model item
    bluenimble:.> create service post todoitem
    
        /--> 'post todoitem' Service
           |
           +--+   spec file created 'services/todoitems/CreateTodoitem.json'
           |
           +--+ script file created 'services/todoitems/CreateTodoitem.js'
           
    

The iCli generates 2 files CreateTodoitem.json and CreateTodoitem.js

CreateTodoitem.json the specification or the definition of your service
CreateTodoitem.js where you should write your business logic
CreateTodoitem.json

{

        "verb": "post",
    "endpoint": "/todoitems",

    "spec": {
        "contentType": "application/json",
        "fields": {
            "payload": { "type": "Map" }
        }
    },

    "runtime": {
        "script": "scripts/todoitems/CreateTodoitem.js"
    },

    "spi": {
        "class": "scripting.javascript:ServiceSpi"
    }

}


Specification
verb the http/coap verb to be used when calling this service
endpoint the endpoint part of the url to call
spec define validation rules
contentType(Optional) the payload contentType
fields(Optional) a set of field validation rules
CreateTodoitem.js

    return {
        
        execute: function (api, consumer, request, response) {
            
            // add a Todoitem
            
            return api.database (request)	
                        .create ('Todoitem', request.get ('payload'))
                        .save ()
                        .toJson ();
            
        }
    
    }
    
    

As shown above, the default generated .js script contains code to add a todoitem into the database. You can remove the body of the execute function and write your own logic

Create a service manually

In order to create a service manually, you only need to create the .json and .js files and save them under the services and scripts folders respectively. There is no restriction in naming your files or subfolders.

execute () function arguments
api (Api class) the object representing the Api to whom this service belongs to
consumer (ApiConsumer class) the application or device calling this service
request (ApiRequest class) the parameters, headers and streams send by the calling application or device
response (ApiResponse class) the response to send back to the calling application or device

Adding validation rules to a service

Validation rules, such as type, min, max, regex among other settings, could be added to a service in a declarative way in order to validate the request data before triggering your business logic located in the .js file. Letting you focus on writing your business logic without adding checks and conditions in your code in order to unit-validate the request

Validation rules should be declared under spec/fields object in your service .json specification file

Let's walk you through an example

        {
    
            ...
            
            "spec": {
                "fields": {
                    "email": { "type": "String",  "vType": "email", "required": "true", "scope": "p" } 
                      "age": { "type": "Integer",   "min": "18",    "required": "true", "scope": "p" }
                }
            },
            
            ...
    
        }
    
    

In this example, your service is waiting for 2 parameters ( scope = p ) email and age, both are required ( required = true )

  • email is of type 'String' and should be a valid email address ( vType = email )
  • age is of type 'Integer' and should be greater or equals 18 ( min = 18 )
Defaults
type String
required true
scope p (Parameter). Possible values are 'p', 'h' (Header) and 's' (Stream)

Based on the default settings, the example above could be rewritten this way


        {
    
            ...
            
            "spec": {
                "fields": {
                    "email": { "vType": "email" } 
                      "age": { "type": "Integer", "min": "18" }
                }
            },
            
            ...
    
        }
    
    

Supported Types
String Character sequence value
AlphaNumeric Character/Numbers sequence value
Integer positive and negative numbers
Long long positive and negative numbers
Boolean a boolean value. Possible values are [true, false, yes, no, on, off, n, y, 0, 1]
Decimal decimal numbers
Date date value
DateTime date value
Map an object of values
Stream a binary stream value
Array an array of values
Raw undefined type, should be validated only if it's required
Supported vTypes (Validation Types)
Email a field of type String should be a valid email address
Url a field of type String should be a valid url
Regex a field of type String should match a regular expression defined by the "format" property

Here is an example illustrating the use of the Regex vType to check if a submitted password is strong enough


        {
    
            ...
            
            "spec": {
                "fields": {
                       "email": { "vType": "email" } 
                    "password": { "vType": "Regex", "format": "^(?=.*[A-Z])(?=.*[!@#$&*])(?=.*[0-9])(?=.*[a-z]).{8,}$" }
                }
            },
            
            ...
    
        }
    
    

Validation rule could also be defined inside fields of a Map or Array type to validate the content of a ramified json payload. See example bellow


        {
    
            ...
            
            "spec": {
                "fields": {
                       "email": { "vType": "email" } 
                     "profile": {
                            "type": "Map",
                            "fields": {
                                "age": { "min": "18" }
                                ...
                            }
                     }
                }
            },
            
            ...
    
        }
    
    

You can also set default values this way


        {
    
            ...
            
            "spec": {
                "fields": {
                        "user": { },
                    "subscriptionType": { "value": "Standard" }
                }
            },
            
            ...
    
        }
    
    

If the subscriptionType is not sent by the calling application, the default value will apply

Coding service business logic

Create a file under the resources/scripts folder of your api called Greeting.js and edit it using your preferred javascript editor

Copy the code bellow to the Greeting.js file


    return {
        
        /**
         *
         *	@author		A-Team
         *	@created	26-06-2016 00:20:58
         * 
         **/
        execute: function (api, consumer, request, response) {
            
            // this service accepts a name as request parameter and it sends back a greeting message
            return {
                greeting: 'Hello ' + request.get ('name');
            };
            
        }
    
    }
                                    
    

Let's create the spec .json file. Create a Greeting.json file under the resources/services folder of your api

Copy the code bellow to the Greeting.json file


        {
    
                "verb": "get",
            "endpoint": "/hello",
    
            "runtime": {
                "script": "scripts/Greeting.js"
            },
    
            "spi": {
                "class": "scripting.javascript:ServiceSpi"
            }
    
        }
                                    
    

We created a get /hello service accessible from https://[yourSpace].uranus.bluenimble.com/[yourapi]/hello

Since services, by default, are secure, let's disable security for this service for trial purposes

Change your service .json spec by adding the security section as it's shown bellow


        {
    
                "verb": "get",
            "endpoint": "/hello",
    
            // security disabled
            "security": {
                "enabled": "false"
            },
    
            "runtime": {
                "script": "scripts/Greeting.js"
            },
    
            "spi": {
                "class": "scripting.javascript:ServiceSpi"
            }
    
        }
                                    
    

Use the iCli to install your api by issuing the 'push api [yourApi]' command

Open up a browser, and hit https://[yourSpace].uranus.bluenimble.com/[yourapi]/hello?name=John

You should see the following output


        {
    
            "greeting": "Hello John"
    
        }
                                    
    

Create an Api project

Default BlueNimble Security

BlueNimble provides four (4) authentication schemes

Token (Authorization Token aToken) suitable for mobile, IoT and modern web applications using AngularJs or similar
Cookie (Cookie name:value) suitable for web application or usecases where a cookie should be present to establish an SSO-Like authentication
Basic (Authorization Basic base46[user:password]) suitable for application integration using the Authorization Basic scheme
Signature (Authorization Bearer accessKey:signature) suitable for cloud and api integration

An Api can use all or some of the four schemes to authenticate requests

When a request is intercepted by BlueNimble container, the security layer will try to discover which authentication scheme this request is using and delegates to the appropriate scheme resolver.

If None of the schemes is found, the authentication is delegated to the Api.js -> findConsumer function for a custom application authentication

If a scheme is found and the request failed to authenticate, then an error is thrown unless the security is disabled for the service handling the request

Here is the default api specification api.json when it's created by the iCli. It has a security section where it declares the supported security schemes


        {
            
            "namespace": "todolist",
            "name": "todolist api",
            "description": "todolist description",
            
            "runtime": {
                "script": "scripts/Api.js"
            },
            
            "spi": {
                "class": "scripting.javascript:ApiSpi"
            },
            
            "security": {
                "schemes": {
                    "token": {
                        "auth": { "secrets": "defaults" }
                    },
                    "cookie": {
                        "auth": { "secrets": "defaults" }
                    }
                }
            }
            
        } 
        
    

For both the Token and Cookie schemes, the resolver uses an encryption key to encrypt/decrypt tokens. Secrets are created at the space level to keep the encryption keys secure even if you want to share your api project with other developers in your organization or from outside. Also could be reused by multiple apis in the same space to allow a cross security mecanism.

In order to enhance the default authentication mecanism or write your own, you'l need to implement the findConsumer function located in the Api.js under resources/scripts folder

Here is the default Api.js implementation


    return {
    
        findConsumer: function (api, service, request, consumer) {
        
            /**
             *
             * Remove this portion of code if you want to write a custom authentication logic.
             * This code remains valid only if you're using BlueNimble default authentication schemes see api.json / security section
             *
             **/
            if (consumer.type == ApiConsumer.Type.Unknown && consumer.isAnonymous () && 
                    ( !service.security || !service.security.enabled || service.security.enabled == 'true' )) {
                throw 'authentication error'
            }
        }	 
        
    }
    
    

Calling services securely using Http, CoAP and Mqtt

Depending on how you're on-boarding your application users or IoT devices and also which authentication scheme your api is supporting, calling applications should send the appropriate request headers and parameters.

In this chapter, we'll focus on the Token scheme which is the most used scheme in mobile, modern web applications and in IoT with other security artifacts

First of all, an application should should get a token for a user by sending the login request. If you take a look at the Login.json service generated by the iCli, you'll notice that this service isn't secure which makes sense.

Once the application/device/user gets the token, all secure subsequent requests should send the token. Here is the information to send for Http, CoAP and Mqtt

Http Http Authorization Header: Authorization Token aToken
CoAP CoAP option 201: 201 Token aToken
Mqtt Doesn't apply since it's a stateful protocol

Here is a curl/http example


    curl -H "Authorization: Token tokenYouGetWhenUserLogin" -H "Content-Type: application/json" -X POST  \
        -d '{"title": "Meet with the UX team", "description": "Discuss what is done so far & explain our vision.", "when": "2016-09-23T10:30Z"}' \
        https://YourSpace.uranus.bluenimble.com/todolist/items
                                    
    

Here is a CoAP example using a java client (Californium). We'll skip how to load the bluenimble certificate to communicate over ssl


    URI uri = new URI ("coaps://YourSpace.uranus.bluenimble.com/store/kitchen/temperature");
    
    CoapClient client = new CoapClient (uri);
    
    Request r = new Request (Code.POST);
    r.setPayload ("{\"value\": \"67F\"}");
    
    // add the authentication token 
    r.getOptions ().addOption (new Option (201, "tokenYouGetWhenUserLogin"));
    
    r.getOptions ().setAccept (MediaTypeRegistry.APPLICATION_JSON);
    r.getOptions ().setContentFormat (MediaTypeRegistry.APPLICATION_JSON);
    
    CoapResponse response = client.advanced (r);
    
    if (response != null) {
        System.out.println (response.getCode ());
        System.out.println (response.getResponseText ());
    } 
                                    
    

Working with the Database Feature

The database feature provides functions to store, delete and query data in a database implementation provided by BlueNimble.
BlueNimble provides the same interface api for all supported databases. Here is how to acquire a database instance


    /**
     *
     * This is your service business logic  
     *
     */
    return {
        
        execute: function (api, consumer, request, response) {
        
            // acquire a database instance for the default platform database
            var database = api.database (request);
            
        }
    }
    
    

creating and updating records

In order to create or update a record, use the Database class functions. See example bellow


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // create a user record
            database.create (
                'Users', {
                    name: 'Joe Black',
                    title: 'Missionary',
                    age: 36
                }
            ).
            save ();  // save the user record
    
        }
    }
    
        

When adding records, two additional properties are generated: 'id' and 'timestamp'. To provide a custom id, you can send it part of the database object, instructing the database implementation to use this specific value as the record id.


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // create a user record
            database.create (
                'Users', {
                    id: 'joe@somewhere.com',
                    name: 'Joe Black',
                    title: 'Missionary',
                    age: 36
                }
            ).
            save ();  // save the user record
    
        }
    }
    
        

If the id is provided, the database feature may decide to perform an update if the record given by id 'joe@somewhere.com' already exists

getting a record by id

In order to get a record, use the Database class get method. In the example bellow, we get the user record to add/update some of its properties


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // get a user by id
            database.get ('Users', '7e1c08ed-0259-495b-88a7-b3cebc1d2e9f')
    
            // update/add properties
            .set ('age', 38)
            .set ('address', 'S. SomeWhere Dr');
    
            // save record
            .save ();
    
        }
    }
    
        

deleting records by id

In order to delete a record, you can either get the record using the get method or find/query to delete multiple records based on a specific application logic. Here is an example of deleting a record


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // get a user by id
            database.get ('Users', '7e1c08ed-0259-495b-88a7-b3cebc1d2e9f')
    
            // delete record
            .delete ();
    
        }
    }
    
        

find records by query

In order to find records based on a query, make use of the Database find and findOne methods.


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // our result object
            var result = { records: [] };
    
            // get all employees in the IT department having a salary greater than 120K
            database.find ('Employees', {
                where: {
                    department: 'IT',
                    salary: { op: 'gt', value: 120000 }
                }
            }, function (dbo) {
                result.records.push ( dbo.toJson () );
                
            });
            
            return result;
    
        }
    }
    
        

If you want to get only the first record, use the Database.findOne method


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            var employee = database.findOne ('Employees', {
                where: {
                    department: 'IT',
                    salary: { op: 'gt', value: 120000 }
                }
            })
            
            if (employee) {
                return employee.toJson ();
            }
            
        }
    }
    
        

deleting and updating records by query

Here is an example deleting records based on a quey


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // delete orders having a canceled status  
            database.find ('Orders', {
                where: {
                    status: 'Canceled'
                }
            }, function (dbo) {
                dbo.delete ();
            });
    
        }
    }
    
        

The code above is similar this one, using the Database.deleteByQuery


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // delete orders having a canceled status  
            database.deleteByQuery ('Orders', {
                where: {
                    status: 'Canceled'
                }
            });
    
        }
    }
    
        

Here is an example updating records based on a query


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // updating orders status from Received to Done  
            database.find ('Orders', {
                where: {
                    status: 'Received'
                }
            }, function (dbo) {
                dbo.set ('status', Done)
                    .save ();
            });
    
        }
    }
    
        

working with 1-1 and 1-N relationships

The example bellow creates a record and attaches it to a parent record


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // create a user of type partner
            var user = database.create ('Users', {
                name: 'Joe Black',
                email: 'joe@somewhere.com'
            });
            
            // setting the type of this user to 'Partner'
            user.ref ('type', 'UserTypes', 'Partner');
    
            user.save ();
    
        }
    }
    
        

The code above is equivalent to the one bellow


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // create a user of type partner
            var user = database.create ('Users', {
                name: 'Joe Black',
                email: 'joe@somewhere.com'
            });
            
            // setting the type of this user to 'Partner'
            user.set ( 'type', database.get ('UserTypes', 'Partner') );
    
            user.save ();
    
        }
    }
    
        

The example bellow updates a 1-1 reference of a record


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // create an existing offer
            var offer = database.get ('Offers', '2089419540');
            
            // setting the 1-1 status of this offer to 'Expired'
            offer.ref ('status', 'OfferStatus', 'Expired');
            
            offer.save ();
    
        }
    }
    
        

The example bellow attaches a child record to a parent record (1-N relationship)


    return {
    
        execute: function (api, consumer, request, response) {
    
            var database = api.database (request);
    
            // get a partner record
            var partner = database.get ('Partners', 'alpha');
            
            // get the program to add to this partner 
            var program = database.get ('Programs', 'ITC');
            
            // attaching the program to the partner
            program.appendTo (partner, 'programs');
            
            partner.save ();
    
        }
    }
    
        

Working with the Storage Feature

The storage feature provides functions to store, delete and list folders and files in a storage implementation provided by BlueNimble.
BlueNimble provides the same interface api for all supported storages. Here is how to acquire a storage instance


    return {
        
        execute: function (api, consumer, request, response) {
        
            // acquire a storage instance for the default platform storage
            var storage = api.storage (request);
            
        }
    }
    
    

creating folders

In order to create a folder, use the Storage class functions. First we have to get the root folder for the space where the api/service will be running and then we operate on it. See code snippet bellow


    return {
    
        execute: function (api, consumer, request, response) {
    
            var storage = api.storage (request);
    
            // get the space root folder
            var root = storage.root ();
    
            // add a new folder called 'pictures'
            var pictures = root.addFolder ('pictures');
    
        }
    }
    
        

The addFolder function returns the newly created folder. You can create a hierarchy of subfolders by calling the same function in a loop. The code bellow create a structure of subfolders.


    return {
    
        execute: function (api, consumer, request, response) {
    
            // get the space root folder
            var root = api.storage (request).root ();
    
            var path = 'pictures/personal/2016/summer'.split ('/');
            
            for (var i = 0; i < path.length; i++) {
                root = root.addFolder ( path [i] );
            }
    
        }
    }
    
        

getting and listing folders

In order to get a folder, first we locate the parent folder and then use the 'get' function provided by the 'Folder' class to lockup a subfolder by path


    return {
    
        execute: function (api, consumer, request, response) {
    
            // get the space root folder
            var root = api.storage (request).root ();
    
            // get the subfolder for the path in argument
            var summerPictures = root.get ('pictures/personal/2016/summer');
    
        }
    }
    
        

To list the content of a folder, use the 'list' function provided by the 'Folder' class. The code bellow lists the files and folders under a specific folder


    return {
    
        execute: function (api, consumer, request, response) {
    
            var result = { files: [] };
    
            // list all files and folders under folder 'pictures/personal/2016/summer'
            api.storage (request).root ().get ('pictures/personal/2016/summer').list ( function (f) {
                result.files.push (f.name);
            });
            
            return result;
    
        }
    }
    
        

fetching streams (files)

In order to get the content of a stream object (file), you can call the 'get' function of the 'Folder' class by supplying the path of the file.

The code bellow get a stream stored under the invoices folder


    return {
    
        execute: function (api, consumer, request, response) {
    
            // get the folder where the stream will be stored
            var file = api.storage (request).root ().get ('invoices/customer-123/201603');
    
            return file.toOutput ();
    
        }
    }
    
        

The toOutput function of the 'StreamObject' class is verry helpful in case you want to stream a file back to the application (ex. downloads)

storing streams (files)

In order to store a file in a specific folder, first we locate the folder then we supply a StreamSource object. A StreamSource is a stream with some properties such as the name and content-type.

Streams can come from different sources: from other folders, from other storage implementations, from an application such as uploads, from a cloud service, from an enterprise application/ERP or newly created by the service itself.

The code bellow assumes that an application calls the service and sends a image upload


    return {
    
        execute: function (api, consumer, request, response) {
    
            // get the uploaded file
            var stream = request.get (ApiRequest.Payload, ApiRequest.Scope.Stream);
    
            // get the folder where the stream will be stored and call the addObject to store the stream
            api .storage (request).root ().get ('pictures/avatars')
                .addObject (stream);
    
        }
    }
    
        

deleting files and folders

In order to delete a file or a folder, we located the object (file or foilder) by path and we call the delete function provided by the 'StreamObject' class.

The code bellow deletes a file given by a path


    return {
    
        execute: function (api, consumer, request, response) {
    
            // get an object and delete it
            api .storage (request).root ().get ('pictures/avatars/10000').delete ();
    
        }
    }
    
        

Working with the Messaging Feature

The messaging feature provides functions to send messages using a messaging implementation provided by BlueNimble.
BlueNimble provides the same interface api for all supported messaging providers. Here is how to acquire a Messenger instance

The code bellow acquires an instance of a Messenger for the 'my-smtp'.
'my-smtp' is the name of the feature you should create and define at the space level using the iCli 'add feature' command


    return {
        
        execute: function (api, consumer, request, response) {
        
            // acquire a messenger instance
            var messenger = api.messenger (request, 'my-smtp');
            
        }
    }
    
    

sending emails

In order to send emails. First we acquire an instance of a messenger and then we call the send function provided by the 'Messenger' class

The code bellow sends an email in a sync mode, calling application will get the response back after the email is sent to the relay smtp server. If the server responded with an error, application should get the error back.


    return {
    
        execute: function (api, consumer, request, response) {
    
            // acquire a messenger instance
            var messenger = api.messenger (request, 'my-smtp');
            
            messenger.send ({
                    name: 'Billing Dept'            // Email from
                }, [{
                    id: 'someone@somewhere.com'     // recipient
                }],
                'Credit Card Expiration Notice',    // subject
                'Dear, Your credit card is expiring soon, please renew or add a new card.'  // message
            );
    
        }
    }
    
        

In order to send a nice looking email, use html templates. Learn more this topic in the Javascript Api documentation 'class Messenger'

sending mobile push notifications

In order to send push notifications. The Api class provides a simple way to achieve this by calling the push function.

Push Notifications is also a Messenger implementation, you can achieve the same task by using the messenger.
'my-push-notif' is the name of the feature you should create and define at the space level using the iCli 'add feature' command The code bellow will send a push notification to 2 devices given by their 'registration id'


    return {
    
        execute: function (api, consumer, request, response) {
    
            // push notification to a device 
            api.push (
                request, 'my-push-notif', 
                [{
                    id: 'abcd-efgh'   // 1st device registration id   
                }, {
                    id: 'ijkl-mnop'   // 2nd device registration id   
                }],
                {
                    message: "'It's time to go paperless! Learn more"
                }   // data to send to the device.
            );
    
        }
    }
    
        

Working with the Cache Feature

The cache feature provides functions to cache application data using a cache implementation provided by BlueNimble.
BlueNimble provides the same interface api for all supported caching providers. Here is how to acquire a Messenger instance


    return {
        
        execute: function (api, consumer, request, response) {
        
            // acquire a cache instance
            var cache = api.cache (request);
            
        }
    }
    
    

creating cache buckets

In order to cache application data. First we acquire an instance of a cache and then we call the create function provided by the 'Cache' class.
Buckets only created once, then application should get an existing bucket to store data

The code bellow creates a bucket.


    return {
    
        execute: function (api, consumer, request, response) {
    
            // create the preferences bucket where we cache application users preferences 
            var cache = api.cache (request).create ('preferences');
    
        }
    }
    
        

listing entries of a buckets

The code bellow listing the first 100 entries of a cache bucket.


    return {
    
        execute: function (api, consumer, request, response) {
    
            // return the first 100 entries of the 'preferences' bucket 
            return api.cache (request).list ('preferences', 0, 100);
    
        }
    }
    
        

clearing buckets

The code bellow removes all entries of a bucket.


    return {
    
        execute: function (api, consumer, request, response) {
    
            // return the first 100 entries of the 'preferences' bucket 
            return api.cache (request).clear ('preferences');
    
        }
    }
    
        

dropping buckets

The code bellow drops or deletes a bucket.


    return {
    
        execute: function (api, consumer, request, response) {
    
            // return the first 100 entries of the 'preferences' bucket 
            return api.cache (request).drop ('preferences');
    
        }
    }
    
        

inserting entries into a bucket

The code bellow inserts an entry into a bucket.


    return {
    
        execute: function (api, consumer, request, response) {
    
            // return the first 100 entries of the 'preferences' bucket 
            api.cache (request).put ('preferences', 'user-1000', { 
                theme: 'vanilla',
                language: 'Spanish',
                notifications: true
            });
    
        }
    }
    
        

reading entries from a bucket

The code bellow gets an entry from a bucket.


    return {
    
        execute: function (api, consumer, request, response) {
    
            // return the entry value for the key user-1000 
            return api.cache (request).get ('preferences', 'user-1000');
    
        }
    }
    
        

deleting entries from a bucket

The code bellow deletes an entry from a bucket.


    return {
    
        execute: function (api, consumer, request, response) {
    
            // delete an entry for the key user-1000 
            return api.cache (request).dlete ('preferences', 'user-1000');
    
        }
    }
    
        

Working with the Net.Http Api

The Http api allows us to integrate with cloud services such as salesforce, social media and enterprise web services.
The api is quite simple to use, providing direct functions to make get, post, put and delete requests. Here is a simple get request


    return {
        
        execute: function (api, consumer, request, response) {
        
            // call https://www.bluenimble.com 
            // the call returns an http response 
            var httpResponse = Http.get ({ url: 'https://www.bluenimble.com' });
            
        }
    }
    
    

making Http requests

All the get, post, put and delete functions accepts 1 argument which is the request 'spec' object.

The spec object should provide the following properties: url, data (optional), headers (optional), timeouts (optional), proxy (optional) and visitor (optional).
The code bellow creates a get request and return back a json object to the calling application


    return {
    
        execute: function (api, consumer, request, response) {
    
            // ip address
            var ipAddress = '2601:647:4b01:cde8:1c76:ad8c:f55f:192e';
    
            // make a get request to freegeoip to get the approximate geolocation of an ip address 
            var httpResponse = Http.get ({ 
                url: 'http://freegeoip.net/json/' + ipAddress
            });
            
            // test if it's a successful request
            if (httpResponse.status != 200) {
                throw 'Error code=' + httpResponse.status + ', message=' + httpResponse;
            }
            
            // return the json result
            return httpResponse.asJson ();
        }
    }
    
        

adding Http headers

To add additional headers to an http request, we only need to add the headers object to the spec.
The code bellow make a post request with some extra headers


    return {
    
        execute: function (api, consumer, request, response) {
    
            // make a post request to salesforce to create a new Account object with additional headers and a json payload
            var httpResponse = Http.post ({ 
                url: 'https://na12.salesforce.com/services/data/v20.0/sobjects/Account',
                headers: {
                    Authorization: 'Bearer 00D50000000IehZ\!AQcAQH0dMHZfz972Szmpkb58urFRkgeBGsxL',
                    'Content-Type': 'application/json'
                },
                data: {
                    "Name" : "Express Logistics and Transport"
                }
            });
            
            // test if it's a successful request
            if (httpResponse.status != 200) {
                throw 'Error code=' + httpResponse.status + ', message=' + httpResponse;
            }
            
            // return the newly created Accont
            return httpResponse.asJson ();
            
        }
    }
    
        

signing Http requests with OAuth

To OAuth-Sign an http request before making the call, we need to set the visitor object


    return {
    
        execute: function (api, consumer, request, response) {
    
            // make a post request to update the authenticating user’s current twitter status 
            var httpResponse = Http.post ({ 
                url: 'https://api.twitter.com/1.1/statuses/update.json',
                data: {
                    "status" : "hi from #bluenimble"
                },
                visitor: {
                    name: 'signer.oauth', 
                    key: 'your twitter consumer key', secret: 'your twitter consumer secret'
                }
            });
            
            // test if it's a successful request
            if (httpResponse.status != 200) {
                throw 'Error code=' + httpResponse.status + ', message=' + httpResponse;
            }
            
            // return the updated status
            return httpResponse.asJson ();
            
        }
    }
    
        

Working with Utility Apis: Lang, Crypto, DateTime and more

Utility Classes provide useful functions for application development such as encryption, working with dates and data hashing


    return {
        
        execute: function (api, consumer, request, response) {
        
            // call https://www.bluenimble.com 
            // the call returns an http response 
            var httpResponse = Http.get ({ url: 'https://www.bluenimble.com' });
            
        }
    }
    
    

using Lang functions

Most of the application has to manage and generate almost-unique ids for many purposes. guid and rand are the most used functions that Lang provides.
To create a guid, use the Lang.guid function


    return {
    
        execute: function (api, consumer, request, response) {
    
            var id = Lang.guid (); // the id will look like (47635fbc-9cfe-4523-878b-99848f03e24a)
            
        }
    }
    
        

To create a fixed-length alpha numeric id, use the Lang.rand function


    return {
    
        execute: function (api, consumer, request, response) {
    
            var id = Lang.rand (8); // the id will look like (YGk1e96s)
            
        }
    }
    
        

using Crypto functions

The Crypto class provides encryption fundtions for applications to encrypt data

The code bellow encrypts and decrypts data using a paraphrase


    return {
    
        execute: function (api, consumer, request, response) {
    
            var paraphrase  = 'mykey';
            var text        = 'text to encrypt';
            
            // encrypt
            var encrypted = Crypto.encrypt ( Lang.toBytes (text), paraphrase ); 
            
            // decrypt
            var decrypted = Crypto.decrypt ( Lang.fromBytes (decrypted), paraphrase ); 
            
            return {
                theSame: (decrypted == text)
            }
    
        }
    }
    
        

To calculate an md5 of a portion of data, use the md5 function. See code bellow


    return {
    
        execute: function (api, consumer, request, response) {
    
            var hash = Crypto.md5 ( Lang.toBytes ('text to md5') ); 
            
        }
    }
    
        

To calculate a hmac of a portion of data, use the hmac function. See code bellow


    return {
    
        execute: function (api, consumer, request, response) {
    
            var paraphrase  = 'mykey';
    
            var hash = Crypto.hmac ( Lang.toBytes ('hamac a text'), paraphrase ); 
            
        }
    }