Introduction: What is Backendless?
Backendless is a comprehensive Backend-as-a-Service (BaaS) platform that enables developers to build applications without writing server-side code. It provides ready-to-use backend functionality including database management, user authentication, file storage, business logic, and API services. With Backendless, developers can focus on creating engaging user interfaces while leveraging a robust and scalable backend infrastructure that eliminates the need for traditional server development and maintenance.
Core Concepts and Components
Backendless Architecture
- Data Service: Database management with real-time capabilities
- User Management: Authentication, registration, and user roles
- Messaging Service: Push notifications, email, and in-app messaging
- Media Service: File and media storage management
- Business Logic: Custom server-side code via Cloud Code and API services
- UI Builder: Visual application development environment
- Serverless Functions: Executable code without server management
- API Services: REST and real-time APIs for data access
Development Approaches
| Approach | Description | Best For |
|---|---|---|
| Codeless | Visual development with no coding | Rapid prototyping, citizen developers |
| Low-Code | Mix of visual tools and minimal code | Business applications, quick MVP |
| Pro-Code | Full access to APIs and SDKs | Complex applications, professional developers |
Data Service
Data Model Structure
- Tables: Collections of data objects (similar to database tables)
- Columns: Properties defined for each table
- Relations: Connections between tables (one-to-one, one-to-many, many-to-many)
- Data Types: Text, Number, Boolean, DateTime, GeoPoint, JSON, etc.
Data Management APIs
// Create a new record
Backendless.Data.of('TableName').save({
property1: 'value1',
property2: 'value2'
});
// Retrieve records with query builder
Backendless.Data.of('TableName')
.find()
.then(records => {
// Process retrieved records
});
// Update a record
Backendless.Data.of('TableName').save({
objectId: 'existing-record-id',
property1: 'updated-value'
});
// Delete a record
Backendless.Data.of('TableName').remove('record-id');
Data Query Operations
| Operation | Description | Example |
|---|---|---|
| Find | Retrieve records | Backendless.Data.of('TableName').find() |
| Where | Apply conditions | .where('age > 21') |
| Properties | Select specific fields | .properties(['name', 'email']) |
| SortBy | Order results | .sortBy('created DESC') |
| PageSize | Limit results per page | .pageSize(20) |
| Related | Include related data | .related('orders') |
| GroupBy | Group results | .groupBy('department') |
| First/Last | Get first/last result | .first() |
| Distinct | Get unique values | .distinct('category') |
Data Relations and Advanced Features
Relation Management
// Load related objects Backendless.Data.of('Parent').loadRelations('parent-id', 'children'); // Add relation Backendless.Data.of('Parent').addRelation('parent-id', 'relationColumnName', ['child-id-1', 'child-id-2']); // Set relation Backendless.Data.of('Parent').setRelation('parent-id', 'relationColumnName', ['child-id-1', 'child-id-2']); // Delete relation Backendless.Data.of('Parent').deleteRelation('parent-id', 'relationColumnName', ['child-id-1']);Data Transactions
Backendless.Data.beginTransaction() .addOperation('create', 'TableName', { property: 'value' }) .addOperation('update', 'TableName', { objectId: 'id', property: 'new-value' }) .execute();Bulk Operations
Backendless.Data.of('TableName').bulkCreate([ { property1: 'value1' }, { property1: 'value2' } ]); Backendless.Data.of('TableName').bulkUpdate( 'property1 = "target"', { property2: 'updated-value' } ); Backendless.Data.of('TableName').bulkDelete('isDeleted = true');
User Management
Authentication Methods
// Email/Password Registration
Backendless.UserService.register({
email: 'user@example.com',
password: 'securePassword',
name: 'User Name'
});
// Login with Email/Password
Backendless.UserService.login(
'user@example.com',
'securePassword',
true // remember me
);
// Social Login
Backendless.UserService.loginWithOAuth2(
'facebook',
accessToken,
fieldsMapping,
stayLoggedIn
);
// Anonymous Login
Backendless.UserService.loginAsGuest();
// Logout
Backendless.UserService.logout();
User Operations
Password Management
// Reset Password Backendless.UserService.restorePassword('user@example.com'); // Change Password Backendless.UserService.changePassword( 'oldPassword', 'newPassword' );User Data Management
// Get Current User Backendless.UserService.getCurrentUser(); // Update User Data Backendless.UserService.update({ objectId: 'user-id', name: 'Updated Name' });
User Roles and Permissions
Role Management
- Default roles: Authenticated, NotAuthenticated, AuthenticatedUser
- Custom roles created via Backendless Console
- Role-based permissions assignment
Setting Permissions via API
// Set permissions Backendless.Data.Permissions.FIND.grantForRole('RoleName', 'TableName'); Backendless.Data.Permissions.UPDATE.denyForUser('user-id', 'TableName');Permission Types
- FIND: Retrieve objects
- CREATE: Add new objects
- UPDATE: Modify existing objects
- DELETE: Remove objects
File Storage
File Operations
// Upload a file
Backendless.Files.upload(
file,
'path/in/backendless/storage.txt',
true // overwrite if exists
);
// Download a file
Backendless.Files.download(
'path/in/backendless/storage.txt',
responseCallback
);
// Delete a file
Backendless.Files.remove('path/in/backendless/storage.txt');
Directory Operations
// Create directory
Backendless.Files.createDirectory('path/to/directory');
// List files in directory
Backendless.Files.listing('path/to/directory');
// Remove directory
Backendless.Files.removeDirectory('path/to/directory');
File Permissions
// Grant permissions
Backendless.Files.Permissions.READ.grantForRole('RoleName', 'path/to/file.txt');
Backendless.Files.Permissions.WRITE.grantForUser('user-id', 'path/to/file.txt');
// Deny permissions
Backendless.Files.Permissions.DELETE.denyForRole('RoleName', 'path/to/file.txt');
Messaging Services
Push Notifications
// Register device for push notifications
Backendless.Messaging.registerDevice(
deviceToken,
channels,
expirationTime
);
// Unregister from push notifications
Backendless.Messaging.unregisterDevice();
// Send push notification
Backendless.Messaging.publish(
'channelName',
'Notification message',
publishOptions
);
Publish Options for Push Notifications
const publishOptions = {
pushBroadcast: {
// iOS specific
ios: {
badges: 1,
sound: 'default',
alertTitle: 'Title',
alertBody: 'Message body'
},
// Android specific
android: {
contentTitle: 'Title',
contentText: 'Message body',
notificationIcon: 'notification_icon',
soundName: 'notification_sound'
}
}
};
Email Sending
// Send email
Backendless.Messaging.sendEmail(
'subject',
'body',
['recipient@example.com']
);
// Send email with template
Backendless.Messaging.sendEmailFromTemplate(
'templateName',
{ key1: 'value1', key2: 'value2' }, // template variables
['recipient@example.com']
);
Business Logic
API Services
- Custom API Services: Create custom APIs in the Backendless Console
- API Documentation: Auto-generated Swagger documentation
- Versioning: Support for multiple API versions
- Authentication: Secured by Backendless authentication system
Cloud Code (Serverless Functions)
// Timer-based event
Backendless.ServerCode.addTimer({
name: 'scheduledTask',
frequency: { schedule: '0 0 * * *' }, // daily at midnight (cron format)
execute: function() {
// Function logic here
console.log('Timer event executed');
}
});
// Custom API event handler
Backendless.ServerCode.addHandler('CustomService', 'methodName', async (req) => {
// Extract parameters from request
const { parameter1, parameter2 } = req.parameters;
// Business logic
const result = await someProcessing(parameter1, parameter2);
// Return result
return result;
});
// Data event handler (before/after CRUD operations)
Backendless.ServerCode.addHandler('TableName', 'beforeCreate', async (req) => {
// Modify or validate data before saving
req.item.createdAt = new Date();
if (!req.item.isValid()) {
throw new Error('Invalid data');
}
return req.item;
});
Debugging Business Logic
- Use
console.log()for logging information - View logs in Backendless Console under Monitoring section
- Set debug points in Cloud Code editor
- Use try/catch blocks to handle errors gracefully
Real-Time Database
Real-Time Data Subscriptions
// Subscribe to changes in a data table
const eventHandler = Backendless.Data.of('TableName').rt();
// On object created
eventHandler.addCreateListener((obj) => {
console.log('New object created:', obj);
});
// On object updated
eventHandler.addUpdateListener((obj) => {
console.log('Object updated:', obj);
});
// On object deleted
eventHandler.addDeleteListener((obj) => {
console.log('Object deleted:', obj);
});
// On bulk changes
eventHandler.addBulkCreateListener((objs) => {
console.log('Multiple objects created:', objs);
});
// Stop listening
eventHandler.removeCreateListeners();
eventHandler.removeAllListeners();
Real-Time Queries
// Create real-time query
const rtQuery = Backendless.Data.of('TableName')
.rt()
.where('status = "active"');
// Subscribe to query results changes
rtQuery.subscribe().then(subscription => {
subscription.addObjectsAddedCallback(objects => {
console.log('Objects added to query results:', objects);
});
subscription.addObjectsDeletedCallback(objects => {
console.log('Objects removed from query results:', objects);
});
// Stop subscription
subscription.stop();
});
UI Builder
UI Components Reference
- Containers: Container, Tab, Panel, Table
- User Input: TextInput, Checkbox, RadioButton, Select, DatePicker
- Data Components: List, DataGrid, Form
- Navigation: Tabs, Menu, Breadcrumbs
- Media: Image, Video, Audio, FileUpload
- Charts: LineChart, BarChart, PieChart
- Maps: Map, MapMarker
UI Builder Logic Blocks
- Data Operations: Get Data, Save Data, Delete Data
- Page Navigation: Navigate To, Open Modal
- UI Manipulation: Show/Hide Component, Change Property
- Flow Control: If/Else, Loop, Delay
- User Interaction: Confirm Dialog, Alert
- Authentication: Login, Register, Logout
Page Navigation
// Navigate to a page
Pages.navigateTo('PageName');
// Navigate with parameters
Pages.navigateTo('PageName', { id: 'record-id' });
// Open modal dialog
Pages.openModal('ModalName');
// Go back to previous page
Pages.goBack();
API Management
REST API Examples
# Basic CRUD Operations
GET /api/data/TableName # Retrieve all records
POST /api/data/TableName # Create a record
PUT /api/data/TableName/objectId # Update a record
DELETE /api/data/TableName/objectId # Delete a record
# Query Parameters
GET /api/data/TableName?where=age>21
GET /api/data/TableName?sortBy=created%20DESC
GET /api/data/TableName?pageSize=20&offset=40
GET /api/data/TableName?loadRelations=orders
# User Management
POST /api/users/register # Register a new user
POST /api/users/login # Login
GET /api/users/logout # Logout
GET /api/users/current # Get current user
API Security
User Token Authentication
- User-token header:
user-token: 57A23807-XXXX-XXXX-XXXX-EFEB097E68D9
- User-token header:
API Key Authentication
- Application ID header:
application-id: YOUR-APP-ID - REST API Key header:
rest-api-key: YOUR-REST-API-KEY
- Application ID header:
OAuth 2.0 Authentication
- Bearer token header:
Authorization: Bearer ACCESS-TOKEN
- Bearer token header:
Common Challenges and Solutions
| Challenge | Solution |
|---|---|
| Complex Data Queries | Use DataQueryBuilder combined with WHERE clauses and relation loading |
| Real-Time Updates | Implement RT listeners for table changes or query results |
| Custom Business Logic | Create Cloud Code event handlers and API services |
| User Authentication Flow | Combine registration, login, and social auth with role-based security |
| File Management | Use Files API with proper directory structure and permissions |
| Offline Operations | Implement Data Offline with synchronization strategies |
| Custom UI Requirements | Combine UI Builder with custom components and logic blocks |
| API Integration | Use REST API or SDK methods with proper error handling |
Performance Optimization
Database Optimization
- Create appropriate data indexes
- Use properties selection to retrieve only needed fields
- Implement pagination for large data sets
- Use bulk operations for multiple updates
- Structure data appropriately using relations
Business Logic Optimization
- Optimize serverless function execution time
- Use caching strategies for repetitive operations
- Implement background processing for heavy tasks
- Use transactions for operations requiring atomicity
- Implement efficient error handling and logging
Client-Side Optimization
- Use SDK persistent cache
- Implement optimistic UI updates
- Load data progressively
- Use proper component lifecycle management
- Implement data prefetching where appropriate
Integration with Frontend Frameworks
React Integration
// Setup in React application
import Backendless from 'backendless';
Backendless.initApp('YOUR-APP-ID', 'YOUR-API-KEY');
// Example React component using Backendless
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
Backendless.Data.of('Users')
.find()
.then(res => setUsers(res))
.catch(err => console.error(err));
}, []);
return (
<div>
{users.map(user => (
<div key={user.objectId}>{user.name}</div>
))}
</div>
);
}
Angular Integration
// Setup in Angular application
import { Injectable } from '@angular/core';
import Backendless from 'backendless';
@Injectable({
providedIn: 'root'
})
export class BackendService {
constructor() {
Backendless.initApp('YOUR-APP-ID', 'YOUR-API-KEY');
}
getUsers() {
return Backendless.Data.of('Users').find();
}
createUser(userData) {
return Backendless.Data.of('Users').save(userData);
}
}
Flutter/Mobile Integration
// Setup in Flutter application
import 'package:backendless_sdk/backendless_sdk.dart';
void initBackendless() async {
await Backendless.initApp(
applicationId: 'YOUR-APP-ID',
androidApiKey: 'YOUR-ANDROID-API-KEY',
iosApiKey: 'YOUR-IOS-API-KEY',
);
}
// Example Flutter widget using Backendless
class UserList extends StatefulWidget {
@override
_UserListState createState() => _UserListState();
}
class _UserListState extends State<UserList> {
List<Map> users = [];
@override
void initState() {
super.initState();
loadUsers();
}
void loadUsers() async {
final result = await Backendless.data.of('Users').find();
setState(() {
users = result.cast<Map>();
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) => ListTile(
title: Text(users[index]['name']),
),
);
}
}
Development Best Practices
Project Setup
- Plan data model before implementation
- Create clear folder structures for files
- Set up proper user roles and permissions early
- Document API services and endpoints
- Implement proper error handling strategy
Security Practices
- Use role-based permissions for all resources
- Validate all inputs on client and server side
- Implement proper authentication flows
- Use HTTPS for all communication
- Regularly audit permissions and access logs
- Implement data validation in Cloud Code
Team Collaboration
- Use Backendless team development features
- Create development and production environments
- Document data models and API interfaces
- Implement version control for business logic
- Use consistent naming conventions
