At NY Cloud Computing meetup

Looking forward to hearing about Hadoop in the cloud from GigaSpaces

Apstrata will be presenting at NY Mobile Apps on Monday

Hope to see some of you there:

Monday, November 26, 2012
7:00 PM
Alley NYC
500 7th Ave, 17th Floor
New York, NY 10018

Server-side Scripts

Server-side scripting is another cool feature of Apstrata. It allows any developer to add back-end logic to his/her applications while leveraging the power of Apstrata’s API. In addition to this, Apstrata’s server-side scripting capability provides the developers with other advantages:

  • No deployment and configuration efforts: the scripts are written in JavaScript and all that is needed is to upload them to your Apstrata account,
  • Multi tenancy: since you can deploy multiple scripts for different client applications,
  • Built-in security: as we will see it shortly, you can leverage Apstrata’s authentication and authorization (ACLs) in your scripts, which gives you control on who can read/edit or run your scripts,
  • Background jobs: you can ask for asynchronous execution of your scripts, scheduling them to run at specific times or intervals,
  • Orchestration: you can factor out the logic to coordinate (orchestrate) the execution of multiple services (Apstrata APIs or any other web service and or server-side scripts) and build your own APIs through Apstrata server-side scripts.

How to create server-side scripts?

While you could write a script using any IDE and just upload it to your Apstrata account by calling the SaveScript API, the easiest way to create a script is by using the Apstrata workbench. Log in to the workbench using your Apstrata authentication key and secret, then click on “Manage Account” > “Scripts” > “My Scripts”. In the panel that opens, either click on “New” to start writing a new script, or select an existing script, which in both cases results in opening the script editor. Although the capabilities of the editor are limited, they cover most of what you need to get started, including the highlighting of the JavaScript keywords and the analysis of the JavaScript syntax.

