14q2 Bitcoin Spanish
14q2 Bitcoin Spanish
All rights reserved. No parts of this work may be reproduced in any form or by any means - graphic, electronic, or
mechanical, including photocopying, recording, taping, or information storage and retrieval systems - without the
written permission of the publisher.
Products that are referred to in this document may be either trademarks and/or registered trademarks of the
respective owners. The publisher and the author make no claim to these trademarks.
While every precaution has been taken in the preparation of this document, the publisher and the author assume no
responsibility for errors or omissions, or for damages resulting from the use of information contained in this
document or from the use of programs and source code that may accompany it. In no event shall the publisher and
the author be liable for any loss of profit or any other commercial damage caused or alleged to have been caused
directly or indirectly by this document.
User Service 6
1 Overview
................................................................................................................................... 6
2 Setup ................................................................................................................................... 6
3 Core Classes
................................................................................................................................... 7
4 Error Handling
................................................................................................................................... 8
5 User Properties
................................................................................................................................... 9
6 Retrieve
...................................................................................................................................
User Entity Properties 10
7 User Registration
................................................................................................................................... 12
8 Login................................................................................................................................... 15
9 Update
...................................................................................................................................
User Properties 18
10 Get Current
...................................................................................................................................
User 20
11 Logout
................................................................................................................................... 21
12 Password
...................................................................................................................................
Recovery 22
13 Security
................................................................................................................................... 24
14 Role to
...................................................................................................................................
User Mapping 28
Data Service 29
1 Overview
................................................................................................................................... 29
2 Setup................................................................................................................................... 29
3 Sync ...................................................................................................................................
and Async Calls 30
4 Error ...................................................................................................................................
Handling 31
5 Native...................................................................................................................................
vs External Databases 31
6 Using...................................................................................................................................
External Databases 32
7 Data Object
................................................................................................................................... 36
8 Saving
...................................................................................................................................
Data Objects 36
9 Updating
...................................................................................................................................
Data Objects 38
10 Deleting
...................................................................................................................................
Data Objects 42
11 Retrieving
...................................................................................................................................
Schema Definition 46
12 Basic...................................................................................................................................
Search 47
13 Advanced
...................................................................................................................................
Search 50
14 Using...................................................................................................................................
Dates in Search 54
15 Relations
...................................................................................................................................
Overview 56
16 Relations
...................................................................................................................................
(Save/Update) 62
17 Relations
...................................................................................................................................
(Delete) 69
18 Relations
...................................................................................................................................
(Retrieve) 72
3
4 Backendless API for JavaScript
19 Relations
...................................................................................................................................
with Geo Points 77
20 Security
................................................................................................................................... 83
Messaging Service 89
1 Overview
................................................................................................................................... 89
2 Setup................................................................................................................................... 90
3 Core ...................................................................................................................................
Classes 91
4 Sync ...................................................................................................................................
and Async Calls 93
5 Error ...................................................................................................................................
Handling 93
6 Push ...................................................................................................................................
Notification Setup (Android) 94
7 Push ...................................................................................................................................
Notification Setup (iOS) 97
8 Message
...................................................................................................................................
Publishing 107
9 Publish
...................................................................................................................................
Push Notifications 116
10 Cancel
...................................................................................................................................
Scheduled Message 118
11 Message
...................................................................................................................................
Subscription 119
12 Cancel
...................................................................................................................................
Subscription 123
13 Sending
...................................................................................................................................
Email 124
Index 200
5
6 Backendless API for JavaScript
1 User Service
1.1 Overview
The Backendless User Service empowers applications with the functionality related to the user accounts
such as user registrations, logins, password recovery and logouts. The core concept which the User
Service relies on is the User entity. The structure of the entity is configurable, that is a developer can
decide which properties "describe" a user in the context of a given version of the application. Typically,
properties describing a user are the ones collected during the user registration process. The User
Service provides the API enabling the following functionality for the applications built on top of
Backendless:
User Registration - Applications use the Backendless' registration API to let the users register
and create accounts for subsequent logins. Application developers can restrict access to the
server-side resources for specific user accounts or based on roles.
User Login - the API lets the registered users login to establish their identity within the
application.
Password Recovery - Backendless supports a complete workflow allowing users to recover lost or
forgotten passwords.
User Logout - the API lets the logged in users terminate their session and disassociate their
identity from the application.
Updating User Registration - the API supports the operation of updating user information.
1.2 Setup
To get access to the Backendless services, JavaScript applications must reference the backendless.js
library. The library can be retrieved using any of the approaches listed below:
1. Download Backendless SDK for JavaScript. The SDK can be downloaded from the Backendless
website
2. Install the Backendless Bower package:
bower install backendless
compressed library:
http://api.backendless.com/sdk/js/latest/backendless.min.js
Before the JavaScript client uses any of the APIs, the code must initialize the Backendless Application
using the following call:
Backendless.initApp( application-Id, secret-key, version )
Make sure to use the "JavaScript Secret Key" for the secret-key argument.
The version argument must contain the name of the targeted version. When a new application is
created, the default version name is "v1" . To manage versions, login to the console, select the
"Manage" icon and click "Versioning".
Backendless.UserService - provides access to the user service API. All user-related operations,
such as user registration, user update, login, logout and password recovery are available through this
class.
Backendless.User - represents a user registered with the application. The class is used in:
User Registration - an instance of the class contains a list of user properties
User Registration/Properties Update - an instance of the class contains a list of properties to be
updated
The Login method returns an instance of the class upon successful login.
The Backendless.User definition contains only one field - password . All other fields can be defined
on the fly - see User Registration for details.
Backendless.Async - a construct used in the asynchronous API calls. Must reference two functions:
one accepting a result from the server and the other for handling errors reported by the server.
Backendless.Async Definition
The Backendless.Async function is defined as:
Backendless.Async = Async;
where:
successCallback - a reference to a function which will be called when the server returns a
result. The signature of this callback function must accept one argument
which will be the actual result object returned by the server.
faultCallback - an (optional) reference to a function which will be called if the server
returns an error. The function must accept one argument which is a fault
object containing the information about the error.
context - an (optional) reference to the object which is used as "this" when
calling successCallback or faultCallback
where:
message - contains a string value with the description of the error
statusCode - error code as a string value. Currently all the error codes are numbers,
however the method returning the error code returns the String type. This is
done for future expansion of the error code system which may include
characters.
The asynchronous calls receive the fault through the fault callback referenced in the Async function.
For the synchronous calls the fault object is thrown as an error which must be handled in a catch( err
) block:
try
{
backendlessAPIcall();
}
catch( err )
{
console.log( "Error message - " + err.message );
console.log( "Error code - " + err.statusCode );
}
The interface consists of two lists: Available Properties and Selected Properties. The Selected
Properties list contains the properties assigned to the User entity - these are the effective properties for
the selected version of the application. The Available Properties list is simply a storage for the non-
effective properties which can be moved to the Selected list if needed. A property can be moved between
the lists by clicking its name.
Identity Property
Among the Selected Properties, one must be marked as identity. This is the property Backendless
uses for the Login and Restore Password operations.. As users register, Backendless ensures the
provided value for the property selected as identity is unique in the context of a specific version for
an application.
Password Property
"password" is a special property. Backendless automatically adds the property when an application
is created. The following rules apply to the password property:
Password cannot be moved out of the Available Properties list.
Password cannot be marked as Identity.
Password is always a required property
To add a property, click the "Add Custom Property" button. New properties automatically added to the
Selected Properties list. To move a property to the other list, simply click its name.
where:
callback - an an instance of Backendless.Async which receives either a return value or an error
from the server. The return value from the server is an array of the objects describing
properties of the User entity for the specified version of the application. The structure of
the object in the response array is:
The method's return value is an array of the objects describing properties of the User entity for the
specified version of the application. See above for the object's structure.
( gotPropertyDesc, gotError ) );
for( i in props )
{
console.log( "property name - " + props[ i ].name );
console.log( "\tis property required - " + props[ i ].required );
console.log( "\tproperty data type - " + props[ i ].type );
console.log( "\tdefault value - " + props[ i ].defaultValue );
console.log( "\tis property identity - " + props[ i ].identity );
}
where:
user - an instance of the Backendless.User class which contains property values
for the account registration.
asyncCallback - an instance of Backendless.Async . Receives either a return value or an error
from the server. The return value from the server is an instance of the
Backendless.User class with the ID assigned by the server-side.
where:
user - an instance of the Backendless.User class which contains property values
for the account registration.
Error Codes:
The following errors may occur during User Registration API calls. See the Error Handling section for
details on how to retrieve the error code when the server returns an error.
Error Description
Code
2002 Version is disabled or provided wrong application info (application id or
secret key)
try
{
Backendless.UserService.register( user );
}
catch( err )
{
console.log( "error message - " + err.message );
console.log( "error code - " + err.statusCode );
}
The "Registration" toggle turns the registration API on or off. When the registration is turned off and a
user attempts to register, the system returns error 3009 .
Email Confirmations
Backendless can send out an email requesting new registered users to confirm their email address. This
feature can be configured in the Backendless Console:
1. Log into the console and select the application.
2. Click the "Users" icon in the vertical icon menu on the left.
3. Click "Registration".
When email confirmations are required (the feature is enabled by default), the "email" user property is
required and must contain a value formatted as an email address. To configure the text of the email
message, select "Communication & Email Templates" from the Users menu in the console and select
the "User registers" event.
External Registration
User registrations can be duplicated in an external system through the External Registration Callback.
Developer can specify a URL where Backendless sends a POST request to with the user registration
data as a JSON object. The external registration callback is synchronous and takes place in the same
transaction as the Backendless registration call. As a result, the external system must return result as
fast as possible. The format of the request and response for the external registration is the same as the
request/response body of the Backendless registration API.
To configure the callback:
1. Login to the console and select the application.
2. Click the "Users" icon in the vertical icon menu on the left.
1.8 Login
Registered users can login to establish their identity with the application using the API below. The login
operation requires two properties: one marked as user identity and the second is password .
Backendless automatically assigns the "AuthenticatedUser" role to all successfully logged in users.
The role can be used to differentiate access to various resources (persistent objects, messaging
channels, media streams) between authenticated users and guests.
Asynchronous Method:
The method call does not block - it returns immediately. The AsyncCallback argument receives
either the response or the fault returned by the Backendless servers.
Backendless.UserService.login( login, password, stayLoggedIn,
asyncCallback );
where:
login - a value for the property marked as identity.
password - user's password
stayLoggedIn - a Boolean value requesting user login information to be saved
so it can be reused when the application restarts (or page is
reloaded). Use the following API to check if the login information
is available from a previous run:
if( Backendless.LocalCache.get("user-token") )
{ // user login information is available, skip the login form }
where:
login - a value for the property marked as identity.
password - user's password
stayLoggedIn - a boolean value requesting user login information to be saved so
it can be reused when the application restarts (or page is
reloaded). Use the following API to check if the login information
is available from a previous run:
if( Backendless.LocalCache.get("user-token") )
{ // user login information is available, skip the login form }
Error Codes:
The following errors may occur during the Login API call. See the Error Handling section for
details on how to retrieve the error code when the server returns an error.
Error Description
Code
2002 Version is disabled or provided wrong application info (application id
or secret key)
3000 Login has been disabled for the user account.
3001 Missing login settings, possibly invalid application id or version.
3002 User cannot login because Multiple Logins disabled and there is a
logged in user for the account.
3003 Invalid login or password.
3006 Either login or password is an empty string value.
3034 User logins are disabled for the version of the application.
3036 Account locked out due to too many failed logins.
3038 One of the required parameters (application id, version, login or
password) is null
3044 Multiple login limit for the same user account has been reached.
8000 Property value exceeds the length limit
var user;
try
{
External Authentication
Similar to external registration, Backendless supports external authentication. When configured,
Backendless delegates the authentication process to an external system by sending the provided
user credentials to a URL. The URL of the external authentication system can be configured in
Backendless Console:
1. Log into the console and select the application.
2. Click the "Users" icon in the vertical icon menu on the left.
3. Click "Login".
4. The "External authentication" section contains the configuration settings.
When the external authentication is enabled and user attempts to login, Backendless sends the
following request to the specified URL:
POST http://external-authentication-url
Authorization: Basic base64-encoded-login:password
Multiple Logins
The Multiple Logins feature enables login using the same account from different computers or
devices. Multiple logins can be configured in the Backendless Console:
1. Log into the console and select the application.
2. Click the "Users" icon in the vertical icon menu on the left.
3. Click "Login".
4. The "Multiple Logins" section contains the configuration settings.
When the feature is turned on (multiple logins allowed), the configuration setting may include the
maximum number of simultaneous logins for the selected version of the application. When the
feature is disabled (multiple logins are not allowed), the configuration must indicate whether which
login should be invalidated (first or second for the account):
Session Timeout
Backendless supports session expiration which can be configured in console. Along with the
session timeout interval, the configuration can also include a forwarding URL which is used to
redirect requests to for the expired sessions.
Account Lockout
An application powered by Backendless can be configured to lock out accounts with failed logins.
The console has two configuration options: number of failed logins before the account is locked and
a time interval to wait before the account is available for logins again.
where:
user - an instance of the Backendless.User class which contains property values to
where:
user - an instance of the Backendless.User class which contains property values to
be updated for the account.
Error Codes:
The following errors may occur during the Update User Properties API call. See the Error Handling
section for details on how to retrieve the error code when the server returns an error.
Error Description
Code
2002 Version is disabled or provided wrong application info (application id or
secret key)
3018 The property marked as "identity" is being updated and another user
already has the specified value which must be unique.
3024 General "update registration" error. Error message should contain
additional details.
3028 User is not logged in.
3029 Cannot modify properties of another user. Returned when one user is
logged and the call attempts to modify properties of another user.
3030 Unable to locate user account - invalid user id.
3031 A new "dynamic" property is being added, but dynamic property
definition is disabled.
3045 Required properties in the provided object do not contain values.
function updateUser()
{
user.address = "123 Main St";
Backendless.UserService.login( user, new Backendless.Async
( userUpdated, gotError ) );
}
var user;
try
{
user = Backendless.UserService.login( username, password );
}
catch( err )
{
// login failed
console.log( "error message - " + err.message );
console.log( "error code - " + err.statusCode );
}
try
{
user.phoneNumber = "5551212";
user = Backendless.UserService.update( user );
}
catch( err )
{
// update failed
console.log( "error message - " + err.message );
console.log( "error code - " + err.statusCode );
}
1.11 Logout
The Logout operation terminates user session and disassociates the AuthenticatedUser role from the
subsequent requests made by the client application.
where:
asyncCallback - an instance of Backendless.Async . Receives either a notification or an error
from the server.
Error Codes:
The following errors may occur during the Logout API call. See the Error Handling section for details on
how to retrieve the error code when the server returns an error.
Error Description
Code
2002 Version is disabled or provided wrong application info (application id or
secret key)
3007 Invalid application-id or version.
3023 General error while executing logout. Error details should be available in
the message property.
function userLoggedout()
{
function logoutUser()
{
Backendless.UserService.logout( new Backendless.Async
( userLoggedout, gotError ) );
}
try
{
user = Backendless.UserService.login( username, password );
}
catch( err ) // see more on error handling
{
// login failed, to get the error code, call err.statusCode
console.log( "error message - " + err.message );
console.log( "error code - " + err.statusCode );
}
try
{
// now log out:
Backendless.UserService.logout();
}
catch( err ) // see more on error handling
{
// logout failed, to get the error code, call err.statusCode
console.log( "error message - " + err.message );
console.log( "error code - " + err.statusCode );
}
where:
where:
identityValue - a value for the property marked as identity.
Error Codes:
The following errors may occur during the Password Recovery API call. See the Error Handling section
for details on how to retrieve the error code when the server returns an error.
Error Description
Code
2002 Version is disabled or provided wrong application info (application id or
secret key)
3020 Unable to find user with the specified login (invalid user identity).
3025 General password recovery error. Additional details should be available
in the "message" property of the response.
3038 One of the requirement arguments (application id, version or user
identity) is missing.
try
{
1.13 Security
All Backendless API operations can be restricted either for specific user accounts or for roles. A user
account may be associated with one or more roles. Backendless supports several built-in system roles
as well as developer-defined roles. The system roles include:
NotAuthenticatedUser - any user who has not authenticated to a Backendless application.
AuthenticatedUser - any user who has successfully logged in.
SocialUser - any user who has logged in through a social network.
FacebookUser - any user who has logged in with a Facebook account.
TwitterUser - any user who has logged in with a Twitter account.
Developer-defined roles can be added using the Backendless Console. Roles are defined at the
application version level, that is a particular version of an application may have its own set of developer-
defined roles.
There are two levels of permissions for the API operations - global and resource-specific. The resource-
specific permissions guard access to the specific resources (data tables, messaging channels, etc).
They have higher priority and are checked first. When Backendless receives an API call from a client, it
determines the user associated with the request and obtains a list of roles associated with the user
account (for the users who have not authenticated, the NotAuthenticatedUser role is used). The
resource-specific permissions can be set to either inherit the permission from the global matrix or
explicitly grant or deny access to the resource for the given user or role. The diagram below illustrates
the process when the resource-specific permission is set to inherit:
When the resource-specific permission is explicitly set to either grant or deny access, the global
permissions are bypassed:
Global Permissions
The global service permissions apply to all resources managed by a particular service. For example,
global Data Service permissions for a particular role apply to all data tables. These permissions can be
viewed and modified by clicking a role on the Users > Security and Restrictions screen in Backendless
Console:
To register a new role use the "Add Role" button on the "Security and Restrictions" screen. Once a role
is added, you can configure it's global permission matrix as well as resource-specific permissions.
Resource-Specific Permissions
To view, assign or modify resource-specific permissions, use a corresponding screen in the
Backendless Console. For example, to restrict access to a data table, switch to the Data view, select a
table and click the "Schema and Permissions" button. The user interface has two views - one is for
managing permissions for user accounts and the other for roles. To modify permissions for a user
account:
1. Click the "User Permissions" list item.
2. Enter the user name in the search field.
3. Select the user and click the "Add" button.
4. The table displays the permissions for various operations for the selected user and the resource.
5. Click an icon representing the permission state to modify the permission.
Similarly permissions can be assigned or modified for specific roles - use the "Role Permissions" list
item.
To modify the permissions for Messaging channels, click the "Messaging" icon, select a channel and
switch to the "Permissions" view.
Example:
Before retrieving the user roles, log in as described in the Login section. Then, retrieve the user
roles as follows:
function successCallback(data){alert(data)}
function errorCallback(e){alert(e)}
var async = new Backendless.Async(successCallback, errorCallback);
Backendless.UserService.login(username, password, true, new Backendless.Async
( userLoggedInStatus, errorCallback ));
function userLoggedInStatus(){
console.log(Backendless.UserService.getUserRoles());
}
2.1 Overview
The Backendless Data Service is a highly scalable, object storage system. It is available via intuitive API
which supports all basic data persistence operations - Create, Retrieve, Update and Delete (CRUD). The
Data Service operates with persistent data at the object level, that means applications use the APIs to
save, update, delete or search for objects, rather than traditional database records. Developers using the
Data Service API do not need to know or understand the databases, schema creation rules, stored
procedures or SQL syntax.
The Data Service follows the following rules when working with user objects:
1. Objects persisted by the Data Service must specify the "type" or be an instance of a class (for
client applications written in strongly-typed languages).
2. Backendless automatically creates tables for each persisted type it has not seen before and
saves objects in the corresponding tables. Each table has columns corresponding to the
properties of the persisted objects.
3. Backendless creates three additional system-level columns for each new table:
objectId - contains a unique object ID assigned by Backendless to each object.
created - contains a timestamp when the object was first saved by Data Service
updated - contains a timestamp when the object was most recently updated. The value is
null for newly created objects.
4. When an object of a known type/class introduces any new properties throughout the lifetime of
the application, the persistence structure will be modified accordingly. When such an object is
persisted, Backendless analyzes the object's properties and automatically alters the structure of
the corresponding table if any new properties are added.
5. When an object is saved or updated, it may reference another related object (a one-to-one
relationship) or objects (one-to-many). Backendless creates the underlying tables for the main
and the referenced types and persists the hierarchy accordingly.
2.2 Setup
To get access to the Backendless services, JavaScript applications must reference the backendless.js
library. The library can be retrieved using any of the approaches listed below:
1. Download Backendless SDK for JavaScript. The SDK can be downloaded from the Backendless
website
2. Install the Backendless Bower package:
bower install backendless
compressed library:
http://api.backendless.com/sdk/js/latest/backendless.min.js
Before the JavaScript client uses any of the APIs, the code must initialize the Backendless Application
using the following call:
Backendless.initApp( application-Id, secret-key, version )
Make sure to use the "JavaScript Secret Key" for the secret-key argument.
The version argument must contain the name of the targeted version. When a new application is
created, the default version name is "v1" . To manage versions, login to the console, select the
"Manage" icon and click "Versioning".
where:
where:
message - contains a string value with the description of the
error
statusCode - error code as a string value. Currently all the error
codes are numbers, however the method returning
the error code returns the String type. This is done
for future expansion of the error code system which
may include characters.
The asynchronous calls receive the fault through the fault callback referenced in the Async function.
For the synchronous calls the fault object is thrown as an error which must be handled in a catch( err
) block:
try
{
backendlessAPIcall();
}
catch( err )
{
console.log( "Error message - " + err.message );
console.log( "Error code - " + err.statusCode );
}
The external storage can be any database located elsewhere which the Backendless service connects
to with the connection parameters provided by the developer. Currently MySQL/MariaDB databases is
the only type of the supported external storage.
An application must be configured to use either the native or an external storage mechanism, they
cannot be combined into the hybrid mode. However, regardless of which mechanism is enabled, the
Data Service API can be used to work with the data. Additionally, if the application is configured to use
an external database, Backendless console can be used the manage the external data the same way it
does so with native. The only exception is the management of an external schema - Backendless
Console displays it in the view only mode.
To learn more about external data storage, see the Using External Databases chapter.
4. Once a connection is established (it may take several minutes), console displays a list of the
databases in the Database drop-down menu. Select a database and click the Ok button to
confirm your choice.
5. Backendless will inspect the selected database and an email is delivered to the application
developer email address with the status of the inspection.
6. Upon successful database inspection the Data Management screen displays a list of the
tables from the external database.
Re-connect (or edit the connection details) to current external database by clicking the
connect button:
Limitations
© 2015 Backendless Corp.
36 Backendless API for JavaScript
In addition to objectId , Backendless maintains two additional properties for every persisted
object - created and updated . The former contains the timestamp when the object was
initially created in the Backendless data store. The latter is updated every time the object is
updated. To get access to these values use the dynamically assigned properties:
var createdTime = persistedDataObject["created"];
var updatedTime = persistedDataObject["updated"];
where:
constructor-function - a reference to a JavaScript constructor function defining a
JavaScript class. The entity argument must be an instance of
this class.
entity - a JavaScript object to persist, must be an instance of JS-Class.
async - Optional argument. If provided, the method is executed
asynchronously. The successCallback function referenced in the
async object receives a callback when the method successfully
saves the object. If an error occurs, the faultCallback function is
invoked. See Sync and Async Callsfor additional details.
Return Value:
If the method is invoked synchronously, it returns the saved object. The asynchronous call
receives the return value through a callback executed on the Async object.
Example:
Consider the following class:
function Contact(args) {
args = args || {};
this.name = args.name || "";
this.age = args.age || "";
this.phone = args.phone || "";
this.title = args.title || "";
}
});
Backendless.Persistence.of(SampleTable).save(obj);
URL:
https://api.backendless.com/<version>/data/<table-name>/<object-id>
where:
<version> - name of the application's version. Application versions can be
managed using Backendless Console. Login to the console,
select an application, click Manage, then Versioning.
Backendless automatically creates version "v1" for any new
application.
<table-name> - name of the table where the object needs to be updated.
<object-id> - ID of the object to update assigned by Backendless in the
create object operation.
Request Headers:
application-id: app-id-value
secret-key: secret-key-value
Content-Type:application/json
application-type: REST
where:
application-id - the ID of your application generated upon its creation. You can
find this header in the Manage > App Settings section of the
Backendless Console. This header is mandatory. Please refer to
the Setup section for information on how to obtain the values for
the header.
secret-key - the key of your application generated upon its creation. You
can find this header in the Manage > App Settings section of
the Backendless Console. This header is mandatory. Please
refer to the Setup section for information on how to obtain the
where:
updated - special property generated by Backendless which contains the
timestamp when the object was last updated.
created - similar to 'updated', but contains the timestamp showing when
the object was initially created.
ownerId - when the object is created by an authenticated user, this
property contains the id of the currently logged in user object.
objectId - unique id (GUID) assigned to the object.
___class - contains the name of the table where the object is stored. This
is the same value as the <table-name> in the URL.
Example:
curl
-H application-id:application-id-value-from-console
-H secret-key:secret-key-value-from-console
-H Content-Type:application/json
-X PUT
-d "{\"name\":\"Bob\", \"age\":20 }"
-v https://api.backendless.com/v1/data/Person/6C77C11B-E9B3-EB14-
FFA2-69F38CF48800
Notice the objectId value is put directly into the URL. The same value is optional in the JSON
body of the request.
a Native Database
Method:
PUT
URL:
https://api.backendless.com/<app version>/data/bulk/<table-name>?
where=<where clause>
where:
<app version> - name of the application's version. Application versions can be
managed using Backendless Console. Login to the console,
select an application, click Manage, then Versioning.
Backendless automatically creates version "v1" for any new
application.
<table-name> - name of the table where the objects need to be updated.
<where clause> - condition for selecting the objects for the bulk update (please
refer to the examples below in this section). Should be URL
encoded.
Request Headers:
application-id: app-id-value
secret-key: secret-key-value
Content-Type:application/json
application-type: REST
where:
application-id - the ID of your application generated upon its creation. You can
find this header in the Manage > App Settings section of the
Backendless Console. This header is mandatory. Please refer to
the Setup section for information on how to obtain the values for
the header.
secret-key - the key of your application generated upon its creation. You
can find this header in the Manage > App Settings section of
the Backendless Console. This header is mandatory. Please
refer to the Setup section for information on how to obtain the
values for the header.
Content-Type - the static value, should be set to application/json. This header
is mandatory.
application-type - the static value, should be set to REST. This header is
mandatory.
Sample Request:
Bulk update allows changing several data objects selected by the specified criteria. For
instance, if you have the list of employees and need to update their salary info depending on
their time of employment, you can do it by using the bulk update feature.
To test the feature:
1. Create two persons/employees: one employed for 15 days curl -H application-id:
application-id-value-from-console-H secret-key:secret-key-value-
from-console -H Content-Type:application/json -X POST -d
"{\"name\":\"Tom\", \"age\":35, \"salary\":0, \"workDays\":\"15\"}"
-v https://api.backendless.com/v1/data/Person , another one employed for
20 days curl -H application-id:application-id-value-from-console-H
As a result you will receive the response displaying the number of data object updated (2
objects). The salary of both employees will be changed to 1000.
Sample Response:
Server will return the number of the updated objects.
where:
constructor-function - a reference to a JavaScript constructor function defining a
JavaScript class. The entity argument must be an instance of
this class.
entity - a JavaScript object to update, must be an instance of JS-Class.
async - Optional argument. If provided, the method is executed
asynchronously. The successCallback function referenced in the
async object receives a callback when the method successfully
saves the object. If an error occurs, the faultCallback function is
invoked. See Sync and Async Calls for additional details.
Return Value:
If the method is invoked synchronously, it returns the saved object. The asynchronous call
receives the return value through a callback executed on the Async object.
Example:
Consider the following class:
function Contact(args) {
args = args || {};
this.name = args.name || "";
this.age = args.age || "";
this.phone = args.phone || "";
this.title = args.title || "";
}
Please note: deleting an object from a native database differs from deleting an object from an external
database.
URL:
https://api.backendless.com/<version>/data/<table-name>/<object-id>
where:
Request Headers:
application-id: app-id-value
secret-key: secret-key-value
application-type: REST
where:
application-id - the ID of your application generated upon its creation. You can
find this header in the Manage > App Settings section of the
Backendless Console. This header is mandatory. Please refer to
the Setup section for information on how to obtain the values for
the header.
secret-key - the key of your application generated upon its creation. You
can find this header in the Manage > App Settings section of
the Backendless Console. This header is mandatory. Please
refer to the Setup section for information on how to obtain the
values for the header.
application-type - the static value, should be set to REST. This header is
mandatory.
Request Body:
None
Example:
curl
-H application-id:application-id-value-from-console
-H secret-key:secret-key-value-from-console
-X DELETE
-v https://api.backendless.com/v1/data/Orders/6C77C11B-E9B3-EB14-
FFA2-69F38CF48800
URL:
https://api.backendless.com/<app version>/data/bulk/<table-name>?
where=<where clause>
where:
<app version> - name of the application's version. Application versions can be
managed using Backendless Console. Login to the console,
select an application, click Manage, then Versioning.
Backendless automatically creates version "v1" for any new
application.
<table-name> - name of the table where the objects need to be deleted.
<where clause> - condition for selecting the objects for the bulk delete (please
refer to the examples below in this section). Should be URL
encoded.
Request Headers:
application-id: app-id-value
secret-key: secret-key-value
application-type: REST
where:
application-id - the ID of your application generated upon its creation. You can
find this header in the Manage > App Settings section of the
Backendless Console. This header is mandatory. Please refer to
the Setup section for information on how to obtain the values for
the header.
secret-key - the key of your application generated upon its creation. You
can find this header in the Manage > App Settings section of
the Backendless Console. This header is mandatory. Please
refer to the Setup section for information on how to obtain the
values for the header.
application-type - the static value, should be set to REST . This header is
mandatory.
Sample Request:
Bulk delete allows removing several data objects selected by the specified criteria. For instance,
if you have the list of employees and need to delete some of them depending on their time of
employment, you can do it by using the bulk delete feature.
To test the feature:
1. Create three persons/employees:
employed for 15 days curl -H application-id:application-id-value-from-
console-H secret-key:secret-key-value-from-console -H Content-
Type:application/json -X POST -d "{\"name\":\"Tom\", \"age\":35,
\"salary\":0, \"workDays\":\"15\"}" -v https://api.backendless.
com/v1/data/Person
employed for 0 days curl -H application-id:application-id-value-from-
console-H secret-key:secret-key-value-from-console -H Content-
Type:application/json -X POST -d "{\"name\":\"Bob\", \"age\":20,
\"salary\":0, \"workDays\":\"0\"}" -v https://api.backendless.
com/v1/data/Person
employed for 0 days curl -H application-id:application-id-value-from-
console-H secret-key:secret-key-value-from-console -H Content-
Type:application/json -X POST -d "{\"name\":\"Brad\", \"age\":22,
As a result you will receive the response displaying the number of data object deleted (2
objects). The second and third employees (Bob and Brad) will be deleted from the database.
Sample Response:
Server will return the number of the deleted objects.
Backendless.Persistence.of( constructor-function ).remove( dataObject,
async );
where:
constructor-function - a reference to a JavaScript constructor function defining a
JavaScript class. The dataObject argument must be an instance
of the class.
dataObject - a JavaScript object to remove, must be an instance of JS-
Class, alternatively the argument can be objectId of the object to
remove.
async - Optional argument. If provided, the method is executed
asynchronously. The successCallback function referenced in the
async object receives a callback when the method successfully
removed the object. If an error occurs, the faultCallback function
is invoked. See Sync and Async Callsfor additional details.
Return Value:
The synchronous method returns the time stamp when the server-side removed the object from
the data store. The asynchronous call receives the return value through a callback executed on
the Async object
Example:
Consider the following class:
function Contact(args) {
args = args || {};
this.name = args.name || "";
this.age = args.age || "";
this.phone = args.phone || "";
this.title = args.title || "";
}
The following code saves and then deleted an instance of the Contact class:
var APPLICATION_ID = "YOUR-APP-ID",
SECRET_KEY = "YOUR-SECRET-KEY",
VERSION = "v1"; //default application version;
where:
className - name of a table or a reference to a prototype function
corresponding to a table on the backend.
async - optional argument. If provided, the method is executed
asynchronously. The successCallback function referenced in
the async object receives a callback when the method
successfully saves the object. If an error occurs, the
faultCallback function is invoked. See Sync and Async Calls
for additional details.
Return value:
Returns an array of object's properties. Each object in the array describes a column in the
specified table using the structure below:
{
autoLoad: true or false,
customRegex: value,
defaultValue: null or value,
isPrimaryKey: true or false,
name: value,
where:
autoLoad - applies only to relations. If true, the property is set to auto-load
related data for the data retrieval queries.
customRegex - a regular expression assigned to the column as a validator. The
validator applies when a new object is saved in the table or an
existing one is updated.
defaultValue - a default value assigned to any object saved/updated in the
table where the column does not have a value.
isPrimaryKey - true if the column is or is a part of a primary key.
name - contains the name of a property.
relatedTable - contains the name of the related table(s).
required - defines whether a property is optional or required for the
requests which save the initial object or update an existing one.
type - defines the property type.
Example:
The example below demonstrates how to retrieve table schema. Save an object in the persistent
storage (this will force Backendless to create a table for the object of the specified type if one
does not exist yet):
function Sample( args )
{
args = args || null;
this.name = args.name || "SampleName";
}
Please note: searching for an object in a native database differs from searching for an object in an
external database.
Find first data object of the type defined by constructor-function . The first data object is the
first one saved in the data store:
var dataObject = Backendless.Persistence.of( constructor-function ).findFirst
( async );
Find last data object of the type defined by constructor-function . The last data object is the
last one saved in the data store:
var dataObject = Backendless.Persistence.of( constructor-function ).findLast
( async );
where:
constructor-function - a reference to a JavaScript constructor function defining a
JavaScript class. Object(s) returned by functions will be of the
specified type.
async - optional argument. If provided, the method is executed
asynchronously. The successCallback function referenced in the
async object receives a callback when the method successfully
removed the object. If an error occurs, the faultCallback function
is invoked. See Sync and Async Callsfor additional details.
Return Value:
dataObject - an object of type defined by constructor-function.
dataCollection - a collection of objects. Each object is of type defined by
constructor-function. The collection has the following structure:
{
"nextPage":value,
"data": [ array of data objects defined by constructor-function ],
"offset":value,
"totalObjects":value
}
where:
nextPage - is a REST URL returning the next page of data.
data - is an array of data objects.
offset - is a numeric value defining the index in the data store from
where the current page of data is returned.
totalObjects - is a total number of all data objects found through the search
request. If the length of the "data"array is a smaller number than
"totalObjects, it means an additional request must be made to
load the next page of data. Alternatively, use an advanced search
function with a custom page size.
Example:
Consider the following class:
function Contact(args) {
args = args || {};
Please note: searching for an object in a native database differs from searching for an object in an
external database.
where:
properties - is an array containing property names. If the array has any
data, find operations return data object(s) with the requested
property names.
condition - search condition - this is a query in the SQL-92 syntax (the
"where" clause part) to search for data with.
options - an object used to control data paging, sorting and loading of the
related data. The options object may include the following
properties:
{
var pageSize;
var offset;
var sortBy;
var relations;
}
where:
pageSize - sets the size of the "page", i.e. the size of the collection of
results to be returned by the find operation.
offset - sets the offset in the data store from where to search for data.
sortBy - is an array of the data object properties to sort the result
collection by.
relations - is an array of the related data object properties. Each property
must point to a related entity.
where:
constructor-function - a reference to a JavaScript constructor function defining a
JavaScript class which determines which table the query will use
to search for data objects.
query - an instance of Backendless.DataQuery described above. The
object contains the search query and other search options.
async - Optional argument. If provided, the method is executed
asynchronously. The successCallback function referenced in the
async object receives a callback when the method successfully
returns a search result. If an error occurs, the faultCallback
function is invoked. See Sync and Async Calls for additional
details.
Return Value:
The synchronous invocation returns a collection of objects found by the query. The
asynchronous invocation receives the return value through a callback executed on the
AsyncCallback object.
Example:
Consider the following class:
function Contact(args) {
args = args || {};
this.name = args.name || "";
this.age = args.age || "";
this.phone = args.phone || "";
this.title = args.title || "";
}
Find all contacts where the value of the "age" property equals 21:
var contactStorage = Backendless.Persistence.of( Contact );
var dataQuery = {
condition: "age = 21"
};
var myContact = contactStorage.find( dataQuery );
Find all contacts where the value of the "age" property is greater than 21:
var contactStorage = Backendless.Persistence.of( Contact );
var dataQuery = {
condition: "age > 21"
};
var myContact = contactStorage.find( dataQuery );
Find all contacts where the value of the "age" property is between 21 and 30:
where:
<operator> - Possible values are <, >, =, >=, <=
units-function - Defines the units of measure for the distance. Possible values
are:
ft( X ) - the distance value X is expressed in feet
km( X ) - the distance value X is expressed in kilometers
mi( X ) - the distance value X is expressed in miles
yd( X ) - the distance value X is expressed in yards
For example, the following expression searches for data objects located within 200 miles from
the point at 30.26715, -97.74306. Each data object must have the "coordinates" property
of type GeoPoint.
distance( 30.26715, -97.74306, coordinates.latitude, coordinates.longitude )
< mi(200)
function Person(args){
args = args || {};
this.name = args.name || "NoName";
this.age = args.age || 20;
this.phoneNumber = args.phoneNumber || "555-555-55-55";
this.coordinates = args.coordinates || null;
}
Run the following query/code to store a data object representing Jane with a link to his home in
Houston, TX:
function Person(args){
args = args || {};
this.name = args.name || "NoName";
this.age = args.age || 20;
this.phoneNumber = args.phoneNumber || "555-555-55-55";
this.coordinates = args.coordinates || null;
}
Run the following query/code to store a data object representing Fred with a link to his home in
San Antonio, TX:
function Person(args){
args = args || {};
this.name = args.name || "NoName";
this.age = args.age || 20;
this.phoneNumber = args.phoneNumber || "555-555-55-55";
this.coordinates = args.coordinates || null;
}
Once the data is in the persistent object and geo location storage, run the following code/query
to perform a distance-based search:
var query = new Backendless.DataQuery();
query.options.relationsDepth = 1;
query.condition = "distance( 30.26715, -97.74306, coordinates.latitude,
coordinates.longitude ) < mi(200)";
Backendless.Persistence.of(Person).find(query);
The search returns all data objects within the specified distance. Each data object has the
coordinates property containing the coordinates of a geo point associated with this data
object.
Comparison Operators
Backendless supports the following date comparison operators:
Column's value is after the specified date/time: use either > or the after keyword:
birthDate > '22-Dec-1980'
Column's value is before the specified date/time: use either < or the before keyword:
birthDate < '22-Dec-1980'
Column's value is either at or after the specified date/time: use either => or the at or after
keyword:
birthDate >= '28-10-1988'
Column's value is either at or before the specified date/time: use either <= or the at or
before keyword:
birthDate >= '28-10-1988'
Note: the whereClause-based queries can be tested in the Backendless Console with the SQL Search
turned on.
MM.dd.yyyy
MM-dd-yyyy
MM/dd/yyyy HH:mm:ss z
MM/dd/yyyy HH:mm:ss 'GMT'Z
MM.dd.yyyy HH:mm:ss z
MM/dd/yyyy HH:mm
MM/dd/yyyy
dd/MMM/yyyy
dd-MMM-yyyy
EEEEE, d MMMMM yyyy
ddMyy
d MMMMM yyyy, HH'h' mm'm' ss's'
yyyy/MM/d/hh:mm:ss
yyyy-MM-dd'T'hh:mm:ss
EEEEE, MMMMM d, yyyy
MMMMM d, yyyy
yyyy-MM-dd
yyyy M d
yyyyMMMd
yyyy-MMM-d
yyyy-M-d, E
yyyyMMdd
'Date' yyyy-MM-dd
yyyy-MM-dd'T'hh:mm:ssZ
yyyy-MM-dd'T'hh:mmZ
yyyy-'W'w-d
yyyy-DDD
Example
Creating Relations
Relations can be declared manually by using the Backendless Console. Creating a relation between
objects involves two main steps:
1. Declaring a relationship between the tables where the objects are stored.
2. Establishing relations between the objects from the related tables.
6. The pop-up window will display new menu options. Select a related table and the cardinality
of the relations from the corresponding drop-down menus. The one-to-one relation means that
a table's object can be linked with only one object from the related table. While the one-to-
many relation means that a table's object can be linked with several objects from the related
table.
Once a relationship column is declared, it will appear along other columns in the Data Browser view of
the Backendless Console.
1. Click the table name where you declared a relation. Console displays the columns
representing relations slightly different than the other ones. The header for these columns
includes:
- name of the related table;
- relation type (cardinality) visualized as either a single line for one-to-one relations or three
lines for one-to-many relations;
- the "auto-load" checkbox.
2. Click the plus icon next to the object, for which you want to create a relation. The Set
Related Object pop-up window will display the list of objects from the related table.
3. Each object in the displayed popup has either a radio button or a checkbox next to the
object's data. Radio buttons are used for one-to-one relations, while checkboxes apply for the
one-to-many relations. Select the object(s) which will be linked to the parent object.
4. Click the Set Related Object button to save the changes.
The Data Service API can be used to link objects from different tables to form a relation. For more
information see the Relations (Save/Update) section of the guide.
Editing Relations
You can edit the relations between the data objects via the Backendless Console:
1. Click the name of the table containing the object with relations. Click the plus icon next to
the relation you want to edit:
2. The Set Related Object pop-up window will display. If you want to link a data object with
different object(s), click the radio-button or check-box(s) next to the necessary object(s).
3. Click the Set Related Object button to save the changes.
Refer to the Relations (Save/Update) section to learn how to update relations by using the API.
Deleting Relations
You can delete both relations between the objects and between the tables if necessary. Relations
between the tables can be deleted only by using the Backendless Console. While relations between the
objects can be deleted either via the Backendless Console or API.
To delete relations between the data objects via the Backendless Console:
1. Click the name of the table, where you want to delete a relation. Click the plus icon next to
the relation you want to delete.
2. The Set Related Object pop-up window will display. Click the Unlink Related Object
button to delete the relation.
Additionally, a relation between two objects (not tables) can be deleted by using the API. For more
information see the Relations (Delete) section.
Notice the PhoneBook entity references Contact through two properties - "owner" (the one to one
relationship) and "contacts" (the one to many relationship). Each contact entity also references
Address. These entities will be used to demonstrate how Backendless handles related entities in all
basic data persistence operations. Consider the following class definitions for these entities:
function Contact(args) {
args = args || {};
this.___class = 'Contact';
this.name = args.name || "";
this.age = args.age || "";
this.phone = args.phone || "";
this.title = args.title || "";
this.address = args.address || {};
}
function Address(args) {
args = args || {};
this.___class = 'Address';
this.street = args.street || "";
this.city = args.city || "";
this.state = args.state || "";
}
title: "Plumber",
address: new Address({
street: "123 Main St.",
city: "Denver",
state: "Colorado"
})
});
Add Contact to an existing PhoneBook (uses the "savedPhoneBook" object created at the
end of the example above):
// use the phone book object created in the previous example, for example:
var phoneBookStorage = Backendless.Persistence.of( PhoneBook );
// save the phone book so the contact list is updated in the persistent data
store
Update a property in the aggregated object (update the phone number in the "owner" of
PhoneBook) and save PhoneBook:
// use any of the samples above to the point when PhoneBook is saved
// then use JohnsPhoneBook object, for example:
var phoneBookStorage = Backendless.Persistence.of( PhoneBook );
Removing one contact from PhoneBook, adding another and re-saving PhoneBook:
function Contact(args) {
args = args || {};
this.___class = 'Contact';
this.name = args.name || "";
this.age = args.age || "";
this.phone = args.phone || "";
this.title = args.title || "";
this.address = args.address || {};
}
function Address(args) {
args = args || {};
this.___class = 'Address';
this.street = args.street || "";
this.city = args.city || "";
this.state = args.state || "";
}
var phoneBookStorage = Backendless.Persistence.of( PhoneBook );
Notice the PhoneBook entity references Contact through two properties - "owner" (the one to one
relationship) and "contacts" (the one to many relationship). Each contact entity also references
Address. These entities will be used to demonstrate how Backendless handles related entities in all
basic data persistence operations. Consider the following class definitions for these entities:
function Contact(args) {
args = args || {};
this.___class = 'Contact';
this.name = args.name || "";
this.age = args.age || "";
this.phone = args.phone || "";
this.title = args.title || "";
this.address = args.address || {};
}
function Address(args) {
args = args || {};
this.___class = 'Address';
this.street = args.street || "";
this.city = args.city || "";
this.state = args.state || "";
}
phoneBookStorage.remove( JohnsPhoneBook );
// save the phone book and all the changes in it. At this point the actual
// contact is not removed in the data storage, it is only disassociated from
// the phone book.
JohnsPhoneBook = phoneBookStorage.save( JohnsPhoneBook );
function Contact(args) {
args = args || {};
this.___class = 'Contact';
this.name = args.name || "";
this.age = args.age || "";
this.phone = args.phone || "";
this.title = args.title || "";
this.address = args.address || {};
}
function Address(args) {
args = args || {};
this.___class = 'Address';
this.street = args.street || "";
this.city = args.city || "";
this.state = args.state || "";
}
var phoneBookStorage = Backendless.Persistence.of( PhoneBook );
phoneBookStorage.remove( JohnsPhoneBook );
Please note: retrieving relations in a native database differs from retrieving relations in an external
database.
For any two tables A and B where A has a relationship column linking it to B, the console includes the
"auto load" checkbox for the relationship column. Selecting the checkbox instructs Backendless to
return all related B objects when the parent instance of A is retrieved through an API call. For example,
in the image above, the Order table has the one-to-many "items" relationship with the OrderItem table.
When the "auto load" checkbox in the "items" column is selected, all related OrderItem objects will be
included into the response for a find query for the Order table.
where
RELATED-PROPERTY-NAME - name of a related property to load. For example, if table
Person, has a relation "homeAddress" pointing to an object in
the Address table, the value would be "homeAddress". The
syntax allows to add relations of relations. For example, if the
same Address table has a relation "country" pointing to the
Country table, then "homeAddress.country" would instruct the
related Country object to be loaded as well.
Foo - reference to a function which identifies the table from which the
data is to be loaded.
The diagram shows a hierarchy for class structure - the Order class has two relations: with OrderItem
and Customer classes. Each in turn has a relation to the Manufacturer and Address classes. When an
instance or a collection of Order objects is retrieved from Backendless, the API may include a parameter
specifying the depth of relations to include into the response. If the relation depth is 1, then all related
instances of OrderItem and Customer will be included into each Order object. If the relation depth is 2,
then not only OrderItem and Customer instances will be included, but the corresponding Manufacturer
and Address objects as well.
where:
relationsDepth - number indicating the depth of relations to load.
backendlessDataQuery - an instance of Backendless .DataQuery
Example:
var query = new Backendless.DataQuery();
query.options = {relationsDepth:2};
var resultCollection = Backendless.Persistence.of( Foo ).find
( query );
Notice the PhoneBook entity references Contact through two properties - "owner" (the one to one
relationship) and "contacts" (the one to many relationship). Each contact entity also references
Address. These entities will be used to demonstrate how Backendless handles related entities in all
basic data persistence operations. Consider the following class definitions for these entities:
function Contact(args) {
args = args || {};
this.___class = 'Contact';
this.name = args.name || "";
this.age = args.age || "";
this.phone = args.phone || "";
this.title = args.title || "";
this.address = args.address || {};
}
function Address(args) {
args = args || {};
this.___class = 'Address';
this.street = args.street || "";
this.city = args.city || "";
this.state = args.state || "";
}
The general structure of the query to load a collection of child objects for a specific parent object is:
ParentTableName[ relatedPropertyForChildrenCollection ].
parentColumnName COLUMN-VALUE-CONDITION
When a query in this format is used to fetch a collection of child object, the table addresses in the
Find all contacts for the specific phone book where the city name contains letter 'a':
Find all contacts where age is greater than 20 for a specific phone book:
Find all contacts for a specific phone book where age is within the specified range:
Find all contacts for a specific phone book where age is greater than 20 and the city is
Tokyo:
persistent systems and sets up the relationship. Likewise, when a data object is
retrieved by using the API, any related geo points can be retrieved using the same
principle for loading data relations. The data-to-geo relation is bidirectional, it means a
geo point may reference a data object in its metadata. You can learn more about it in
the Relations with Data Objects section of the Geolocation documentation.
The relationship between a data object and a geo point (or a collection of) can be established by using
either the "code first" or the "schema first" approaches. With the former, the relationship is determined
by the data structure persisted with the API. If a data object references a GeoPoint (or a collection of) in
one of its properties, Backendless interprets it as a relation and, as a result, will create a relation
column in the data table schema. With the latter ("schema first") approach, application developer can
declare a relationship in the data table schema first. In either one of these approaches, once a
relationship is declared, data objects and geo points may be linked together by using the Backendless
console as well.
4. Enter the name of the column in the Name field. This column will represent a data-to-geo
relationship.
5. Select the Geopoint Relationship option from the Type drop-down list.
6. New menu options will become available. Select the cardinality of the relation from the
corresponding drop-down menu. The one-to-one relation means that a table's object can be
linked with only one geo point, while the one-to-many relation means that a table's object can
be linked with multiple geo points.
3. Click the plus icon next to the object, for which you want to create a data-to-geo relation.
The Set Related GeoPoint pop-up window will display the list of the geo points.
4. Use the Geo Category drop-down list to select a geo category from which the points should
be displayed.
5. If you declared a one-to-one relation for a table the object belongs to, you will be able to link
this object with only one geo point (by the means of a radio button). If it is a one-to-many
relationship, the interface uses check boxes, which allow for multiple selection. Click a radio-
button or select check-boxes next to the geo points which you want to link with the data
object.
6. Click the Set Related GeoPoint button to save the changes.
Once a relation is established, it is shown in the data browser as a hyperlink. The hyperlink for the one-
to-one relations displays the coordinates of the related geo point. For the one-to-many relations the link
says "multiple Geopoints". In both cases, the link opens the Geolocation screen of the console which
displays the related geo point(s).
Updating Relations
You can update a data-to-geo relation by following the steps shown below:
1. Click the name of the table containing an object that has a data-to-geo relation you want to
edit . Click the plus icon next to the relation:
2. The Set Related GeoPoint pop-up window will display. Use the radio-buttons (one-to-one
relations) or check-boxes (one-to-many relations) next to select/deselect the geo points.
3. Click the Set Related GeoPoint button to save the changes.
To delete a relationship definition between a data table and the geo points:
1. Click the name of the table which contains a "GeoPoint relationship" column you need to
remove.
2. Click the Table Schema and Permissions button in the top right corner. The Table
Schema and Permissions page will display.
3. Click the check-box next to the column you need to delete.
2. The Set Related GeoPoint pop-up window will display. Click the Unlink Relation button to
delete the relation.
The example below demonstrates how to link a taxi (a data object) with location (a geo point). First,
create TaxiCab class:
function TaxiCab (args) {
args = args || {};
this.CarMake = args.CarMake || null;
this.CarModel = args.CarModel || null;
this.Location = new GeoPoint();
this.PreviousDropOffs = [];
}
taxi.PreviousDropOffs = previousDropOffs;
Backendless.Persistence.of(TaxiCab).save(taxi);
2.20 Security
Data Service supports a very flexible security mechanism for restricting access to objects stored in
Backendless. Security permissions apply to users and roles. A permission can either grant or reject an
operation for a particular asset. In the context of Data Service, the asset is an object which your app can
retrieve, update or delete. Permissions can be granted or rejected globally, where they apply to all tables
and all objects in the data store. Additionally, every table may have its own permission matrix and owner
policy – a special instruction whether object owners can or cannot retrieve/update/delete the objects
they ‘own’. Finally, every object has its own Access Control List (ACL) which is a matrix of permissions
for the operations applicable specifically to the object:
The security system is multi-layered. For an API call to retrieve, update or delete object(s), the system
goes through several where each can trim the scope of the operations. The layered order of the decision
making is important and consists of the following:
Where:
“User-defined roles” – roles created by the application developer
“System roles” – roles built into Backendless (Authenticated User, NonAuthenticated User,
SocialUser, etc)
Consider the following guide which illustrates the decision making process:
1. Backend receives an API request to load data from a table (the Find operation). All objects
become candidates for the retrieval. Backendless goes through the security permissions chain
to determine which ones must be included.
2. ObjectACL for the user who makes the call. Backendless checks if there are any
restrictions for the user account at the object level. Any object in the collection with ACL which
rejects access to the user is excluded from the result. To see or modify the permissions for a
particular object, click the ‘key’ icon in the ACL column in the data browser in management
console.
3. ObjectACL for user-defined roles assigned to the user who makes the call. This is the
same check as the one above, except Backendless looks into the permissions for the roles
defined by the application developer. If the user belongs to any of the custom roles,
Backendless checks if these roles are allowed to perform the current operation. In the
screenshot below, only the “MyRole” role will be checked in this step, since this is the only
custom role in the application:
4. Table permissions for the User account. Every table in Backendless may have its own set of
permissions for users and roles. At this point Backendless checks if the currently logged in
user is allowed to run the current operation. For example, if the Find operation is denied for the
user, no objects would be returned.
5. Table permissions for the user-defined roles. This step is identical to the one described
above with the exception that is checks custom roles for the table. Since this guide reviews the
decision making process for the Find operation, Backendless checks the column for Find. If any
of the custom roles deny access, the operation is rejected and no data is returned.
6. Owner Policy. When a new object is created in Backendless, the system automatically links
it with the account of the currently logged in user. You can see that information in the ‘ownerId’
column in any of your tables in the data browser. With the association between objects and
users, Backendless provides a way to control whether users can get access to the data they
created. This is done through a concept we call ‘Owner Policy’. The policy is available on the
‘Schema and Permissions’ screen. Select a table in the data browser and click the ‘Table
Schema and Permissions’ button in the upper right corner. Select the ‘Owner Policy’ menu
item. Owner policy can be global (select ‘All Tables’ from the drop down in the upper right
corner) or it could apply to a specific table.
Granting a permission for an operation in Owner Policy, guarantees that the objects owned by
the current user will be included in the resulting collection. Denying a permission, takes out the
‘owned’ objects from the collection of candidate objects to return. Consider the following:
Results in the following. The objects with bold border are guaranteed to be returned. All other
objects will be subject to the subsequent permission checks.
The objects owned by the current user will be excluded from the resulting collection. All
remaining objects will be decided by the subsequent permission checks.
7. Object ACL for system roles. This check is identical to step 3 (Object ACL for custom roles).
The difference is the system roles cover larger groups of users. For example, this step would
make possible to restrict access to specific objects for all authenticated (or not authenticated)
3 Messaging Service
3.1 Overview
Data Messaging is an essential function of mobile and desktop applications. It can be used for a
multitude of functions including chat or private messaging, system update broadcast, maintaining game
scores, etc. The Backendless Messaging Service provides API and software infrastructure enabling
publish-subscribe message exchange pattern and mobile push notifications. The service consists of the
following core concepts: channels, publishers, subscribers and registered devices:
channel - a logical medium "carrying" the messages.
publisher - a program using the Publishing API to send messages to a channel.
subscriber - a program using the Subscription API to receive messages from a channel.
registered device - a mobile device registered with a Backendless channel to receive
push notifications.
Publish-Subscribe Messaging
With the publish-subscribe pattern, one part of the code (or an entire application) can subscribe to
receive messages and another publishes messages. A message can be any data - Backendless
supports messages of primitive or complex data types. To enable publish-subscribe messaging,
Backendless supports the concept of a channel. Subscriptions are "attached" to a channel (or multiple
channels) and messages are published into a channel. By default Backendless sends all messages
published into a channel to all the channel's subscribers. However, a subscription can include message
filters, in this case Backendless delivers only the messages matching the filter.
Push Notifications
A message published to a channel can be tagged as a push notification, thus triggering the logic for
distributing it to the registered devices. Backendless supports push notifications for iOS, Android and
Windows Phone devices. Messages published as push notifications can target either a specific
subscriber (as a device) or a group of subscribers. Subscribers can be grouped by operating system (for
example, a message sent to all registered iOS devices) or as a collection of individual registrations. The
Backendless messaging API supports different types of push notifications - badge updates, alerts, etc.
3.2 Setup
To get access to the Backendless services, JavaScript applications must reference the backendless.js
library. The library can be retrieved using any of the approaches listed below:
1. Download Backendless SDK for JavaScript. The SDK can be downloaded from the Backendless
website
2. Install the Backendless Bower package:
bower install backendless
compressed library:
http://api.backendless.com/sdk/js/latest/backendless.min.js
Before the JavaScript client uses any of the APIs, the code must initialize the Backendless Application
using the following call:
Backendless.initApp( application-Id, secret-key, version )
Make sure to use the "JavaScript Secret Key" for the secret-key argument.
The version argument must contain the name of the targeted version. When a new application is
created, the default version name is "v1" . To manage versions, login to the console, select the
"Manage" icon and click "Versioning".
Backendless.Messaging - is the central point for all Backendless Messaging APIs. Provides
access to the device registration, subscription management and messaging publishing functionality
SubscriptionOptions - may be used in the subscription call to establish subscriber identity and set messaging filte
var SubscriptionOptions = function (args) {
args = args || {};
DeliveryOptions - used in the publishing API for targeted message delivery. Supported options
include: tagging a message as a push notification, scheduling message delivery in the future,
scheduling repeated message delivery and message expiration.
var DeliveryOptions = function (args) {
args = args || {};
// sets the timestamp when the repeated messaging publishing should stop
this.repeatExpiresAt = args.repeatExpiresAt || undefined;
};
Backendless.Async = Async;
where:
successCallback - a reference to a function which will be called when
the server returns a result. The signature of this
callback function must accept one argument which
will be the actual result object returned by the server.
faultCallback - an (optional) reference to a function which will be
called if the server returns an error. The function
must accept one argument which is a fault object
containing the information about the error.
context - an (optional) reference to the object which is used as
"this" when calling successCallback or faultCallback
3.5 Error Handling
When the server reports an error, it is delivered to the client through a fault object, which is an untyped
JavaScript object. The fault object has the same structure for both synchronous and asynchronous
invocations:
{
"message": value,
"statusCode": value
}
where:
message - contains a string value with the description of the
error
statusCode - error code as a string value. Currently all the error
codes are numbers, however the method returning
the error code returns the String type. This is done
for future expansion of the error code system which
may include characters.
The asynchronous calls receive the fault through the fault callback referenced in the Async function.
For the synchronous calls the fault object is thrown as an error which must be handled in a catch( err
) block:
try
{
backendlessAPIcall();
}
catch( err )
{
console.log( "Error message - " + err.message );
console.log( "Error code - " + err.statusCode );
}
8. Click Save. At this point the backend is configured and is ready to publish push notifications to
Android devices.
In your project you should register the device in order to receive or send push notifications. To
accomplish this, do the following:
1. Login to Google Developers Console and select your previously created project.
2. Copy the project number located at the top of the screen:
1. Creating App ID
2. Creating Certificate Request
3. Generating an SSL Certificate
4. Configuring Backendless App/Backend with the Certificate
Creating App ID
1. First we are going to create an App ID for the mobile application which will receive Push
Notifications. Login to Apple Developer Member Center. Click on “App IDs” in the “Identifiers”
section. Use the plus sign “+” button to create a new ID:
2. When prompted enter App ID Prefix. Make sure it is descriptive enough so you recognize it
later when you return to the Member Center.
3. Select Explicit App ID in the “App ID Suffix” section and enter the same bundle ID which you
will be using in the application:
4. In App Services select the services which the application will use and click “continue”:
5. Make sure that Push Notifications are enabled and click “submit”. This will conclude the App ID
creation for the app:
2. Enter your email address and Common Name (leave the CA Email Address field empty),
select “Saved to disk” and click “Continue”:
2. Select certificate type – there are two options Development and Production. For now select
“Apple Push Notification service SSL (Sandbox)”:
4. Next you will see the instructions for generating a CSR which you have already created by
now. Click Continue to proceed to the next step.
5. Select the CSR file created and saved to the disk earlier and click Generate:
11. Enter a password for the certificate. Make sure to make a record of the password – you will
need to use it later in the instructions when you submit the certificate to Backendless:
12. Enter your Mac OS X account password to confirm the action. At this point you have a
certificate for Push Notifications.
2. Click Manage > App Settings. Locate the Mobile Settings section and upload the .p12
certificate created earlier. Make sure to enter the same password you used when created the
certificate:
Publishing with message headers - headers is a collection of name = value pairs of arbitrary
data. Subscribers can set additional filters expressed as SQL queries which Backendless applies
to the headers. When the query matches the published data in headers, message is delivered to
To receive messages from more than one subtopic, subscribers can use the wildcard
character (*) in place of any tokens in the subtopic name. For instance, a subscriber
could subscribe to the following subtopic: "news..business.* ", and the publisher sends
messages to "news.business.newyork " and "news.business.tokyo ". In this case the
messages published to either subtopic will be delivered to the consumer.
The wildcard character in the last position will match any token in that position as well as
tokens after it. For instance, subtopic com.foo.* will match all of the following: com.foo.
bar, com.foo.abc.def , etc. However, the wildcard character in any position other than
the last will match only one token. For example, subtopic com.*.foo will match com.
abc.foo and com.123.foo , but will not match com.foo .
See example.
where:
channelName - name of the channel to publish the message to. If the channel
does not exist, Backendless automatically creates it.
message - object to publish. Can be a primitive value, an array or a
complex type.
publishOptions - optional argument. An instance of the PublishOptions class.
Contains publisher ID, message headers and subtopic name.
deliveryOptions - optional argument. An instance of the DeliveryOptions class.
May specify message delivery policy (push, pub/sub or both),
timestamp (in milliseconds) for publishing at the specified time in
the future, interval for repeated publishing.
async - optional argument. An instance of Backendless.Async. If
present, contains references to the success and failure callback
functions. See the Sync and Async Calls section for additional
details.
Return value:
An untyped JavaScript object containing message ID and the status of the publishing operation:
{
status : "published" | "scheduled" | "failed",
messageId: messageIdValue
}
Errors:
The following errors may occur during the message publishing API call. See the Error Handling
section for details on how to retrieve the error code when the server returns an error:
Error Description
Code
5003 Invalid repeatExpiresAt date in delivery options.
5007 User does not have the permission to publish messages
5030 Invalid publishAt date in the delivery options.
Examples:
Basic message publishing
Publishing with message headers
Publishing to a subtopic
Publishing a message only as a push notification
Publishing a message as a push notification and targeting specific group of devices (grouped by
OS)
Publishing a push notification and targeting specific devices
Delayed publishing
Repeated publishing
Synchronous publish:
var channel = "TestChannel",
message = "Hello, world!";
Asynchronous publish:
var channel = "TestChannel",
message = "Hello, world!",
success = function (response) {
/* ... */
},
failure = function (response) {
/* ... */
};
Backendless.Messaging.publish(
channel,
message,
null,
null,
new Backendless.Async(success, failure)
);
Synchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = new PublishOptions({
headers: {
city: "Denver",
state: "Colorado"
}
});
Asynchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = new PublishOptions({
headers: {
city: "Denver",
state: "Colorado"
}
}),
success = function (response) {
/* ... */
},
failure = function (response) {
/* ... */
};
Backendless.Messaging.publish(
channel,
message,
pubOps,
null,
new Backendless.Async(success, failure)
);
Publishing to a subtopic
Application initialization
var APPLICATION_ID = "<your application ID>",
SECRET_KEY = "<your secret key>",
VERSION = "v1"; //default application version;
Backendless.initApp(APPLICATION_ID, SECRET_KEY, VERSION);
Synchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = new PublishOptions({
subtopic: "sightseeing"
});
var response = Backendless.Messaging.publish( channel, message,
pubOps );
// message has been published, message status is available via
response.status
// if publish failed - error is described in response.errorMessage
Asynchronous Publish:
var channel = "TestChannel",
Synchronous Publish
var channel = "TestChannel",
message = "Hello, world!",
pubOps = null,
deliveryOps = new DeliveryOptions({
pushPolicy: "PUSHONLY"
});
var response = Backendless.Messaging.publish( channel, message,
pubOps, deliveryOps );
// message has been published, message status is available via
response.status
// if publish failed - error is described in response.errorMessage
Asynchronous Publish
var channel = "TestChannel",
message = "Hello, world!",
pubOps = null,
deliveryOps = new DeliveryOptions({
pushPolicy: "PUSHONLY"
}),
success = function (response) {
/* ... */
},
failure = function (response) {
/* ... */
Synchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = null,
deliveryOps = new DeliveryOptions({
pushPolicy: "PUSHONLY",
pushBroadcast: "ANDROID"
});
var response = Backendless.Messaging.publish( channel, message, pubOps,
deliveryOps );
// message has been published, message status is available via response.
status
// if publish failed - error is described in response.errorMessage
Asynchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = null,
deliveryOps = new DeliveryOptions({
pushPolicy: "PUSHONLY",
pushBroadcast: "ANDROID"
}),
success = function (response) {
/* ... */
},
failure = function (response) {
/* ... */
};
Backendless.Messaging.publish(
channel,
message,
pubOps,
deliveryOps,
new Backendless.Async(success, failure)
);
Synchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = null,
deliveryOps = new DeliveryOptions({
pushPolicy: "PUSHONLY",
pushSinglecast: ["dummyDeviceId_001", "dummyDeviceId_002"
] // devices IDs
});
var response = Backendless.Messaging.publish( channel, message,
pubOps, deliveryOps );
// message has been published, message status is available via
response.status
// if publish failed - error is described in response.errorMessage
Asynchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = null,
deliveryOps = new DeliveryOptions({
pushPolicy: "PUSHONLY",
pushSinglecast: ["dummyDeviceId_001", "dummyDeviceId_002"] //
devices IDs
}),
success = function (response) {
/* ... */
},
failure = function (response) {
/* ... */
};
Backendless.Messaging.publish(
channel,
message,
pubOps,
deliveryOps,
new Backendless.Async(success, failure)
);
Delayed publishing
Application initialization
var APPLICATION_ID = "<your application ID>",
SECRET_KEY = "<your secret key>",
VERSION = "v1"; //default application version;
Synchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = null,
deliveryOps = new DeliveryOptions({
publishAt: (new Date()).getTime() + 60 * 1000 // 1 minute
delay
});
var response = Backendless.Messaging.publish( channel, message,
pubOps, deliveryOps );
// message has been published, message status is available via
response.status
// if publish failed - error is described in response.errorMessage
Asynchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = null,
deliveryOps = new DeliveryOptions({
publishAt: (new Date()).getTime() + 60 * 1000 // 1 minute
delay
}),
success = function (response) {
/* ... */
},
failure = function (response) {
/* ... */
};
Backendless.Messaging.publish(
channel,
message,
pubOps,
deliveryOps,
new Backendless.Async(success, failure)
);
Repeated publishing
Application initialization
var APPLICATION_ID = "<your application ID>",
SECRET_KEY = "<your secret key>",
VERSION = "v1"; //default application version;
Backendless.initApp(APPLICATION_ID, SECRET_KEY, VERSION);
Synchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = null,
deliveryOps = new DeliveryOptions({
Asynchronous Publish:
var channel = "TestChannel",
message = "Hello, world!",
pubOps = null;
deliveryOps = new DeliveryOptions({
repeatEvery: 10, // frequency in seconds
repeatExpiresAt: (new Date()).getTime() + 60 * 1000 //
expiration timestamp (in milliseconds) , eg: after 1 minute
}),
success = function (response) {
/* ... */
},
failure = function (response) {
/* ... */
};
Backendless.Messaging.publish(
channel,
message,
pubOps,
deliveryOps,
new Backendless.Async(success, failure)
);
Push notifications can be published directly from Backendless Console or using the API (see the
examples in the Message Publishing section).
Method Signatures
Backendless.Messaging.cancel(messageId, async)
where:
messageId - ID of the message to cancel.
async - optional argument. An instance of Backendless.Async. If
present, contains references to the success and failure callback
functions. See the Sync and Async Calls section for additional
details.
Return value:
true if the scheduled message has been successfully canceled, false otherwise.
Errors:
The following errors may occur during the message cancellation API call. See the Error
Handling section for details on how to retrieve the error code when the server returns an error:
Error Description
Code
5040 Message has already been canceled or does not exist.
Examples:
Application initialization
var APPLICATION_ID = "<your application ID>",
SECRET_KEY = "<your secret key>",
VERSION = "v1"; //default application version;
Backendless.initApp(APPLICATION_ID, SECRET_KEY, VERSION);
Backendless.Messaging.subscribe(channelName, subscriptionCallback,
subscriptionOptions, async)
where:
channelName - ID of the message to cancel.
subscriptionCallback - a callback function where the messaging system delivers
published messages for the subscription.
subscriptionOptions - optional argument. An instance of SubscriptionOptions which
can be used to set subscriber ID, subtopic or selector. See the
Message Filtering section for additional details.
async - optional argument. An instance of Backendless.Async. If
present, contains references to the success and failure callback
functions. See the Sync and Async Calls section for additional
details.
Return value:
An object identifying the subscription. Should be used to cancel subscription.
Errors:
The following errors may occur during the message cancellation API call. See the Error
Handling section for details on how to retrieve the error code when the server returns an error:
Error Description
Code
5008 User does not have permission to create a subscription.
5009 General subscription error. See error message for additional
details.
5010 Unknown messaging channel.
Messages
The JavaScript clients retrieve messages from Backendless using short polling. The
subscriptionCallback function in the subscribe call receives published messages. The function's
argument is an untyped object with the "messages" property. The property contains an array of
messages published to the channel since the previous polling request.
var subscriptionCallback = function (data) {
var messagesArray = data["messages"];
// process messages here
}
where:
messageId - unique message ID. The ID is assigned at the time of message
publishing.
headers - an associative array which is a collection of key/value pairs.
Examples:
Application initialization
var APPLICATION_ID = "<your application ID>",
SECRET_KEY = "<your secret key>",
VERSION = "v1"; //default application version;
Backendless.initApp(APPLICATION_ID, SECRET_KEY, VERSION);
Synchronous Subscribe:
var channel = "TestChannel",
callback = function (data) {
var messagesArray = data["messages"];
},
subOps = new SubscriptionOptions({ // all fields are optional
subscriberId: "myDummyID", // string value identifying
subscriber
subtopic: "general", // string value - name of
the subtopic to subscribe to
"selector-query": "<value>" // string query in the SQL-
92 format (the where clause)
});
Asynchronous Subscribe:
var channel = "TestChannel",
subOps = new SubscriptionOptions({ // all fields are optional
subscriberId: "myDummyID", // string value identifying
subscriber
subtopic: "general", // string value - name of
the subtopic to subscribe to
"selector-query": "<value>" // string query in the SQL-
92 format (the where clause)
}),
callback = function (data) {
var messagesArray = data["messages"];
},
success = function (subscription) {
/* ... */
},
failure = function (response) {
/* ... */
};
Backendless.Messaging.subscribe(
channel,
callback,
subOps,
new Backendless.Async(success, failure)
);
Message Filtering
Backendless message filtering is a powerful mechanism enabling conditional message delivery, interest-
based subscriptions and private messaging. A subscription request may include filters in the form of
subtopics and selectors. Backendless applies subscriber's filters to every message published into the
channel and they match, the message is delivered to the subscriber.
Subtopics
Multiple subtopics can be defined within a channel. Both publishers and subscribers can specify
a subtopic within a channel. Subtopic names can be defined using a multi-tiered format:
maintoken[.secondaryToken][.additionalToken]
To receive messages from more than one subtopic, subscribers can use the wildcard character
(*) in place of any tokens in the subtopic name. For instance, a subscriber could subscribe to
the following subtopic: "news..business.* ", and the publisher sends messages to "news.
business.newyork " and " news.business.tokyo ". In this case the messages published to
either subtopic will be delivered to the consumer.
The wildcard character in the last position will match any token in that position as well as
tokens after it. For instance, subtopic com.foo.* will match all of the following: com.foo.bar,
com.foo.abc.def , etc. However, the wildcard character in any position other than the last will
match only one token. For example, subtopic com.*.foo will match com.abc.foo and
com.123.foo , but will not match com.foo .
Selectors
A selector is a query expressed using the SQL-92 syntax and formatted as the condition part of
the SQL's WHERE clause. A query condition must reference the headers of the published
messages. When a message is published and a subscriber has a selector query, Backendless
executes the query on the headers of the published message. If the result of the query is true,
the message is delivered to the subscriber. Consider the following example where the subscriber
will receive only messages containing the "city " header with the value of "Tokyo ":
Publisher:
var APPLICATION_ID = "<your application ID>",
SECRET_KEY = "<your secret key>",
VERSION = "v1"; //default application version;
Backendless.initApp(APPLICATION_ID, SECRET_KEY, VERSION);
Subscriber:
// Application initialization
var APPLICATION_ID = "<your application ID>",
SECRET_KEY = "<your secret key>",
VERSION = "v1"; //default application version;
Method Signatures:
subscriptionObject.cancelSubscription()
where:
subscriptionObject - object received as a result of the subscribe operation.
Examples:
Application initialization
var APPLICATION_ID = "<your application ID>",
SECRET_KEY = "<your secret key>",
VERSION = "v1"; //default application version;
setTimeout(function () {
subscription.cancelSubscription(); // cancelling subscription
after 7 seconds timeout
}, 7000);
Backendless.Messaging.subscribe(
channel,
callback,
subOps,
new Backendless.Async(success, failure)
);
Configuration
To configure a backend:
where:
SMTP Server - Hostname or public IP address of the server where the SMTP server is
running.
Port - The port number the SMTP server accepts requests on.
From - The Name which will appear in the From field of the sent out emails.
User ID - The user id or email address for the SMTP server connection
authentication
Password - The password for the SMTP server connection authentication.
Security - Choose between SSL or TLS connection.
Make sure to click Test before saving any configuration changes. The Discard button discards any
unsaved changes.
where:
subject - email message subject.
bodyParts - an instance of Bodyparts , which contains either plain text and/
or HTML version of the message body.
recipients - an array of email addressed to deliver the email message to.
attachments - an array of file paths for the file entries from the Backendless
File Service. Referenced files will be attached to the email
message. The path is calculated from the root of the file system
(as it is seen in File Service browser in Backendless console)
without the leading slash. For example, if file agreement.txt is
located at /documents/legal/, then the path in the API call must
be "documents/legal/agreement.txt".
responder - the callback used for asynchronous calls to indicate that the
operation has either successfully completed or resulted in error.
Example:
4 File Service
4.1 Overview
Every Backendless backend/app is allocated a dedicated file storage space. The file storage is located
remotely on the Backendless servers. The file storage can be used to store application's files and on-
demand video streams. Backendless File Service provides the API to work with the file storage. The API
supports the following operations:
File Upload - upload files to the applications's file storage. The operation creates directories up
the hierarchy if necessary. Returns file URL which can be used to download or share the file
with others.
File Download - download file using file's URL. The download operation is subject to the
permissions from the File access control list (ACL).
File Deletion - delete a file from the file storage. The delete operation is subject to the
permissions from the File access control list (ACL).
Directory Deletion - same as file deletion, but applies to the directories.
File/Directory Security (File ACL) - assign/unassign user and roles permissions to upload,
download and delete files and directories. This API is used to modify file or directory ACL.
In addition to the API implementation, the File Service enables the following capabilities:
Git Integration - application developers can interact with the file storage as with a git repository.
Web Hosting - file storage can be used to host static web content.
Custom Domain Name - a custom domain name can be mapped to the file storage in a
Backendless backend. This feature in combination with the Web Hosting provides a way to host
websites on Backendless.
Custom Web Templates Hosting - includes HTML files and JS scripts for special pages used in
various workflows such as user email confirmation, password change and session expiration.
compressed library:
http://api.backendless.com/sdk/js/latest/backendless.min.js
Before the JavaScript client uses any of the APIs, the code must initialize the Backendless Application
using the following call:
Backendless.initApp( application-Id, secret-key, version )
Make sure to use the "JavaScript Secret Key" for the secret-key argument.
The version argument must contain the name of the targeted version. When a new application is
created, the default version name is "v1" . To manage versions, login to the console, select the
"Manage" icon and click "Versioning".
Backendless.Async = Async;
where:
successCallback - a reference to a function which will be called when
the server returns a result. The signature of this
where:
message - contains a string value with the description of the
error
statusCode - error code as a string value. Currently all the error
codes are numbers, however the method returning
the error code returns the String type. This is done
for future expansion of the error code system which
may include characters.
The asynchronous calls receive the fault through the fault callback referenced in the Async function.
For the synchronous calls the fault object is thrown as an error which must be handled in a catch( err
) block:
try
{
backendlessAPIcall();
}
catch( err )
{
console.log( "Error message - " + err.message );
console.log( "Error code - " + err.statusCode );
}
To create a file:
1. Log in to Backendless Console. Select an application. Click the Files icon:
2. Select a directory where a new file should created. Click the New File button at the top of
the file listing table.
3. Enter the name in the File name field and select a file extension from the Syntax
highlighter drop-down menu:
4. Enter the contents for the file as necessary. Click the Save button.
Editing a File
Backendless supports in-browser editing of the files with the following extensions:
.conf, ,css, .csv, .htm, .html, .ini, .java, .js, .log, .php, .
properties, .py, .rb, .sh, .txt, .xml, .xsd
To edit a file:
1. Select a directory containing the file on the Files screen of the console.
2. Click the Edit file icon next to the file to open it for editing:
3. Once the changes in the file are made click the Save button.
Archiving Files
Backendless Console includes a feature enabling to compress directories into a single ZIP file. The
feature applies specifically to directories, meaning an individual file cannot be compressed - it must be
placed into a directory first.
Notice: archiving of directories with total content size greater than 100 Mb may take longer time;
Backendless sends an email to the application developer upon successful completion of the operation.
To archive a directory:
1. Log in to Backendless Console. Select an application and click the Files icon.
2. Navigate to a directory which should be compressed.
3. Click the ZIP Directory button:
4. Once the directory is compressed into an archive, it will appear in the parent directory:
where:
<application id> - ID of the application which can be obtained from the Manage >
App Settings screen of the Backendless Console
<version name> - application's version name
The URL assigned to a file and returned as a result of the upload operation accounts for any security
permissions assigned to the file (or the folder it is located in).
Backendless Console includes a file browser with the management functions to upload files, create or
delete directories and files. The file browser is available in the Files section of the console:
File browser also provides a way to see the contents of the files. Every file is a link which opens the file.
The URL of files in file browser is not the same as the URL returned by the file upload operation. The
reason file browser uses a different URL is to let the application developer see the file contents without
any application security constraints. The only constraint applied to the URLs available in file browser is
the application developer must be logged to the console.
Methods:
Backendless.Files.upload( file, path, async )
Backendless.Files.upload( files, path, async )
where:
file - an instance of JavaScript File class.
files - an instance of JavaScript FileList class.
path - directory path (without the name of the file) in the
Backendless file storage where the file should be stored. If the
path does not exist, Backendless File Service creates the
directory structure.
async - asynchronous operation handler. Must contain references to
"success" and "failure" callback functions. The "success"
function receives a callback when the method successfully
uploads file(s). If an error occurs, the faultCallback function is
invoked. See Sync and Async Calls for additional details.
Return Value:
The return value, which is the URL of the uploaded file, is delivered through a callback
referenced on the Async object.
JavaScript:
// this line goes into the app initialization block
document.getElementById('files').addEventListener('change',
handleFileSelect, false);
function handleFileSelect(evt)
{
files = evt.target.files; // FileList object
}
function uploadFileFunc()
{
var callback = {};
callback.success = function(result)
{
alert( "File successfully uploaded. Path to download: " + result.
fileURL );
}
callback.fault = function(result)
{
alert( "error - " + result.message );
}
where:
path - path of the directory where the file should be
stored. Must start with "/" which represents the root
directory of the remote file storage.
fileName - name of the file where the byte content should be
written to.
fileContent - an array of bytes to save.
overwrite - the file is overwritten if the argument value is true
and the file already exists. Otherwise, if the value is
false and another file with the same name already
exists, an error is returned.
The server will return the link to the newly added file or an error.
Errors:
Error codes returned on attempt to save a file from the byte array.
Error Description
Code
6016 When saving a new file from the byte array, the payload exceeds
2,800,000 bytes.
6003 A file you are trying to save already exists in the system and cannot
overwrite since overwrite argument is ether set to false or
omitted.
where:
<application id> - ID of the application which can be obtained from the
Manage > App Settings screen of the Backendless
Console.
<version name> - Application's version name.
<path> - Directory path where the file is saved.
<file name> - Name of the file.
Files fetched with the URL scheme defined above are subject to the security constraints and
permissions established by the application developer. See the Files Security section for additional
details on how to secure file storage. Fetching a file secured by an access control list (ACL) policy
requires an additional HTTP header in the request:
user-token:<value>
where:
<value> - Value of the user token established for the current
user session as a result of the user login operation.
The token uniquely identifies the user session. It is
used by Backendless to establish user identity for all
operations where the token is present. This is
The API to delete a file uses the <path>/<filename> part to identify the file which must be deleted.
Methods:
Backendless.Files.remove( filePath, async )
where:
filePath - Path of the file to delete. The path must consist of the file path
and file name.
async - Asynchronous operation handler. Must contain references to
"success" and "failure" callback functions. The "success"
function receives a callback when the method successfully
deletes the file. If an error occurs, the faultCallback function is
invoked. See Sync and Async Calls for additional details.
Return Value:
None. If an error occurs, it is delivered to the faultCallback function referenced in the Async
object.
Example:
var callback = new Backendless.Async(
function(result)
{
alert( "File successfully deleted" );
},
function(result)
{
alert( "error - " + result.message );
});
The API to delete a directory uses the <path> element from the URL above.
Methods:
where:
path - path of the directory to delete.
async - asynchronous operation handler. Must contain references to
"success" and "failure" callback functions. The "success"
function receives a callback when the method successfully
deletes the directory. If an error occurs, the faultCallback function
is invoked. See Sync and Async Calls for additional details.
Return Value:
None. If an error occurs, it is delivered to the faultCallback function referenced in the Async
object.
Example:
var callback = new Backendless.Async(
function(result)
{
alert( "Directory successfully deleted" );
},
function(result)
{
alert( "error - " + result.message );
});
When the git integration is turned on, all files present in or uploaded to the file storage are immediately
committed to the repository. This integration is bi-directional. It means that any files committed into the
git repository by the means of git, will also be copied into the file storage. When git integration is being
turned off, the git repository is deleted with all the associated history (the files remain in the file storage).
With the git integration enabled, a new folder (.git) appears in the File Browser on the Files screen. The
folder contains the files from the git repository. When a file is uploaded to file storage either via the
Upload API or using the File Browser, it is automatically committed to the repository. Likewise, when a
file is pushed into the repository, it becomes available and visible in the file storage. The same applies to
editing and deleting files either in the Backendless Console or in git repository.
where:
<application id> - application ID available in Backendless Console at Manage >
App Settings .
When the Backendless backend is configured with a custom domain name, the repository URL is:
http://<custom domain name>/.git
The repository uses the same authentication as Backendless Console. That means all git commands
must use the same developer email address and password as for logging in to Backendless Console.
It is important to note that any system level files created by git are also placed into the file storage (the .
git directory). These files are accounted for when calculating the file space used by the app/backend.
# pushes the repo and its refs for the first time to Backendless git
> git push -u origin --all
The /web folder serves as the web server root. The web server is available at the following URLs:
where:
<application id> - ID of the application which can be obtained from the Manage >
App Settings screen of the Backendless Console
<version name> - application's version name
Web Hosting. Backendless file storage contains a special directory - /web , which serves as the
web site root. When a custom domain name is mapped to a Backendless application/backend,
the contents of the /web directory are served for the HTTP requests with the domain name. See
the Web Hosting section for additional details.
git endpoint. When the Backendless git integration is enabled, the git endpoint with a custom
domain name is:
http://<custom domain name>/.git
The Custom Domain mapping is a feature included into Backendless Plus package. The package
enables multiple features for a flat monthly subscription fee. Backendless Plus can be enabled in
console at Manage > Billing .
All these use cases have something in common - they all force the user to interact with a web page. The
Backendless Plus package allows to customize the look and feel of these pages. Once Backendless
Plus is enabled (use the Manage > Billing section in console to turn it on), Backendless puts the
templates for these pages into the /web/templates path of the backend's file storage:
The look and feel as well as the logic in the pages can be customized by modifying the HTML/CSS /JS
files provided for each template. For example, the contents of the change_password folder is:
To modify the permission matrix for a file or a directory, click the "Edit Permissions" link in file browser
in console. The permission assignment screen contains allows to work with permissions for specific
user accounts or for application roles.
To assign permissions to a user account, type in userid in the "enter user name" field, select the user(s)
and click "Add":
To modify a permission for an operation for a user, click the icon in the corresponding column. The icon
has 3 states:
- inherit GRANT permission from the global permission matrix. This is the default permission.
- explicit GRANT of the permission for the operation. Allows the user to perform the operation.
- DENY permission for the operation. Restricts the user from performing the operation.
Managing permissions for roles is identical to users, except all roles are automatically listed in the table:
5 Geo Service
5.1 Overview
Backendless Geolocation Service is a system supporting management and search of geo points. A geo
point in the most primitive format consists of a pair of coordinates: latitude and longitude. Optionally a
geo point may contain metadata, which is a collection of arbitrary key/value pairs. A geo point belongs
to a category, which is a logical grouping of geo points. The diagram bellow illustrates these concepts:
Backendless allows infinite number of geo points managed for an application. Geo points can be added
via an API call or the import functionality in Backendless console. Once the backend is populated with
geo points, the search API can be used to run the following types of geo queries:
Radius-based search - Searches for geo points in a circular map area defined by the coordinates
of the central point and a radius. Backendless returns all geo points within the area.
Search in a rectangular map area - Searches for geo points in a rectangular map area identified by
the coordinates of two corners defining the area (North West and South East):
Additionally, the geo search API supports the following search options available in the APIs:
Filtering by categories - Both types of search (radius-based and rectangular) can specify the
categories in which the backend should search for the geo points.
Query-based search - The metadata associated with the geo points can be used in queries
which should be formatted using the SQL-92 syntax. For example, the geo point shown in the
image above can be discovered with the following queries:
cuisine = 'French'
Relative search - Runs a search for a subset of metadata key/value pairs to match up to the
specified threshold value. The threshold must be expressed as a percentage of matches.
5.2 Setup
To get access to the Backendless services, JavaScript applications must reference the backendless.js
library. The library can be retrieved using any of the approaches listed below:
1. Download Backendless SDK for JavaScript. The SDK can be downloaded from the Backendless
website
2. Install the Backendless Bower package:
bower install backendless
compressed library:
http://api.backendless.com/sdk/js/latest/backendless.min.js
Before the JavaScript client uses any of the APIs, the code must initialize the Backendless Application
using the following call:
Backendless.initApp( application-Id, secret-key, version )
Make sure to use the "JavaScript Secret Key" for the secret-key argument.
The version argument must contain the name of the targeted version. When a new application is
created, the default version name is "v1" . To manage versions, login to the console, select the
"Manage" icon and click "Versioning".
where:
message - contains a string value with the description of the
error
statusCode - error code as a string value. Currently all the error
codes are numbers, however the method returning
the error code returns the String type. This is done
for future expansion of the error code system which
may include characters.
The asynchronous calls receive the fault through the fault callback referenced in the Async function.
For the synchronous calls the fault object is thrown as an error which must be handled in a catch( err
) block:
try
{
backendlessAPIcall();
}
catch( err )
{
console.log( "Error message - " + err.message );
console.log( "Error code - " + err.statusCode );
}
The image below shows the Geolocation screen with categories in the app:
Methods:
Backendless.Geo.addCategory( name, async )
where:
name - name of the category to create.
async - asynchronous operation handler. Must contain
references to "success" and "failure" callback
functions. The "success" function receives a callback
when the method successfully creates the category. If
an error occurs, the faultCallback function is invoked.
See Sync and Async Calls for additional details.
Return Value:
A javaScript object with the following structure:
{
"objectId": "<categoryId>",
"size": "0",
"name": "<categoryName>"
}
Example:
function(result)
{
alert( "error - " + result.message );
});
Methods:
Backendless.Geo.deleteCategory( name, async )
where:
name - name of the category to delete.
async - asynchronous operation handler. Must contain
references to "success" and "failure" callback
functions. The "success" function receives a callback
Return Value:
true if the category is deleted, false otherwise.
Example:
var callback = new Backendless.Async(
function(result)
{
alert( "category deleted - " + result );
},
function(result)
{
alert( "error - " + result.message );
});
where:
async - asynchronous operation handler. Must contain
references to "success" and "failure" callback
functions. The "success" function receives a callback
when the method successfully retrieves the geo
categories in the application. The argument of the
"success" function callback is an array of category
objects (see the return value section). If an error
occurs, the faultCallback function is invoked. See Sync
and Async Calls for additional details.
Return Value:
An array of JavaScript objects. Each object has the following structure:
{
"objectId": "<categoryId>",
"size": <categorySize>,
"name": "<categoryName>"
}
where:
<categoryId> - ID assigned by Backendless to the category.
<categorySize> - number of geo points contained in the geo category.
If an error occurs, it is delivered to the faultCallback function referenced in the Async object.
Example:
var callback = new Backendless.Async(
function(result)
{
alert( "received " + result.length + " categories" );
},
function(result)
{
alert( "error - " + result.message );
});
Backendless.Geo.getCategories( callback );
Methods:
Backendless.Geo.addPoint( geoPoint, async )
where:
geoPoint - a JavaScript object describing the geo point to add.
Must have the following structure:
{
latitude: <latitude>,
longitude: <longitude>,
categories: <categoriesArray>,
metadata: <metadataObj>
}
where:
<latitude> - latitude of the point to add. Must be a numeric
value.
<longitude> - longitude of the point to add. Must be a numeric
value.
<categoriesArray> - optional parameter. Array of categories the point is
added to. If a category does not exist at the time
when a point is added, Backendless creates the
category and adds the point to it. If the property is
not present in the object, the point is added to the
"Default" category. Each category name must be a
string.
If an error occurs, it is delivered to the faultCallback function referenced in the Async object.
Example:
var callback = new Backendless.Async(
function( result )
{
alert( "geo point saved " + result.geopoint.objectId );
},
function(result)
{
alert( "error - " + result.message );
});
var point = {
latitude: 20,
longitude: 30,
categories: ["restaurants", "cool_places"],
metadata: {"owner":"XXXX-XXXX-XXXX-XXXX"}
}
6. A confirmation notification will appear in the top right. The selected geopoint(s) are removed.
Example:
The example below demonstrates how to delete a geopoint. A geopoint is added first, then
subsequently deleted.
var deletePointCallback = new Backendless.Async(
function( result )
{
alert( "geo point deleted" );
},
function(result)
{
alert( "error - " + result.message );
});
var geopoint = {
latitude: 20,
longitude: 30,
categories: ["restaurants"]
};
where:
latitude - the latitude coordinate of a geo point
longitude - the longitude coordinate of a geo point
category1,category2 - comma separated list of categories. The value must
be enclosed in double quotes.
key1=value1|key2=value2 - Geo point metadata. Multiple key/value pairs
The import process runs asynchronously. When the process is complete, Backendless sends an email
to the application developer. The email text includes the log entries informing about any errors which
could have occurred during the import. Upon successful completion of the import, the Geolocation
section of the console displays the categories, geo points and their metadata:
Methods:
Backendless.Geo.find( query, async )
where:
query - a query object to run the search with. Must have the
following structure:
{
metadata: <metadataObj>,
categories: <categoriesArray>,
includeMetadata: <metaInResponse>,
pageSize: <pageSize>,
offset: <offset>
}
where:
<metadata> - metadata which must match in order for a point to
be selected for the search result. Must be a JavaScript
object. Backendless searches for geo points with
metadata which matches the specified object entirely.
See partial match search for the search API that does
not require complete matches. Accepted values for this
parameter are: String, Number (integer and double),
and Data Service objects. Date values must be
represented as number in the Unix timestamp format
(number of milliseconds since January 1, 1970 at
UTC). Learn more about using date in search queries
for category, radius, or rectangular area search.
<categories> - list of categories separated by comma where to run
the search. If the parameter is not present in the
request, the search is ran in the "Default" category.
<metaInResponse> - a boolean value indicating whether geo point
metadata should be included in the response.
<pageSize> - number of geo points to be returned in the
response.
<offset> - sequential (zero-based) index from where to run the
search. For example, suppose the first search query
returned 50 geo points (pageSize is set to 50). A
subsequent search should set the offset value to 50 in
order to get the next page of search results.
async - asynchronous operation handler. Must contain
references to "success" and "failure" callback
functions. The "success" function receives a callback
when the method successfully completes the search
where:
<geoPointCollection> - array of geo points objects matching the search
query parameters. Each object has the following
structure:
{
categories: array of category names
latitude: latitude of the geo point
longitude: longitude of the geo point
objectId: ID assigned by Backendless to the geo point
}
If an error occurs, it is delivered to the faultCallback function referenced in the Async object.
Search in categories
To search in one or more categories without any constraints on metadata or proximity to a
center point, simply set the names of the categories in the query object. The request returns all
geo points divided into pages of data, one page at a time.
var callback = new Backendless.Async(
function(result)
{
alert( "found geo points - " + result.data.length );
},
function(result)
{
alert( "error - " + result.message );
});
var geoQuery =
{
categories: ["Restaurants"]
}
var geoQuery =
var geoQuery =
{
includeMetadata:true,
categories: ["Restaurants"]
}
Methods:
Backendless.Geo.find( query, async )
where
query - query object to run the search with. Must have the
following structure:
{
radius: <radius>,
latitude: <latitude>,
longitude: <longitude>,
units: <units>,
metadata: <metadataObj>,
categories: <categoriesArray>,
includeMetadata: <metaInResponse>,
pageSize: <pageSize>,
offset: <offset>
}
where:
<radius> - distance from the center point within which to run
the search.
<latitude> - latitude of the point in the center of the search.
<longitude> - longitude of the point in the center of the search.
<units> - unit of measure applied to the radius value.
Supported unit values are: METERS, KILOMETERS, MILES,
YARDS, FEET
<metadata> - metadata which must match in order for a point to
be selected for the search result. Must be a JavaScript
object. Backendless searches for geo points with
metadata which matches the specified object entirely.
See partial match search for the search API that does
not require complete matches. Accepted values for this
parameter are: String, Number (integer and double),
and Data Service objects. Date values must be
represented as number in the Unix timestamp format
The geo points in the search results will be sorted by their proximity to the central point (center
of the radius): the geo points that are closest to the central point will be listed first.
The collection object in the response has the following structure and behavior:
{
data: <geoPointCollection>,
offset: <offsetValue>,
totalObjects: <totalObjectsValue>,
getPage : function( offset, pageSize, async );
nextPage: function( async );
}
where:
<geoPointCollection> - array of geo points objects matching the search
query parameters. Each object has the following
structure:
{
categories: array of category names
distance: distance between the central point and this geo point
in units
latitude: latitude of the geo point
longitude: longitude of the geo point
objectId: ID assigned by Backendless to the geo point
}
If an error occurs, it is delivered to the faultCallback function referenced in the Async object.
var geoQuery =
{
latitude: 41.38,
longitude: 2.15,
radius: 100000,
units: "METERS",
categories: ["Restaurants"]
}
var geoQuery =
{
latitude: 41.38,
longitude: 2.15,
radius: 100000,
units: "METERS",
metadata: {Cuisine:"French", Atmosphere:"Romantic"},
categories: ["Restaurants"]
}
latitude: 21.306944,
longitude: -157.858333,
categories:["Coffee", "City"],
metadata: {
"Name":"Starbucks",
"City": "Honolulu",
"Parking":true,
"updated": Date.now()
}
};
Backendless.Geo.addPoint(point);
var query = new BackendlessGeoQuery();
query.categories = ['Coffee', 'City'];
query.includeMetadata = true;
query.latitude = 21.30;
query.longitude = -157.858333;
query.radius = 50;
query.units = Backendless.Geo.UNITS.KILOMETERS;
query.condition = "updated > " + updated;
var result = Backendless.Geo.find(query);
console.log(result);
Methods:
Backendless.Geo.find( query, async )
where
query - query object to run the search with. Must have the following
structure:
{
searchRectangle: <search-rect-coord>,
metadata: <metadataObj>,
categories: <categoriesArray>,
includeMetadata: <metaInResponse>,
pageSize: <pageSize>,
offset: <offset>
}
where:
<search-rect-coord> - an array of 4 numbers which are the coordinates defining the
search area. The numbers must be in the following order:
[
North West latitude,
North West longitude,
South East latitude,
Return Value:
Geo points returned from the search query are contained inside of a collection object. Since the
search query may produce a large number of geo points, not all of them are returned at once.
Instead, all found geo points are divided into 'pages'. The size of each page is determined by
the pageSize parameter in the query object. The first response returns the first page. The
collection class includes methods for loading additional pages. The collection also includes the
total number of all geo points found by the search operation (the totalObjects value).
All geo points in the entire search result are indexed. The index of the first geo point is 0. The
offset parameter in the query object and in the getPage method in the collection specifies the
index from which to load the next page of geo points. For example, suppose the entire search
result is 200 points (the totalObjects value returned in the collection is 200). If the initial
pageSize is 20, then only 20 geo points are returned in the first response. To get the second
page of geo points, they should be loaded from offset 20, third from 40 and so on. The formula
for calculating the offset is:
[value of offset in the current response] + [size of current page ].
The collection object in the response has the following structure and behavior:
{
data: <geoPointCollection>,
offset: <offsetValue>,
totalObjects: <totalObjectsValue>,
getPage : function( offset, pageSize, async );
nextPage: function( async );
}
where:
< geoPointCollection> - array of geo points objects matching the search query
parameters. Each object has the following structure:
{
categories: array of category names
latitude: latitude of the geo point
longitude: longitude of the geo point
objectId: ID assigned by Backendless to the geo point
}
< offsetValue> - index of the first geo point in the returned collection.
<totalObjectsValue> - total number of geo points which match the search query. This
number may be different than the number of geo points in the
data array. Points not returned in the query can be retrieved with
a subsequent request, by setting the offset parameter to:
[value of offset in the current response] + [size of data array].
getPage - function responsible for loading a "page" of search results from
the specified offset.
nextPage - function loading the next page. Should be used only if data.
length is less than totalObjectsValue.
If an error occurs, it is delivered to the faultCallback function referenced in the Async object.
var geoQuery =
{
searchRectangle: [32.78, -96.8, 25.79, -80.22],
metadata: {Cuisine:"French", Atmosphere:"Romantic"},
categories: ["Restaurants"]
}
Backendless creates clusters by splitting the map into a grid of squares. Geo points
which belong to a square are placed into the same cluster. When a square contains
only one point, it remains non-clustered.
4. Console reloads geo points and clusters for the current viewport of the map and displays the
results. A cluster is visualized as a blue marker on the map with a number indicating how
many geo points it represents.
Geo clustering is also available with the "Search in Radius" option, which searches for geo points in a
circular area. To enable this functionality, click the Search in radius toggle:
If you want to see the geo points in a cluster, zoom in the map or double-click a cluster's marker.
Zooming the map in too much (when using the clustering along with the search in radius) may result that
the search radius will be much bigger than the visible part of the map on the screen. In this case, the
pop-up window will display offering you to resize (zoom out) the map. Clicking the Yes button zooms the
map out.
Clicking a cluster's marker will reveal the coordinates and metadata of a cluster.
Backendless.Geo.find(geoQuery, callback);
when clusterGridSize parameter is not defined, the server will use the default value (100 px)
var callback = new Backendless.Async(
function(result)
{
var geoObjectCollection = result.data;
var counterGeoClusters = 0;
var counterGeoPoints = 0;
for(var i = 0; i < geoObjectCollection.length; i++){
if(geoObjectCollection[i] instanceof GeoCluster){
counterGeoClusters ++;
}
else if(geoObjectCollection[i] instanceof GeoPoint){
counterGeoPoints ++;
}
}
console.log( "Received collection contains " + result.totalObjects + "
objects, which are:");
console.log(counterGeoClusters + " objects type of GeoCluster and " +
counterGeoPoints + " objects type of GeoPoint.");
},
function(result)
{
console.log( "error - " + result.message );
});
Backendless.Geo.find(geoQuery, callback);
where
westLongitude - the longitude of any point on the western boundary of the map
in degrees.
eastLongitude - the longitude of any point on the eastern boundary of the map in
degrees.
mapWidth - the size of the viewing area of the map in pixels.
clusterGridSize - the size in pixels of the grid's squares used to group
points into clusters. The default value is 100 pixels
Once the clustering parameters are set, the geo point search API will return clustered geo points. The
return value is a collection of GeoCluster and/or GeoPoint objects. Instances of the latter may be
returned when a geo point does not have any neighboring points within the grid's square it belongs to.
The GeoCluster class extends from GeoPoint and supports all the inherited properties: latitude,
longitude, categories and metadata. Additionally, geo cluster has its own property representing the
number of points the cluster consists of. Since a GeoCluster object an instance of the GeoPoint class,
the processing of search responses may look like this:
var callback = new Backendless.Async(
function(result)
{
var geoObjectCollection = result.data;
var counterCluster = 0;
var counterTotalPoints = 0;
var counterPoints = 0;
var number = 0;
for(var i = 0; i < geoObjectCollection.length; i++){
number = i + 1;
if(geoObjectCollection[i] instanceof GeoCluster){
console.log("Object" + number +" is geo-cluster, it contains: "+
geoObjectCollection[i].totalPoints + " points;");
counterTotalPoints += geoObjectCollection[i].totalPoints;
counterCluster ++;
}
else if(geoObjectCollection[i] instanceof GeoPoint){
console.log("Object" + number +" is geo-point, it contains: 1 points;");
counterTotalPoints += 1;
counterPoints ++;
}
}
console.log("Received collection contains " + counterTotalPoints + " points."
);
console.log( "This points was groupped to " + result.totalObjects + "
objects, which are:");
console.log(counterCluster + " objects type of GeoCluster and " +
counterPoints + " objects type of GeoPoint.");
},
function(result)
{
alert( "error - " + result.message );
});
Backendless.Geo.find(geoQuery, callback);
Apart from linking with the data objects, you can also link a geo point with a user
object. Establishing relations with a user objects is performed the same way as with a
data object.
5. Type in a metadata property name in the Metadata property name field. The new property
will be associated with the related data object.
6. Select a data table from from the Data table drop-down menu. If you want to establish
relation with a user object, select the Users option from the drop-down menu. A list of the
data objects which belong to the selected table will display.
7. Select the check-boxes for the data object(s) you want to link with the geo point.
8. Click the Add Related Objects button to establish a relation and save the changes.
Once the relation is established, the name of the property and the related data table will display next to
the corresponding geo point.
Updating Relations
You can update a geo to data relation (for instance, add or remove objects to/from the relation) by
following the instructions below:
1. Select a geo category and locate the geo point.
2. To update a geo to data relation, click the link with the name of the data table in the geo point
metadata column.
Deleting Relations
To delete a relation between a geo point and a data object:
1. Select a geo category and locate the geo point.
2. Click the link with the name of the data table in the geo point metadata column. The Add
Related Object pop-up window will display.
3. Un-check the check-boxes next to the data objects you want to unlink from the geo point.
4. Click the Update Relation button to save the changes.
The example below adds a geo point representing a location of a taxi cab. The geo point includes the
"TaxiCab" metadata property which references an object from the TaxiCab data table. This is an
example of a one-to-one relation (one geo point is related to one data object).
First, declare the TaxiCab function:
function TaxiCab (args)
{
args = args || {};
this.CarMake = args.CarMake || null;
this.CarModel = args.CarModel || null;
this.Location = new GeoPoint();
this.PreviousDropOffs = [];
}
About Geofencing
Geofencing on the surface, comprises drawing a stationary geometric boundary around an area on a
map. This action creates programmatically a set of simple or complex global coordinates which
represent a shape. A boundary represents a “fence,” which surrounds the area. For Backendless, the
boundary and area become meaningful when a Geopoint crosses the boundary or stays within the area.
Geofences work with Geopoints. A Geopoint is the most elementary Geolocation concept in
Backendless. It is a point (latitude and longitude coordinate pairs) on the map that is accessible via API
and allowed to move (change coordinates), i.e., a user carrying a mobile device. In addition to the
coordinates, the Geopoint includes metadata in context for the Geopoint.
The Design Tool includes line, rectangle, and circle drawing tools (the cursor changes from hand to
crosshairs when selected) for creating Geofence boundaries. Boundaries can be geometrically
symmetrical or irregular shapes and have no minimum or maximum size constraints. In use cases, a
Geofence conceptually “fences in” a city block, a shopping center, a sports stadium, or perhaps a mall;
even smaller geographic areas are possible such as the shoe department in a retail store.
Place the cursor on the map where the first control point should be and click. Drag the cursor to the next
place and Click again. The first line segment appears. Repeat these steps until you have nearly
completed the shape of your boundary. (It’s not a Geofence just yet.) Click the cursor on the last control
point (which was the first one set). Backendless detects a closed shape and enables a new Geofence.
NOTE: If you accidentally close the Geofence before completing the drawing, the New Geofence dialog
box appears. If you click Cancel, the Geofence will be removed. To keep the Geofence, click Save,
then re-edit the shape as needed.
Immediately after the shape closes, a popup appears prompting you to name the Geofence. Enter a
name in the Geofence Name text box. Since this example uses the state of Nevada, it makes sense to
name it Nevada. Click Save to enable the Geofence. (We will refer to this example again.)
The result is a new item row in the List of Geofences. The Geofence area is filled with green, and the
item row is highlighted in yellow when a Geofence is selected on the map or on the list. See the image
below.
Deleting a Geofence
A Delete button is positioned directly below the interactive map. For each selected checkbox next to the
Geofence hyperlink, the Delete button removes those Geofences. Once a Geofence is deleted, it cannot
be restored.
From left to right, the second column shows the Geofence name, which is hyperlinked to the Update
Geofence dialog. The Geofence locator icon is next to the Geofence hyperlink (see image below). The
tool repositions the map view to an optimal zoom-level, from which the Geofence boundary can be
easily viewed, accessed, and edited.
Qualification Criteria, which identifies the types of Geopoints Backendless traces and tracks for a
specific geogence, can be defined in the Update Geofence dialog. The Geofence hyperlink opens the
dialog. A criterion, in this case, is a special string entered in the Geopoint Qualification Criteria text box.
(The string format is the SQL 92 syntax, regular SQL as relates to a database query WHERE clause.)
For example, if tracking only visitors, the SQL would need something like usertype=visitor . Where
usertype is a Geopoints metadata property. visitor is the metadata property value.
The string can be tested via the Validate button. Upon a successful validation, a success message
displays.
Conversely, Backendless could track only employees, excluding visitors, and function as a time clock
action, such as clock-in and clock-out.
Events
Three event types are organized in columns in the List of Geofences. The events types are:
On Enter – a Geopoint crosses the Geofence boundary into the defined area
On Stay – a Geopoint remains in the Geofence area for at least a specified period
On Exit – a Geopoint crosses the Geofence boundary out of the defined area
Actions
For each of the above events, a developer can select an action and specify parameters to be executed
from Backendless. There are four action types:
Push notification
Publish-subscribe (pub/sub) message
Send a custom event
Call a URL
The scenarios for choosing an action are wildly different; however, they drive the action and parameter
choices the developer makes. When an action type is selected for an event, a dialog appears where
action parameters can be entered. The fields in the dialog are specific to the action type.
Whenever an action is configured, visual elements indicate whether the parameters are complete. A gear
icon and green checkmark indicate proper configuration, where as a red X in place of the checkmark
indicates improper configuration. The configuration can be edited by clicking the gear to reopen the
currently assigned action dialog.
Content Configuration – configure Push Notification content look and feel for Android, iOS, or
Windows Phone.
Message Headers – allows header name and header value.
Delivery – to individual Geopoints or those registered to a channel.
Channel name – the name for a channel. Backendless creates the channel if it
doesn’t exist.
Topic name – the name of a topic used for filtered delivery.
Message headers – optional. Use the key=value format. Comma delimited.
Message body – written in JSON. The body of the message to be delivered.
Missing Actions – look for red X next to the edit action gear. An action is improperly configured.
ON/OFF Toggle – click to switch either on or off. ON activates the server-side monitoring for the
selected Geofence.
When an action is properly configured, i.e. complete, the Is Active toggle for the selected Geofence
appears. When set to ON, a popup provides cautionary information and a checkbox option, which
applies actions to Geopoints located within the Geofence at the time when the monitoring is turned on (i.
e. the toggle is being set to ON). See the image below.
Once server-side monitoring is activated by setting the Is Active toggle to ON, a play button appears
next to the gear icon. This button executes the action on-demand for any Geopoints within the
Geofence. (This function can be useful when debugging.)
The frequency of refresh on the screen is controlled by the refresh interval. The value is in seconds and
can be set to a value from 10 to 300. You can force a refresh by clicking the refresh button. See the
image below.
geofences (or a specific geofence) and tracks device positional changes. When the device crosses,
stays in, or exits a geofence boundary, the Backendless client executes a callback. Based on this,
Backendless client-side monitoring supports the following options:
In-app callback for the on enter, on stay and on exit events. A callback is executed on the
device when it's location enters, stays in or exits a geofence. With this approach the client
application decides how to handle a geofence event.
In-app callback interface
Client applications must use a special class to receive in-app callbacks. The class includes
delegate methods invoked by the Backendless library when the current device's location
enters, stays in or exits a geofence. The callback's delegate methods include information
about the current location.
Consider the following example of a callback implementation. The example creates and saves
a geopoint with dummy coordinates (0,0). As the device changes its location, the in-app
callback is executed and the code saves the device's location on the server. See the example
below.
Remote callback for the on enter, on stay and on exit event. The Backendless client
automatically notifies the server when a geofence event occurs. If there is an action associated
with the event, Backendless executes on the server-side.
The API applies the options above either to a specific or all geofences. It is important to note that a
Backendless client can monitor only the geofences which are not activated for the server-side
monitoring. In other words, a geofence with the "Is Active” toggle in the Backendless console set to ON
cannot be tracked on the client-side.
Geofence APIs
The Geolocation service provides the following APIs:
Client-side location monitoring:
Start location monitoring with an in-app callback
Start location monitoring with a remote callback
Stop location monitoring
Executing a geofence action:
Run the OnEnter action
Run the OnStay action
Run the OnExit action
Retrieve geopoints from a geofence
where:
Example:
where:
geofenceName - name of a geofence for which to monitor the device's location. If
the value of the argument is null, the Backendless client will
monitor device's current device location for all geofences.
geoPoint - the geopoint object to pass to the server. The geopoint
represents the current device location. It may be a geopoint
stored in the Geolocation storage (with objectId assigned to it)
or a new geopoint object. The Backendless client assigns the
current location coordinates to the geoPoint object before
sending it to the server.
responder - a responder that notifies the calling program when the operation
has started successfully geofence monitoring or has resulted in
error.
Example:
where:
geofenceName - name of the geofence for which device location monitoring will
stop. If the value of the argument is null, the method stops
location monitoring for all geofences.
Example:
where:
geofenceName - name of the geofence on which the OnEnter action will run.
geoPoint - a geopoint which will be used as the context for the action
execution. Any substitutions which the action may be configured
Example:
where:
geofenceName - name of a geofence on which the OnStay action will run.
geoPoint - a geopoint which will be used as the context for the action
execution. Any substitutions which the action may be configured
with will be resolved against the geopoint. If the value of the
argument is null, the action is executed on all geopoints located
within the geofence.
callback - a responder that notifies the calling program when the operation
has requested successfully the action to be executed or resulted
in error.
Example:
where:
geofenceName - name of a geofence on which the OnExit action will run.
geoPoint - a geopoint which will be used as the context for the action
execution. Any substitutions which the action may be configured
with will be resolved against the geopoint. If the value of the
argument is null, the action is executed on all geopoints located
within the geofence.
callback - a responder that notifies the calling program when the operation
has requested successfully the action to be executed or resulted
in error.
Example:
where:
geofenceName - name of a geofence to retrieve the geopoints from.
Example:
The example loads geopoints from a geofence called "Manhattan". The returned geopoints will have
metadata properties and will match the SQL query:
Index
-B-
backendless.jar 6, 90, 127, 148
-I-
Identity 9
-L-
Login 15
Logout 21
-P-
Password
property 9
recovery 22
-U-
User Properties
defining with API 9
defining with console 9
retrieve user entity description 10
update user registration 18
User Registration
API call 12
disable registration 12
email confirmation 12
registration with external system 12