Before you start coding, pay attention that you need to wrap your JavaScript code into a specific XML structure, composed of an ACL section and a code section, as shown in the below snippet. We will examine the ACL part in more details later on in this tutorial. For now, just remember to insert your JavaScript code into the “<code><![CDATA[” section. If you forget to do this, the workbench will display an alert informing you that your document is not well formed.

<script>
<scriptACL>
     <execute>anonymous</execute>
     <read>group:developers</read>
     <write>group:developers</write>
</scriptACL>
<code><![CDATA[

// Your code goes here

]]>
</code>
</script>

Once you are done coding, enter a name for the script in the “Name” input field then click on “Save”.

Your first server-side script

We will start by implementing a simple script that creates a new document in the default store of your account (or any other store). The document will be schema-less and will contain two fields: “amount” (of type “numeric”) and “date”, that will contain the current date. The identifier of the document (the “documentKey”), as well as the amount will be retrieved from the request. (The complete script is available here)

Retrieving a parameter from the request: the “request” object

From within server-side scripts, you have access to first class Astrata objects such as the"request" object. This object wraps the HTTP request that triggered the execution of your script and is used to retrieve the parameters sent along the request:

var documentId = request.parameters["documentId"]; // we assume that the document id parameter is called "documentId"
var amount = request.parameters["amount"];
Preparing the parameters to pass to the API

Since we need to create a document, we have to invoke the "SaveDocument" API, and pass it the required parameters: the document identifier, the amount field and the date field. Since we do not want to store these fields as strings, we also need to pass the corresponding expected respective types along the parameters of the request sent to “SaveDocument” :

// we need this field to be stored as a numeric, so we parse it to an int
amount = parseInt(amount);

// we create an object that contains the various parameters
var saveDocumentParams = {

  "apsdb.documentKey": documentId, //apsdb.documentKey is an apstrata key word that refers to the document identifier
  "apsdb.store": "DefaultStore", //apsdb.store is an apstrata key word. You actually do not need to specify the store when you are using the default store
  "amount": amount,
  "date": new Date(),
  "amount.apsdb.fieldType": "numeric", // notice how we specify the type of a given field -> [fieldName].apsdb.fieldType
  "date.apsdb.fieldType": date
 }
Invoking the targeted API: the “apsdb” object

In order to invoke any Apstrata API that is available on the current Apstrata cluster, you can leverage the first class “apsdb” object, and more specifically, the “callApi()” function that it provides. This function expects the name of the API to invoke, a JavaScript object containing the parameters to pass and optionally, the files that you need to upload to the document. So let us invoke this function in our script, feeding it with the “saveDocumentParams” object, and storing the result in a variable (“response”):

var response = apsdb.callApi("SaveDocument", saveDocumentParams, null); // notice that we passed 'null' as a last parameter as we have no files to upload.
return response; // our script will return the response received from the execution of apsdb.callApi()
Processing the response of the invoked API

The invocation of “apsdb.callApi()” always returns a response containing the outcome of the call. This outcome is divided in two parts: “metadata” and “result”. The “metadata” part contains the status of the invocation and the “result” part contains the outcome of the API execution, if any. For example, if you remove the “parseInt()” function in our example and run the script (therefore sending a string instead of a numeric), you will receive the following (in the response variable created above):

{
    "metadata": {
	"status": "failure",
	"errorCode": "INVALID_FIELD_VALUE",
	"errorDetail": "Field [amount] cannot contain values that are not numeric"
     }
}

As you can observe, the metadata section informs you that an error occurred during the execution of the SaveDocument API and gives you some details on that error. Hence, in order to determine the status of the “apsdb.callApi()” execution, you just need to check the value of “response.metadata.status” (“failure” or “success”).

Now if you restore the “parseInt()” function and run the script again, you should normally receive a response resembling the following:

{
   "metadata": {
	"status": "success"
   },
   "result": {
	"document": {
         	"key": "[your_document_key]"
	}
   }
}

As you can see, the response now contains a result section filled with the outcome of the SaveDocument API.

In order to know what to expect in this section further to an API call, please consult the corresponding documentation in the Apstrata wiki.

Returning a response from your script

When your script has finished executing, Apstrata will automatically send a response adopting the same structure as the response returned by “apsdb.callApi()” but the “result” section will be null.

The “metadata” section will notify you of any error that resulted from the execution of the script (could be due to a technical concern or to an error in the script logic).

As for the “result” section, since “null” is not very informative to the caller on the client side, it is obviously more interesting to return a more specific result. Depending on the case, you can simply return the response you received further to an API call in your script (such as we did it in the “Invoke targeted API” paragraph), or you can send your own result object. Note that in the former case, the “result” section of the response you obtain from the execution of your script will itself be subdivided into a “metadata” and a “result” section (since all what we did is to returnL the response of the API call). If you decide to build your own response, it is recommended to divide it into a “metadata” and “result” sections as well. Also note that your “metadata” section should preferably at least contain the “status”, “errorCode” and errorDetail attributes in order to standardize the way responses are processed on the client side.

How to execute a script?

You can call the scripts you create on your Apstrata account as any Apstrata API. Simply build the URL of your request such as the following: [http://varick.apstrata.com/rest/apsdb/[your_auth_key]/RunScript?apsdb.scriptName=[your_script_name]&apsws.time=[timestamdp]&script_nameapsws.authSig=[your_signature]&apsws.responseType=jsoncdp&apsws.authMode=simple&[your_parameters]

This latter option is however not really handy for testing in development mode, therefore, you should rather resort to the workbench to run your scripts. From the script editor, save your work by clicking on “Save” then click on “Run”. This opens a panel where you can enter the parameters of your request (name and value). You can even impersonate a user (run the script as if you were this particular user) by selecting a specific in the “RunAs” selection list (we will examine this option in more details in another part of this tutorial). Click on “Go” once you are done.

As you can observe, the workbench will open a new panel further to the call, where the URL of your request to the script and the response returned from your script are displayed.

Tips

Logs

Since it is hard to plug a debugger onto a server-side script, you need an alternative to be able to debug your code. This is provided by the first class "log" object (a property of the “apsdb” object), which will become one of your best friends ;)

In order to start logging events, you first need to set the log level of your script using “apsdb.log.setLogLevel([the_level])”. 5 levels are available, ranging from 0 (no logging) to 4 (all logging calls will be taken into account). To log an event, call the “apsdb.log.debug([message], ?logObject)” function inside your code. All you logs will be sent in the “metadata.scriptLog” attribute of the response (it is an array that contains one object per log call)

A good practice is to make logging configurable in your scripts. For example, you could send the log level as a parameter of your request (which is something you would only do when testing), and set the log level accordingly, as demonstrated in the below example (based on the code we have written so far):

// Note: insert the below code after the retrieval of 'amount' and 'documentId' in your script

// if we sent a logLevel parameter with the request, activate logs and set log level
var logLevel = request.parameters["logLevel"];
if (logLevel) {
	apsdb.log.setLogLevel(logLevel);
}else {
	apsdb.log.setLogLevel(0);
}

// log the value of 'amount'
apsdb.log.debug("Amount received", {amountReceived: amount});

If you run the script, you should receive a response similar to what follows. Notice the “message” and “handback” attributes, which contain respectively the message and the log object you specified when calling “apsdb.log.debug([your_message], [log_object])”;

"metadata": {
		"requestId": "ec97d7c9-970d-4a6b-a6f4-bc517de4ba48",
		"status": "success",
		"scriptLog": [
			{
				"timestamp": "2012-09-13 10:57:04.267",
				"level": "debug",
				"component": "tutorial.part1.firstScript",
				"message": "Amount received",
				"handback": {
					"amountReceived": "5"
				}
			},
			{
				"timestamp": "2012-09-13 10:57:04.268",
				"level": "debug",
				"component": "tutorial.part1.firstScript",
				"message": "Entering API call: SaveDocument"
			},
			{
				"timestamp": "2012-09-13 10:57:04.321",
				"level": "debug",
				"component": "tutorial.part1.firstScript",
				"message": "Exiting API call"
			}
		],
		"statusCode": "200"
	},
	"result": {
		"result": {
			"document": {
				"key": "x"
			}
		},
		"metadata": {
			"status": "success"
		}
	}
Handling exceptions

Another concern that all developers encounter is the occurrence of exceptions during the execution of their server-side scripts. This can be very frustrating as all you get is a generic “script error” message in your “metadata.errorCode” section of the response, with no further details. A good practice is hence to surround your code with a try/catch block, which enables you to capture any exception and process it before the script returns. The catch block would usually wrap the exception into a metadata section that you will send as a response, as shown in the below snippet:

<script>
<scriptACL>
     <execute>anonymous</execute>
     <read>group:developers</read>
     <write>group:developers</write>
</scriptACL>
<code><![CDATA[
  try {
	// your code goes here

  }catch(exception) {
 	return {
 	 "status": "failure",
 	 "error": "EXCEPTION_OCCURRED",
 	 "errorDetails": exception
        }
  }
]]>
</code>
</script>

What’s next?

This first part of the tutorial covered the basics of server-side scripting with Apstrata. In the next parts, we will handle more advanced concepts, such as importing scripts, permissions, transactions, remote calls, redirection, etc.

Push Notifications - A Tutorial

Sending notifications to mobile devices has become a fundamental part of many applications. As a developer, you can leverage Apstrata to easily push notifications to mobile devices running on different platforms (iOS, Android) through a consistent interface. This article will explain how you can do this in a step by step approach. Before we proceed however, let us agree on the definition of some terms that will be used throughout the article:

  • A notification is a message that is sent to one or many mobile devices, through a notification service.
  • A notification service is a middle man that sits between a notification provider and mobile devices that run applications that accept notifications sent by the notification provider.
  • A notification provider is a software application that pushes notifications to mobile devices (more specifically, to applications deployed on mobile devices).
  • A mobile application is an application that is downloaded to a mobile device, which will receive the notifications you push.

Since there exist many notification services (notably the Apple Push Notification Service, APNS, and the Google Cloud To Device Messaging service, C2DM), developers who need to push notifications to mobile devices will have to tackle the differences that exist among those services and integrate these differences into their developments. Moreover, the notification providers will also need to handle subscription and unsubscription requests and their persistence. Resorting to Apstrata will help in simplifying the use of notification services by adding a layer of abstraction which provides a unique way of managing notifications and subscriptions, regardless of the targeted notification service.

Push notifications concepts in Apstrata

Apstrata allows you to push notifications to iOS and to Android devices. Let us examine the different concepts that are available in Apstrata:

  • Channel: a channel is a group of mobile devices towards which you can push the same notification. A channel is defined by a unique identifier (unique per Apstrata store), a mobile application ID (the device that will receive the notifications) and a platform (iOS or Android). Once you have a channel available (or upon creation of a channel), you can subscribe mobile devices to it. For example, you might be interested in pushing a notification about special discounts targeting your VIP customers that hold Apple devices. Therefore, it might be interesting for you to create a channel that you could name “vip_channel_ios” and to subscribe to it the devices of your VIP customers who use iPhones (of course, those customers will have to install some application on their iPhones in order to receive the notifications).

Note that you currently cannot have a channel for more than one type of platform (e.g. iOS and Android). This limitation will be removed in the coming release.

  • Application: a mobile application that is downloaded by your users to their mobile devices. You push notifications to an application through one or many channels. Regardless of the targeted platform, you will usually need some kind of credentials in order to be able to push notifications to an application. How to define credentials is platform specific and will be described in the following paragraphs.
  • Device Token: a device token is an identifier of a mobile device. As a developer, you are responsible for providing Apstrata with such identifiers. Usually, this will be part of the functionality of the mobile application your users will download to their device.

So what do I need to get started?

Pretty simple. You just need to:

  • Have a mobile application and create a definition for it in Apstrata (“create an application”).
  • Create a channel to broadcast notifications to mobile devices that have installed the aforementioned mobile application.
  • Push some notifications.

The below paragraphs will explain how you can do that using Apstrata’s API and tools.

How to create an application?

You can create an application in three different ways:

  1. By using the workbench.
  2. Through a call to the “AddCertificate" REST API.
  3. Using one of the client SDK libraries (The JavaScript SDK is used in this article).
1. Create an application using the workbench

Log in to the Apstrata workbench using your Apstrata authkey and secret. Click on “Manage Account” > “Push Notifications” then select a store (if you’re only testing Apstrata then the only store that you should have is the “DefaultStore”).

Once you have selected a store, a panel displaying the applications you have already created opens. Click on “New” or select an existing application and click “Edit” depending on whether you want to create a new application or edit an existing one. For this tutorial, we will click on “New”, which should open the following form:


Now we need to fill the form fields:

  • Application Id: a unique identifier (per store) that you choose for your application. It does not have to match the name of the corresponding mobile application.
  • Certificate:
    • If your mobile application is an iOS application, you will need to create a certificate from the Apple developer site and upload it using the panel (please refer to the following for more on certificates)
    • If your mobile application is an Android application, you will need to obtain an authentication token (auth token) from Google C2DM service (please read this article for more). Copy and paste your authentication token into a file and upload it to your application via the above form

Note that the auth token you receive from C2DM has a limited life-time and needs to be renewed on a regular basis. You are usually notified of the expiration of your token by C2DM when pushing a notification: C2DM either sends you a new token if the one you are using is about to expire, or notifies you that your token is obsolete. In all cases, you do not have to worry about renewing your token as this is automatically handled by Apstrata in the background.

  • Password:
    • If your application is an iOS application, you will have to enter the password that you have associated to your certificate.
    • If your application is an Android application, you will have to enter your Google account credentials, i.e. your email and password, separated by a comma (the one you might have created for the application for example).

Click on “Save”in order to save your changes.

Don’t forget that you still need to create a mobile application that will receive the notifications you will push. Your users will have to download this application to their mobile devices.

2. Create an application using the “AddCertificate” API

In order to create an application from your code, you just need to POST a request to the “AddCertificate” service. This service allows you to create a definition for a mobile application.

https://sandbox.apstrata.com/apsdb/rest/[Your_Auth_Key]/AddCertificate?apsws.time=[TimeStamp]&apsws.authSig=[Your_Signature]&apsws.responseType=jsoncdp&apsws.authMode=simple

With the following parameters:

{
	"applicationId": "[Some_Id]",
	"password": "[Your_password/or Google e-mail,pwd]"
}

Do not forget that you also need to post the expected “certificate” file (i.e. either the certificate you got from APNS or the authentication key you obtained from C2DM), using the “apsdb_attachment” field.

3. Create an application from the JavaScript SDK

In the following we will be using one of the cool features of the Apstrata JavaScript SDK, which is the “form generator” (an Apstrata widget). The form generator allows you to easily create forms in HTML pages. We will not dive into its intricacies in this article, though we will add some comments to the code in order to make it is easier to understand. Also note that we are just displaying a snippet of the code here. You can download the complete HTML test file from here. We will use the form to upload the certificate file and to set all the other parameters required by “AddCertificate”.

The first step, as usual, is to obtain a connection to Apstrata (we assume in this example that we do not already have such a connection), and to create an instance of the Apstrata JS client using that connection

var connection = new apstrata.sdk.Connection();
var client = new apstrata.sdk.Client(connection);

Second, we create a “form definition” that will be used to automatically generate a form when passed to an instance of FormGenerator (later in the paragraph)

// This is a form definition used to generate a form that will be used to create an application
// it will contain the values of the parameters to post to the "AddCertificate" API, i.e.
// "applicationID", "password", "apsdb_attachment" (for the certificate file)
var formDefinition =  {
        // The label you need to be displayed on top of the form
        label: "Add Certificate",

        // A fieldset is a set of fields that will be contained in your form. The field set contains one definition line per field
        fieldset: [

                // We define a required input field of type string, named "applicationID", that will be labeled as "Application Id"
                {name:"applicationID", label:"Application Id", type:"string", required:true},

                // We define a required input field of type string, name "password", that will be labeled as "Password"
                {name: "password", label: "Password", type: "string", required: true},

                // We define a required field of type "file" that allows uploading/downloading a file (or displaying the file if "displayImage" is true
                // note that you need to pass the current connection to that field so it can connect to Apstrata to retrieve or upload the file
                {name: "apsdb_attachments", label: "Certificate", type: "file", required:true, displayImage:false, connection: connection, value:""}
	],

        // The form generator will automatically generate buttons for every action name in this array
        actions: ['save'],

        // This is optional, if you add this attribute and set it to true, you will be able to submit the form by hitting "Enter"
        submitOnEnter: true,

        // We specify which of the actions defined in the actions array above will be used to submit the form
        submitAction: "save"
};

Third, we need to create an instance of FormGenerator and pass it the above definition. We do this using a function that will be called once the DOM tree is ready and all the widgets are loaded. The function will also take care of adding the DOM node of the FormGenerator instance to the body element of the current HTML document.

function addFormGenerator() {

   // Create an instance of FormGenerator
   var formGenerator = new apstrata.ui.forms.FormGenerator(
   {
       // We pass the form definition that we created above as a parameter
       definition: formDefinition,

       // The "save" function implements the logic that is associated to the "save" action, declared in the "actions"
       // attribute of the above form definition.
       // In our case, "save" will use the Apstrata JS client to post the required data + file using the AddCertificate
       // API. Notice how easy this is: you just need to invoke the "call" function on the Apstrata client,
       // passing it the form node (formGenerator.frmMain) and specifying the HTTP method you need (the "params" is sent
       // empty as all the attributes you need for "AddCertificate" will be retrieved from the form).
       save: function(data) {
	   var params = {};
	   client.call("AddCertificate", params, formGenerator.frmMain.domNode, {method:"post"}).then(
		function(response){
			console.dir(response);
		}
	   )
        }
   });

   var body = dojo.byId("body");
   dojo.place(formGenerator.domNode, body);
};

Finally, once dojo is ready, we invoke the addFormGenerator function.

dojo.ready(function() {

   addFormGenerator();
});

That’s it! You should now be able to fill a form to add new applications to your store.

How to create a channel?

As is the case for creating an application, and for most of what is doable in Apstrata, you can create a channel in three different ways:

  1. By using the workbench.
  2. Through a call to the CreateChannel REST API.
  3. Using one of the client SDKs (JavaScript in this article).

Let us examine what is needed, case by case:

1. Create a channel using the worbench

Log in to the Apstrata workbench using your Apstrata auth key and secret. Click on “Manage Account” > “Push Notifications” and select a store (if you’re only testing Apstrata then the only store that you should have is the “DefaultStore”).

Assume for the sake of this example that we are editing an existing application. Select the application you need. Its details will be displayed in a new panel showing the list of channels that push notifications to the selected application as shown in the below figure (the list will be empty if you never created any channel before for that application).

Click on “Edit Application” then on the “+” button in order to create a new channel. The corresponding form will open:

In this form, you will have to define the following elements:

  • An identifier for your channel (“Channel Id” field). As previously mentioned, this identifier has to be unique in the selected store.
  • A platform (“iOS” or “Android”), depending on the targeted platform.
  • A lifetime, in seconds (optional): this specifies how long a notification service will try to push your notification if it wasn’t successful in pushing it the first time.
  • A list of device tokens (optional) that will be subscribed to this channel (just double click on the ellipsis to add a new device token). Note that using the workbench in order to subscribe mobile devices is mainly useful for test purposes.

Click on “Save” once you are done editing the channel details.

2. Create a channel using the REST API

In order to create an application from your code, you need to send a request to the “CreateChannel" API. This is pretty straightforward and your request should look like the following:

https://sandbox.apstrata.com/apsdb/rest/[your_auth_key]/CreateChannel?apsws.time=[timestamp]&apsws.authSig=[your_signature]&apsws.responseType=json&apsws.authMode=simple&apsdb.store=[your_store]&channelId=[channel_name]&platform=[iOS_or_Android]&applicationID=[existing_app_id]

Note that we did not subscribe any device token in the above call. In order to subscribe device tokens, you need to pass the deviceTokens attribute as many times as there are tokens to subscribe (deviceTokens=13344554&deviceTokens=…)

3. Create a channel using the Apstrata JS SDK

Once again, this is pretty easy to do. As usual, we first need to create an instance of a connection to Apstrata and then pass this connection to a new instance of the Apstrata JS client. After that, we call CreateChannel with all the parameters it requires.

dojo.require("apstrata.sdk.Client")

// Create a connection object with your Apstrata credentials (this example assumes you are logging in as
// an account owner
var connection = new apstrata.sdk.Connection({
	credentials: {
		key: "[your_auth_key]",
		secret: "[your_secret]"
	},
	loginType: "master"
})

// Instantiate a Client object passing the connection
var client = new apstrata.sdk.Client(connection)

// Create the call parameter object
var params = {
	"apsdb.store": "DefaultStore",
	"channelId": "MyTestChannelWithTokens",
	"platform": "iOS",
	"applicationID": "SomeMobileApp"
}

// If you need to subscribe device tokens upon creation of the channel, just add the following to the params object
// "deviceTokens" : ["111111", "22222", ...]

// Invoke the "CreateChannel" API
client.call("CreateChannel", params).then(

        // The event handler that gets called on success
	function(response) {
		// Replace with appropriate code
		console.dir(response)
	},

        // The event handler that gets called on call failure
	function(operation) {
		// Replace with appropriate code
		console.dir(operation.response)
	}
)

How to push a notification

  1. Using the Apstrata workench.
  2. Through a call the the “PushNotification” REST API.
  3. Using one of the Apstrata client SDKs (the JavaScript client in this example).

In this example, we will demonstrate how to push a notification to an iOS device. As mentioned at the beginning of this article, there are no differences in the way Apstrata is used depending on the targeted platform. Only the notification and certificate formats differ.

1. Push a notification using the workbench

Open the Apstrata workbench and log in using your Apstrata credentials as account owner. Click on “API Explorer” the select “PushNotification”. This displays a form that you need to fill with the expected values:

  • The store to use (use “DefaultStore”).
  • channelId: enter the identifier of a channel you previously created (one that is related to the mobile application you will be using on the devices). Make sure your channel is related to an application that has a valid certificate and password and remember to subscribe at least one valid device token to the channel.
  • notification. In this example, we will be using the APNS notification format, since we are pushing to an iOS device.
  • fireAndForget (optional): if set to “false”, the notification will be sent synchronously (the caller will expect the result of the push from the notification service). 

Once you have entered all the parameters, click on “Run” and wait for the notification to arrive to your mobile device.

2. Push a notification using the REST API

To push a notification from your code, you need to POST a request to the “PushNotification" API. Your request should look like the following:

https://sandbox.apstrata.com/apsdb/rest/[your_auth_key]/PushNotification?apsws.time=[time_stamp]&apsws.authSig=[your_signature]&apsws.responseType=json&apsws.authMode=simple&apsdb.store=DefaultStore&channelId=[your_channel_id]PushNotificationsChannel&notification=[your_notification_in_APNS_format_and_URL_encoded]&fireAndForget=yes
3. Push notification using the Apstrata JS SDK
dojo.require("apstrata.sdk.Client")

// Create a connection object with your auth key and secret (assuming you are logged in as an account owner)
var connection = new apstrata.sdk.Connection({
	credentials: {
		key: "[your_auth_key]",
		secret: "[your_secret]"
	},
	loginType: "master"
})

// Instantiate a Client object passing the connection
var client = new apstrata.sdk.Client(connection)

// The call attributes
var params = {
	"apsdb.store": "DefaultStore",
	"channelId": "PushNotificationsChannel",
	"notification": "{ aps: {alert:You got a new message!,badge : 5, sound : default}}",
	"fireAndForget": "true"
}

// Executes the call to apstrata
client.call("PushNotification", params).then(
	// The event handler that gets called on success
	function(response) {
		// Replace with appropriate code
		console.dir(response)
	},
	// The event handler that gets called on call failure
	function(operation) {
		// Replace with appropriate code
		console.dir(operation.response)
	}
)

Good @StartupAPI meetup last night

Mike and Pete attended the meetup last night organized by @sergeyche at @meetup HQ.  It was a very informative session with a lot of engaged conversation.

We share Sergey’s theme: “Developers - you don’t want to code backend plumbing.”  Startup API takes an Open Source route to a solution, and Apstrata takes a Managed Service route to a solution.  But we are coming from the same place.

We look forward to seeing everyone again at the next meeting.  

Reaching out, Getting Social

Your application is ready and deployed. Users are registering on your website while mobile users are installing it on their smart-phones.

Whether you’re a socialite and need to tell your followers about every one of your moves, or a serial gamer who needs to post his progress, achievements and scores, your application will have to post to social networks like Twitter and Facebook.

Which brings us to today’s subject:

Apstrata’s server side scripting brings social networking capabilities to your application.

A simple call like this:

apsdb.social.twitter.tweet(“consumer-key”,”consumer-secret”, “access-token”, “access-token-secret”, “How cool is this, I’m posting to twitter from the best BaaS available!”);

and you’re on your way.

Apstrata provides access to all of Twitter’s api, some through first class api calls like tweet and some through a generic call to callApi.

apsdb.social.twitter.callApi(“consumer-key”,”consumer-secret”, “access-token”, “access-token-secret”, “VERB”, “twitter-resource”, null);

which provides you with access to any existing/new api provided by Twitter without having to wait for a new implementation from you BaaS provider.

A call like this:

apsdb.social.twitter.callApi(“consumer-key”,”consumer-secret”, “access-token”, “access-token-secret”, “GET”, “https://api.twitter.com/1/statuses/home_timeline.json”, null);

will return a user’s timeline in twitter for further processing on the server side.

While this:

apsdb.social.twitter.getApiCall(“consumer-key”,”consumer-secret”, “access-token”, “access-token-secret”, “GET”, “https://api.twitter.com/1/statuses/home_timeline.json”, null);

will return an oAuth signed url which, when called from the application’s front-end, will return the same user’s time line. 

Want to duplicate these tweets and post them on your facebook’s wall? Just switch apis and use: apsdb.social.facebook[callApi | getApiCall]

For detailed info about 

  • creating your twitter/facebook developer account
  • getting permissions from users to access their accounts
  • calling all apis
  • the authentication / permission flow

check the following links

Also, check our website / facebook page for updates and new releases for upcoming support of new networks like linkedIn and YouTube.

User Registration

As a complement to the article on User Management, this article describes the tools that are provided by Apstrata in order to simplify user registration. Indeed, along the “SaveUser” API, Apstrata also ships with server-side scripts and a JavaScript/HTML 5 registration widget that facilitate the work of the developers (more on server-side scripting with Apstrata).

The scripts implement a registration process in three steps:

  1. Create a user in the user store and tag it as suspended. A suspended user cannot log-in to an application that delegates Identity management to Apstrata.
  2. Send a verification e-mail to the user who has registered, with a link he needs to click on in order to validate his registration
  3. Un-suspend the user once the verification is done (the user is now able to use the application) and send a confirmation email.

As for the JavaScript/HTML 5 registration widget, it can be easily dropped into an HTML (or PHP) page to display a registration form containing the mandatory users fields (login, name, password, email) as well as some other fields (job title, web site, company and phone). It is of course possible to modify the form in order to add and/or remove some fields, as it will be explained in the following paragraphs.

Please note that the scripts and the widgets are complementary to each others and to the SaveUser API, therefore, they can be used separately or in conjunction. These scripts and the widget are part of the Apstrata SDK application that can be downloaded from here

The server-side registration scripts.

The registration process is implemented by four scripts that you will need to deploy on your Apstrata account. In order to deploy a script on your Apstrata account, just copy the script content from your favorite IDE, then open the “Scripts” section of the apstrata workbench and paste it there as a new script (keep the same names).

1. widgets.common

This is a configuration placeholder, where you will notably specify the URL of your Apstrata cluster, your authentication Key, as well as the template of the e-mail that will be sent to the users that have submitted their registration. This script contains many configuration parameters that you will have to fill, among which: 

  • projectName = This is the name of your application. It will be sent in the verification e-mail
  • defaultUsersGroup = Users can belong to zero or many groups in Apstrata. Filling this variable specifies the group to which all subscribed users will automatically be assigned. Please note that this group has to be created before using the registration scripts.
  • apstrataHomeKey = This is the authentication key of the account owner of the application. 
  • apstrataHomeSecret = This is the secret of the account owner of the application. 
  • sendEmailOnceRegistrationConfirmed = Set this parameter to true if an email should be sent to the user upon successful registration. The e-mail address to use is specified using the configuration.templatesConfirmed.adminEmail parameter in the script.
  • registrationRedirectUrl = This parameter is optional. It defines a URL to which the “registerUser” script (see below) will redirect once the user submits his registration or once he clicks on the verification link received by e-mail. 
2. widgets.Registration.registerUser

The “registerUser” script implements the first two steps of the registration process described above. It is the script that you need to call in order to submit a user’s registration, whether you used the provided widgets to capture the registration information or if you provided your own HTML form. You should normally not modify this script, unless you have additional requirements.

When ran, the script will first verify if the registration data it received matches and existing user. If not, it will create a new user and tag it as suspended, then send a verification e-mail if configured to do so (default behavior in the configuration script).

Note that the “registerUser” script will create a user with all the data sent by the registration form (you are not limited to the aforementioned user fields), as long as the field names are prefixed with user.”. Also note the form should send the type of all fields that are not of type string. This is done simply by adding a hidden field in the form such as fieldName.apsdb.fieldType = type, for every field. Types should be one of: date, numeric, text. For more on this topic, please refer to the "SaveUser" API documentation.

Invoking the registerUser script can be done in two different ways:

  1. By invoking the script through a REST service call
  2. By invoking the service from JavaScript, using the Apstrata JS SDK.

1. Invoking the registerUser script through a REST service call

You need to build the following request:

https://varick.apstrata.com/apsdb/rest/[auth key]/RunScript

with the following parameters:

"apsdb.scriptName": "widgets.Registration.registerUser", 
"apsws.time": [timestamp],
"apsws.authSig": [the hash generated as a result of signing the request with the authentication key and secret],
"apsws.authMode": "simple",
"user.name": [first name last name],
"user.email": [user's email],
"user.login": [user's login],
"user.password": [user's password],
//... any other user field,

2. Invoke the registerUser script from the Apstrata JS SDK

// Create a new Apstrata connection using your account owner's credentials
var connection = new apstrata.sdk.Connection({
 credentials: {
 key: "[authentication key]",
 secret: "[secret]"
 },
 loginType: "master"
})

// Instantiate an Apstrata JS Client object passing the connection
var client = new apstrata.sdk.Client(connection)

// Prepare the parameters of the call (notice that the signing will be handled by the Apstrata JS client)
var attr = {
 "action": "RunScript", 
 "request": {
 "apsdb.scriptName": "widgets.Registration.registerUser", 
 "user.name": "[last name, first name]", 
 "user.login": "[user's login]", 
 "user.email": "[user's emails]", 
 "user.password": "[user's password]"
 }
}

// Executes the call to apstrata
client.call(attr.action, attr.request).then(
 // The event handler that gets called on success
 function(response) {
 // Replace with appropriate code
 console.dir(response)
 },
 // The event handler that gets called on call failure
 function(operation) {
 // Replace with appropriate code
 console.dir(operation.response)
 }
)
3. widgets.Registration.userExists

This script is used by the preceding one. It verifies if the registration data matches an existing user. You normally should not modify this script.

4. widgets.Registration.verifyAccount

This script implements the third step of the registration process. It is triggered by clicking on the link sent in the verification e-mail. The script verifies that the parameters received match a validation code and an existing login. When it is the case, the script un-suspends the user who is now able to log-in to the application. Last, if configured to do so (as per the values of the parameters defined in “widgets.common”), a confirmation e-mail will be sent to the user who will also optionally be redirected to the specified “registrationRedirectUrl”.

The Registration widget

The “RegistrationWidget” is a JavaScript/HTML 5 component that ships with the Apstrata JS SDK. If you are a JavaScript developer, then you should probably use this widget by simply dropping it into your HTML/JS pages. The “RegistrationWidget” provides many useful out of the box features, such as:

  • Display of a registration form
  • Verification of required fields (login, password and e-mail)
  • Validation of the password and e-mail fields (users will have to re-enter their password in the registration form and the widget will compare the two values. As for the e-mail, the widget makes sure that the entered value matches the e-mail standard format)
  • Verification of e-mail existence (the widget calls the widgets.Registration.userExist script to verify that a user with the same e-mail does not already exist)
  • Call of the widgets.Registration.registerUser script upon submission of the form.
How to use the “RegistrationWidget” ?

To use the “RegistrationWidget”, first make sure that you have the Apstrata JS SDK available as a library in your client application (the SDK also requires you to download the dojo 1.6 toolkit).

In your HTML, simply import the “RegistrationWidget” and place the component into a DOM node as demonstrated in the following example:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
 <title>apstrata.ui.widgets.RegistrationWidget test page</title>

 // Include the dojo library and enable parsing of the widgets while loading the document
 <script type="text/javascript" src="../../../../lib/dojo/dojo/dojo/dojo.js" djConfig="parseOnLoad: true, isDesbug: true"></script>

 // Include the apstrata library
 <script type="text/javascript" src="../../../sdk/apstrata.js"></script>

 // Import the required dojo and apstrata style sheets
 <style>
 @import "../../../../lib/dojo/dojo/dijit/themes/claro/claro.css";
 @import "../../themes/apstrata/apstrata.css";
 @import "../../themes/apstrata/RegistrationWidget.css";
 </style>

     <script type="text/javascript">

 	// Import the Apstrata JS Client class
	dojo.require("apstrata.sdk.Client");

 	// Import the dojo widget parser
 	dojo.require("dojo.parser");

 	// Import the RegistrationWidget class
 	dojo.require("apstrata.ui.widgets.RegistrationWidget");

 	// Import the Apstrata ApConfig class that contains the applications's configuration
 	// notably the Apstrata cluster URL and the credentials to use
 	dojo.require("apstrata.sdk.ApConfig");


	// When the DOM tree is ready and all required classes have been resolved
 	dojo.ready(function() {

 		// Create an instance of the RegistrationWidget component
 		var rw = new apstrata.ui.widgets.RegistrationWidget();

 		// Place the widget dom node into the document body... and that's it !
 		dojo.place(rw.domNode, dojo.body());
 	})
 </script>
 </head>
 <body class='claro apstrata'>
 </body>
</html>
How to extend the RegistrationWidget?

Some developers will probably need to extend the existing “RegistrationWidget” by adding supplementary fields or removing existing ones, or by adding additional actions to the registration form (currently the form only offers the “save” action that submits the form). The good news is that this is actually very easy to do. 

Form definitions

The Apstrata JS SDK ships with a “FormGenerator” component, which is used to generate HTML forms. This component is used by all form-related widgets in the Apstrata JS SDK, such as the “RegistrationWidget”. Although the complete description of the “FormGenerator” capabilities is beyond the scope of this article, it suffices to know that the “FormGenerator” requires a “form definition” to be defined in order to generate a form. A “form definition” is a simple JavaScript object that defines the field used in the form as well as the actions that will be exposed by this latter.

If you look inside the “RegistrationWidget” class, this is the form definition that you will find:

definition: {
 label: "User Registration",
 cssClass: "newClass",
 fieldset: [
 	{name: "required", label: "", type: "subform", style: "form", cssClass:"column",
 	fieldset: [
 		{name: "name", label: "Name", type: "string", required: true},
		{name: "email", label: "Email", type: "string", required: true},
 		{name: "password", label: "Password", type: "password", required: true},
 		{name: "confirmPassword", label: "Confirm Password", type: "password", required: true, attrs: {invalidMessage: "Passwords don't match"}},
 		]
 	},
 	{name: "optional", label: "", type: "subform", style: "form", cssClass:"column", 
 	fieldset: [
 		{name: "jobTitle", label: "Job title", type: "string"},
		{name: "webSite", label: "Website", type: "string"},
 		{name: "company", label: "Company", type: "string"},
 		{name: "phone", label: "Phone", type: "string"}
 		]
 	},
 ],
 actions: ['save']
 },

And if you look a bit further in the code of that class, you will find the definition of the “save” action (a function), which will be bound to the form:

save: function(values) {
 var self = this

 var request = {
 	"apsdb.scriptName": "widgets.Registration.registerUser",
 	"user.login": values.email,
 	"user.groups": "users"
 }

 delete values.confirmPassword

 for (k in values) {
 	request["user."+k] = values[k]
 } 

 this.client.call("RunScript", request, null, {method: "get"}).then(
 function(response) {
 	if (response.result.metadata.errorCode == "DUPLICATE_USER") {
 		self.message(self.nls.EMAIL_ALREADY_REGISTERED)
 		self.form.getField("email").invalidMessage = self.nls.EMAIL_ALREADY_REGISTERED +" <a href=''>" + self.nls.LOGIN + "</a>"
 		self.form.getField("email").validator = function(value, constraints) {
 			return false // true if email not found, false otherwise
 		}
 	self.form.validate()
 	}

 	window.location = response.result.url;
 }, 
 function(response) {
 	console.dir(response)
 })

 if (values.password != values.confirmPassword) { } else { }
 }

Adding fields and actions to the existing “RegistrationWidget”

Now do not dive too much into the details of the above code and let us get back to our initial concern, which is adding new fields and actions to the initial form definition. All you have to do is to:

  • Create a new registration widget class that will extend the former, 
  • Override the existing definition with a new one. 
  • Provide a new function for every new action in your form and connect these function to the “onAction” event (this event is fired when a button matching an action is clicked on the form).

Let us demonstrate this with an example. Assume that we need the following fields: “first name”, “last name”, “email”, “password”, and “country” (a combo box), as well as a “cancel” function that cleans up the form.

This is how your new registration widget would look like:

// this is the demo/ExtendedRegistrationWidget.js file
dojo.provide("demo.ExtendedRegistrationWidget");
dojo.require("apstrata.ui.FlashAlert")

dojo.require("apstrata.sdk.Client")
dojo.require("apstrata.sdk.Connection")
dojo.require("apstrata.ui.widgets.RegistrationWidget");

dojo.requireLocalization("apstrata.ui.widgets", "registration-widget")

/**
 * Extended version of User registration widgets. 
 * 
 * @param {Object} attrs
 */
dojo.declare("demo.ExtendedRegistrationWidget", 
[apstrata.ui.widgets.RegistrationWidget], 
{
  // This is the new definition
  definition: {
    label: "User",
    cssClass: "newClass",
    fieldset: [
      {name: "required", label: "", type: "subform", style: "form", cssClass:"column",
        fieldset: [
          {name: "first_name", label: "First Name", type: "string", required: true},
          {name: "last_name", label: "Last Name", type: "string", required: true},
          {name: "email", label: "Email", type: "string", required: true},          
   	  {name: "country", label: "Country", type: "string", widget: "dijit.form.ComboBox", "formGenerator-options": ["USA", "Canada", "China", "France", "Lebanon"]},
          {name: "password", label: "Password", type: "password", required: true},
          {name: "confirmPassword", label: "Confirm Password", type: "password", required: true, attrs: {invalidMessage: "Passwords don't match"}},
        ]
      },
    ],
    actions: ['save', 'cancel']
  },
    

  // override the postCreate function
  postCreate: function() {
    // Let the parent class handle all the creation work
    this.inherited(arguments);

    // FormGenerator class has an "onAction" method that is called when an action is clicked. We connect to it
    // in order to re-route the event to the cancel function we need to add to the parent class
    dojo.connect(this.form, "onAction", this, "_onAction");        
  },
    
  // this function is called every time an action (button) is clicked on the widget
  _onAction: function(action, values) {
    if (action == "cancel") {
      this.cancel(values);
    } else if(action == "save") {
       this.save(values); // call the inherited save function
    }
  },
    
  // cancellation logic.  
  cancel: function(values) {
    this.form.frmMain.reset();    
  }
    
})

User Management

Almost every application requires some kind of user management, where a user is required to register for an account, to join a group, or to login to the application. Apstrata makes all that easy for the developer, without having to worry about administering or managing his/her own user directory nor having to worry about writing code to handle each of the previously mentioned features. 

Apstrata is a back-end as a service solution, providing the building blocks needed for you to build an application. It provides a set of cloud API services, among which is a set of services for Identity Management. In this post we will be showing code examples to show how easy it is to manage a User in the Apstrata service.

Examples are listed below on how to register a user, authenticate a user, and add/remove a user from a group. Please note that in the following examples, a JSON response is returned for each request indicating its success or failure.  NOTE: These examples use the REST API interface and assume that the REST calls are made via an Apstrata application account and are signed appropriately. User management features are also available via native iOS and Android SDKs. For more details explore our website at apstrata.com.

User Registration

In order to add a user to the directory, you will need to make a REST call to the SaveUser service as follows:

Request URL: 

	https://varick.apstrata.com/apsdb/rest/[authentication_key]/SaveUser

Request Parameters:

	apsws.time: [current time in milliseconds]
	apsws.authSig: [the hash generated as a result of signing the request with the authentication key and secret]
	login: [login of the user]
	password: [password of the user]
	name: [full name of the user]
	email: [email address of the user]

Additional fields can be saved in the user profile as needed. Please refer to the documentation of the SaveUser service for more details.

Moreover, two-steps registration can be easily achieved as follows:

Step 1: User enters his personal info

Request URL:


	https://varick.apstrata.com/apsdb/rest/[authentication_key]/SaveUser


Request Parameters:

	apsws.time: [current time in milliseconds]
	apsws.authSig: [the hash generated as a result of signing the request with the authentication key and secret]
	login: [login of the user]
	password: [password of the user]
	name: [full name of the user]
	email: [email address of the user]
	isSuspended: true

Step 2: User confirms his registration

Request URL: 

	https://varick.apstrata.com/apsdb/rest/[authentication_key]/SaveUser


Request Parameters:

	apsws.time: [current time in milliseconds]
	apsws.authSig: [the hash generated as a result of signing the request with the authentication key and secret]
	login: [login of the user]
	isSuspended: false
	apsdb.update: true

In step 2, we simply activate the user by updating his profile. A user who is suspended has no access to the Apstrata API services.

User Authentication

In order to authenticate a user, you will need to make a call to the VerifyCrendentials service as follows:

Request URL:


	https://varick.apstrata.com/apsdb/rest/[authentication_key]/VerifyCredentials


Request Parameters:


	apsws.time: [current time in milliseconds]
	apsws.user: [login of the user to be authenticated]
	apsws.authSig: [the hash generated as a result of signing the request with the password of the user being authenticated]
User Groups

Groups may be used to specify read, write, and/or delete permissions on the data. A user can be a member of multiple groups.

In order to add a group, you will need to make a REST call to the SaveGroup service as follows:

Request URL:


	https://varick.apstrata.com/apsdb/rest/[authentication_key]/SaveGroup


Request Parameters:


	apsws.time: [current time in milliseconds]
	apsws.authSig: [the hash generated as a result of signing the request with the authentication key and secret]
	groupName: [name of the group]

In order to add a new user to one or more groups, you will need to make a call to the SaveUser service as follows:

Request URL:

	https://varick.apstrata.com/apsdb/rest/[authentication_key]/SaveUser


Request Parameters:


	apsws.time: [current time in milliseconds]
	apsws.authSig: [the hash generated as a result of signing the request with the authentication key and secret]
	login: [login of the user]
	password: [password of the user]
	name: [full name of the user]
	email: [email address of the user]
	groups: [group 1]
	groups: [group 2]
	groups: [group n]

In order to add an existing user to one or more groups, you will need to make a call to the SaveUser service as follows:

Request URL:


	https://varick.apstrata.com/apsdb/rest/[authentication_key]/SaveUser


Request Parameters:


	apsws.time: [current time in milliseconds]
	apsws.authSig: [the hash generated as a result of signing the request with the authentication key and secret]
	login: [login of the user]
	apsdb.update: true
	apsdb.multivalueAppend: [the name of the groups parameter i.e. "groups"; this avoids removing the existing groups membership for the user and appends to the existing ones]
	groups: [group 1]
	groups: [group 2]
	groups: [group n]

In order to remove a user from a specific group, you will need to make a call to the SaveUser service as follows:

Request URL:


	https://varick.apstrata.com/apsdb/rest/[authentication_key]/SaveUser


Request Parameters:


	apsws.time: [current time in milliseconds]
	apsws.authSig: [the hash generated as a result of signing the request with the authentication key and secret]
	login: [login of the user]
	apsdb.update: true
	groups.apsdb.delete = [groupname from which to remove the user]
(via Introducing Apstrata | Keeward’s TechWatch blog)
Keeward is an awesome web agency (and much more) based out of Paris and Beirut. This post sums the thoughts of one of their talented developer&#8217;s as he starts discovering apstrata. 

(via Introducing Apstrata | Keeward’s TechWatch blog)

Keeward is an awesome web agency (and much more) based out of Paris and Beirut. This post sums the thoughts of one of their talented developer’s as he starts discovering apstrata. 

Happy 4th of July Everyone

We got your back.

twitter.com/apstrata

view archive



Home Page

Ask me anything