Developer Guide

This is your in-depth guide to Built.io Backend.

Our in-depth guide covers everything you need to build your app from scratch using Built.io Backend. While it explains every element of Built.io Backend, it also walks you through the entire process of creating an app from scratch in Built.io Backend. The app is called 'Projects-On-The-Go'. It's an app for project management, presumably similar to those that you may be already using at your workplace. By building this app, we'll get a hands-on feel for app development in Built.io Backend. 

To easily locate the required info, we have listed down the links to the most important sections of our documentation.

Create an app in management dashboard
In order to get started, you will have to first create an account with Built.io Backend and create an app in the management console. Click here to learn how to do this. 

Download SDK
Built.io Backend provides software development kits (SDKs) for various platforms. These SDKs come preloaded with a number of tools that make app development easy. Download the required SDK from here

Initialize SDK
For the SDK to communicate with your app, you will have to initialize the SDK after downloading it. Click here to read the step-by-step guide on initializing the SDK.

Create/manage classes
Now that all the basic elements are in place, it's time to define the classes of your app. Read our in-depth guide on Classes to understand what classes are and how you can create them in your app. 

Create/manage objects
Objects are instances of your class. Therefore, once you have created classes, it is time to create objects within these classes. Let's try to understand Objects in detail, and learn what you can do with them. 

Register/login users
In Users, we will learn how you can register new users for your app, as well as manage other user-related aspects such as login, logout, password reset, and so on. 

Create/manage uploads
You can store any type of file, such as images, audios, videos, documents, etc. in your application. These files are stored as uploads in Built.io Backend. In this section, you will learn how you can create, update, and delete an upload, as well as how to attach an upload to an object.  

Set ACL
In order to ensure that your app's data is secure, use Access Control List or ACL. These are permissions that you can assign to your app's user data. ACL can be set at class level as well as at object level. You can also assign permissions to a bunch of users by defining Roles. 

Send push notifications
Push notification allows you notify your app users about a particular event or message even when the app is not being actively used by the users. In Built.io Backend, you can easily enable push notifications in your app. Read the step-by-step Android and iOS push notification tutorial, and also learn channels, sending, and badge management in our Push Notifications guide.  

Real-time
As the name suggests, 'Real-time' helps you push content to users in real-time, i.e., as and when events occur. Using this functionality, you can create apps that allow you to edit documents together, play multiplayer games online, get traffic updates or locate a taxi near you instantly. Let's us understand Real-time in detail, and understand how you can enable it in your app.  

Analysis
Built.io Backend provides two types of analytics to keep track of your application: Usage metering and Deep Analytics. Usage metering, or API Metrics, tracks the usage of your application, which includes API calls made, push notifications sent, etc. Deep Analytics, on the other hand, helps you track the behaviour of your app users and identify a pattern. 

Extensions
With extensions, you can write your own business logic, and extend the functionality of Built.io Backend. Click here to read more about Extensions.   

Collaborators and Roles
You can invite users to collaborate on your app. You can also define the permissions that these collaborators would have. Read more about Collaborators here

Settings
The settings section in the management console lets you tweak any settings related to your app. You can enable/disable certain features, customize email content, invite collaborators and do a lot more through 'Settings'. Read more about settings here.

Other important features
Along with all the important features mentioned above, Built.io Backend provides a few more that ensures smooth functioning of your app. These include Backbone.js compatibility, Integration (webhooks), and Cross Domain calls.

Getting Started

Create an Account

To get started with Built.io Backend, you will have to create an account with Built.io Backend. This will give you access to the management console, which will allow you to do the following:

  • Create applications
  • Manage application data
  • Manage the users of your application
  • Control/customize/manage other features of your application, such as push notifications, analytics, security, etc.

To create an account, log on to manage.built.io

Login Page

If you already have an account, enter your credentials here. Else, click on the 'Sign Up' link on the bottom of the page.

Create an Application

You can create a Built.io Backend application on the dashboard. An application contains all the data that is associated with your app. Through this application, you will be able to handle everything related to your app, including app users, events, devices, push notifications, and so on.

You will need to sign in to Built.io Backend to access the management console. Since you haven't created any applications yet, you will see a blank dashboard. Click on 'Create New Application' link at the right top corner of the page. 

Create Application

As soon as you click on this link, you will be prompted to enter the details of your application on Built.io Backend. 

New Application

Enter a descriptive name for your application. In this case, let's use Projects-On-The-Go.

Application with description.

As soon as you create this app, you will notice a corresponding tile on your dashboard. This tile contains the app name, description and an API Key. 

Unlike the processes involved in traditional app development route, you don't have to worry about servers and deployment when using Built.io Backend. Creating an app here on the dashboard is as good as deploying it on the server.

Download the SDK

Once you have created an account with Built.io Backend, it's time to download the required software development kit (SDK). SDK is a tool that helps you communicate with Built.io Backend. It provides a layer of abstraction over the REST APIs. It is a best practice to use SDK for app development. 

Built.io Backend provides SDKs for various platforms, such as iOS, Android, Javascript, and Xamarin. Click here to download the required SDK.

Initialize the SDK

For the SDK to communicate with your app, you will have to initialize the SDK after downloading it. Click here to read the step-by-step guide on initializing the SDK.

Applications

What's an Application

An application is the representation of your project on Built.io Backend.

On Built.io Backend dashboard, you can create a corresponding application for each of your client app project. This application contains all the data that is associated with your app. Through this application, you will be able to handle everything related to your app, including app users, events, devices, push notifications, and so on.

Each such application has an api_key, which you apply to the SDK. Remember that you can create multiple applications using your Built.io Backend account.

Create an Application

You will need to sign in to Built.io Backend to access the management console. Since you haven't created any applications yet, you will see a blank dashboard. Click on 'Create New Application' link at the right top corner of the page. 

Create new application.

As soon as you click on this link, you will be prompted to enter the details of your application on Built.io Backend.

New Application

Enter a descriptive name for your application. In this case, let's use Projects-On-The-Go. 

Application with description.

As soon as you create this app, you will notice a corresponding tile on your dashboard. This tile contains the app name, description and an API Key. 

Unlike the processes involved in traditional app development route, you don't have to worry about servers and deployment when using Built.io Backend. Creating an app here on the dashboard is as good as deploying it on the server.  

Now, let's take a look at Classes.

Classes

What are Classes?

Look around. You will find several real-world objects: bicycles, cars, computers, dogs, birds, and so on. All these objects, irrespective of where they are found, have two main characteristics: state and behavior.

A bird's state, for example, would be its breed, color, name, etc., and its behavior includes chirping, flying, and so on. Similarly, a bicycle too has state (pedals, gear, current speed, etc.) and behavior (changing gears, change in speed, applying brakes, etc.).

Now, there may be several bicycles in existence with same make and model. This is because each bicycle was created using a common blueprint, and consequently, all these bicycles have same components. This blueprint is called a class, which specifies what all components are required to build a bicycle. The object 'bicycle' is, therefore, an instance of a class known as 'Bicycles'.

In programming terms, a class is a table in a database consisting of fields. These fields together form a schema for that class. Any data added in this class is structured according to the specified schema.

Traditionally, creating a class involved creating tables in a relational database. Here, however, you can create a class effortlessly by just using the management console. Use classes to define your schema.

Before we start with creating a class in Built.io Backend, let us understand what fields are.

Fields

 you create a class, you will have to first define the fields of the class. Fields are attributes of a class. They can be of the following datatypes:

  • Text
    A generic text datatype that stores arbitrary text.
  • ISODate
    A datatype that stores a valid ISO Date.
  • File
    This datatype allows you to attach files.
  • Boolean
    true|false
  • Reference
    Select this datatype to enable providing reference to other classes. Referencing allows you to point to a particular datum in another class. Example: Let’s say you have two classes—Projects and Users—in a project management app. The Projects class contains all the projects of your organization, while the Users class contains all the employees working in the organization. Now, in the Projects class, you wish to have a field called ‘Team members’ to store all the employees working on a project. Here, instead of a text field, you can create a reference field called ‘Team members’. This reference field accepts the UID of the objects of the Users class.
  • Group
    A group is a collection of many fields. So, for instance, if you want to enter a field as 'Address' and want many sub-fields under it such as city, country, landmark, etc., you can select the 'Group' datatype, and then define the sub-fields under it.
  • Link
    Link is a datatype that holds a valid URL. Link comprises of a href and a title attribute.
  • Number
    This datatype holds numerical data as opposed to textual data. For example, while a text field will hold a string "1", a number field holds 1. We can also execute atomic operations like addition, subtraction on this datatype.
  • Mixed
    The Mixed datatype allows you to add arbitrary data. It is useful, for example, when you are fetching a user profile from a 3rd party service, with no fixed schema. Any key-value pairs of valid JSON may be stored here.

When you select any of the above datatypes, you will notice a few more options below the 'Field' section. These options help you be more specific about your data structure. The details of these options are given below:

  • multiple
    There will be multiple entries of this field. Basically, this translates into an array of the field, instead of a single value. Text, ISODate, File, Group, Link and Number datatypes support multiple.
  • mandatory
    It guarantees an entry for this field. Empty fields will not pass this validation. Text, ISODate, File, Reference, Link and Number datatypes support mandatory.
  • unique

       It ensures uniqueness for the specified field. Unique fields can be set by 2 approaches: 
       1. Singly Unique
       2. Compound Unique

             Let us understand more about these methods:

             1) Singly Unique:

This approach marks only the specified field as unique, which disallows any duplicate value. For example, if every  employee is identified by an employee ID, then the  'employee_id' field should be marked as unique, by selecting the  'Unique' option as  shown below:

  Singly Unique Field

         2) Compound Unique: 

 This approach lets you specify a set of other fields of which values needs to be considered for evaluating whether the  given  field is unique. To do this, click on the checkbox given against 'Unique' option, and then select the fields you wish  to pass, from the drop down list. Let us learn more about it with the help of an example:

Suppose you wish to create a class 'Person' which has 3 fields,  'first_name', 'last_name', and 'age', and you want to impose a restriction in the system that there can't be multiple persons having same first name, last name, and age. This restriction can be achieved by specifying 'first_name' and'last_name' in the 'Unique Path' field while constructing the'age' field as shown below:


Compound Unique Field                                      

          

  • min and max
    This option sets the upper and lower limits for your data. For a textual datatype, it checks the length. For a numerical datatype, it checks for a range. Text and Number support this datatype.
  • format (regular expressions)
    The format option validates your data based on a regular expression. It simply checks if any of the input matches the provided regular expression. You can use this for a variety of purposes, for example, to implement a selection criteria. If the regexp is set to be ^(First|Second)$ then only 'First' and 'Second' will be allowed in that field. Only the Text datatype supports this option.

Creating a class

Creating a class in Built.io Backend is fun and easy. You can do this using Built.io Backend's management console. Click on the application tile on your dashboard to go inside the application.

Go to 'Data' on the left panel, and select 'User classes'. The 'Create new class' link will help you create a new class in your application. 

Creating Class Button

Let's us create a new class called 'Projects' for our Projects-On-The-Go application. We will therefore enter the title as 'Projects', and provide a suitable uid for the class. Click next. 

Creating Class Section 1

To keep it simple, we will ad a couple of fields in this class, let's say, 'Name' and 'Description'. To create these fields, click on the 'Add Field' link. 

Creating Class Section 2

In the dialog box, enter the Display Name as 'Name' and UID as 'name', as show in the figure below. Since the name and description of any project would contain text, we will select the datatype as 'Text'. Similarly, if you want the name of the project to be unique, select unique by checking the checkbox against 'Unique'.

Creating Class Modal

Similarly, add another field for 'Descriptions'.

Creating Class Modal

Once you are done with this, you will see the following screen:

Creating Class Step 2

Click Next.

Creating Class Step 3

Step 3 allows you to set certain permissions at class level. Through 'Configure abilities', you can define what your application users can do to the objects of a particular class. To assign or remove permissions, you just need to check/uncheck on the given permissions. This will enable/disable the API calls needed to perform the required action. So, for instance, if you uncheck 'Create Objects', no user would be able to create objects in this class.

While the settings defined in 'Configure abilities' applies to all the application users, you can also set specific permissions for specific users through 'Default permissions: Access Control List'. You can learn more about these security settings in the Security section of our guide. 

Click on 'Create' to create the Projects class.

Since our Projects-On-The-Go app is a bug tracking app, we would need other classes, such as Bugs, Tasks, Milestones, and Comments. To create each of these classes, you will have to follow the same procedure mentioned above. However, we have already created these classes for you, so that you can simply import them into your app.

To import these classes, first save the following files in your local disc. 

Once you have saved the file, go to your Built.io Backend dashboard, and select classes on the left panel. Then click on the Import Class link, and upload the saved files in the same order as given above (IMPORTANT). 

The datatypes we just went through are powerful and can be put to various different uses. As an example of this, let's take a look at the 'Bug' class. The field status has a regular expression constraint. The constraint ^(Open|In Progress|To Be Tested|Closed)$ allows us to specify an allowed list of values in the field. Any other value specified for the field will be met with an error.

Illustrations

Here's how your schema would look like, with a class diagram:

Class Diagram

Here's a corresponding ER diagram for the same:

ER Diagram

Now let's move on to the next part, Objects!

Objects

What is an object?

In real world, you will find several real-world objects: bicycles, cars, dogs, birds, and so on. All these objects, irrespective of where they are found, have two main characteristics: state and behavior.

A bird's state, for example, would be its breed, color, name, etc., and its behavior includes chirping, flying, and so on. Similarly, a bicycle too has state (pedals, gear, current speed, etc.) and behavior (changing gears, change in speed, applying brakes, etc.).

Now, there may be several bicycles in existence with same make and model. This is because each bicycle was created using a common blueprint, and consequently, all these bicycles have same components. This blueprint is called a class, which specifies what all components are required to build a bicycle. The object 'bicycle' is, therefore, an instance of a class known as 'Bicycles'.

In Built.io Backend, a class is like a data structure, and objects are data in this data structure. Any data added in this class is structured according to the specified schema. All the data in your application will be stored as objects.

So, in our Projects-On-The-Go app, all individual projects would be saved as objects under the class called 'Projects'.

Creating an object

Creating an object for your application is fun and easy. You can create numerous objects using the SDK or REST API.

To understand how it works, let us try to create a simple object called 'Super Project #41' in our projects class. Earlier, we had created two fields in the projects class (Name and Description). Therefore, when we create a new object in this class, you will have to input data for these two fields. Here is a code sample of how to do so. 

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltObject *projectObject = [projectClass object];
projectObject[@"name"] = @"Super Project #41!";
projectObject[@"description"] = @"This is a very cool project";
[projectObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
        // object is created successfully
    } else {
        // there was an error in creating the object
        // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectObject:BuiltObject = projectClass.object()
projectObject["name"] = "Super Project #41!"
projectObject["description"] = "This is a very cool project"
projectObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
        // object is created successfully
    }else {
        // there was an error in creating the object
        // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltObject projectObject = builtApplication.classWithUid("project").object();
 
projectObject.set("name", "Super Project #41!");
projectObject.set("description", "This is a very cool project");
 
projectObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
            if(error == null){
               // object is created successfully
            }else{
               // some error has occurred.
               // refer to the 'error' object for more details.
            }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'project' is a uid of a class on Built.io Backend
var Project = Built.App('blt5d4sample2633b').Class('project').Object;
var project = Project();

project = project.assign({
    name: 'Super Project #41!',
    description: 'This is a very cool project'
});

project
.save()
.then(function(project) {
    // object created successfully
    console.log(project.toJSON());
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class("class_uid").Object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend
var project = Built.App("blt5d4sample2633b").Class("project").Object;
project["name"] = "Super Project #41!";
project["description"] = "This is a very cool project";
project.Save().ContinueWith((objectTask) =>
{
   if (objectTask.IsFaulted)
        {
                // there was an error in creating the object
                // objectTask.Exception.Flatten().InnerException contains more details regarding the same                     
        }
        else
        {
                // object is created successfully
        }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "object": {
          "name": "Super Project #41!",
          "description": "This is a very cool project"
       }
    }' \

https://api.built.io/v1/classes/project/objects
RESPONSE:
{
    "notice": "Object created successfully",
    "object": {
        "published": true,
        "uid": "blt0ae4df463e93f6f5",
        "name": "Super Project #41!",
        "description": "This is a very cool project",
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

The code given above will help you create an object called Super Project #41 in the Projects class. You will get a success message on creation of the object. If you are logged in as a user, the object you create will come under your ownership. This means that you obtain exclusive rights to the object, and other users will need permission to access your object. If you wish to check whether the object exists, you can do this by clicking on Objects under 'Data' in the management console. 

Retrieve objects

Let's say you have created several objects using the above method in the Projects class. Now, if you wish to get the whole list of objects created under this class, execute the code given below:

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltQuery *projectQuery = [projectClass query];
[projectQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
        // the query has executed successfully.
        // [result getResult] will contain a list of objects
    }else {
        // query execution failed.
        // error.userinfo contains more details regarding the same
    }}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectQuery:BuiltQuery = projectClass.query()
projectQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
        // the query has executed successfully.
        // result.getResult() will contain a list of objects        
    }else {
        // query execution failed.
        // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltQuery projectQuery           = builtApplication.classWithUid("project").query();
 
projectQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
 
        if(error == null){
            // the queryResultObject will contain the objects of the class.
            List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
            // some error has occurred.
            // refer to the 'error' object for more details.
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('project').Query();

query
.exec()
.then(function(projects) {
    // projects is an array of SDK objects
    // here's the object we just created
    console.log(projects[0].toJSON());
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var query = Built.App("blt5d4sample2633b").Class("project").Query();
query.Exec().ContinueWith(queryTask =>
{
    if (queryTask.IsFaulted)
    {
        // some error has occurred
        // refer to the objectTask.Exception.Flatten().InnerException for more details
    }
    else
    {
        // projects is an array of SDK objects
        // here's the object we just created
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Super Project #41!",
            "description": "We use this project internally",
            "updated_at": "2015-01-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

When you execute this GET API call, you get the entire list of all the objects in the Projects class. Here, object retrieval is limited to a maximum of 1000 objects at a time. You will notice that each of these objects contain a uid. This is because every time you create an object, a uid is generated for that object. This uid (a set of alphanumeric characters) is unique, which means no other object in your application would have the same uid. Therefore, the uid can be used to identify and retrieve an object in your application.

To obtain any object's uid, you can retrieve all objects created in a class by executing the above code using SDK/API, and search for the required object. Alternatively, you can go to the Objects section under 'Data' on the left panel in your management console. This will give you the list of all the objects (along with its uid) created until now in the given class.

Retrieve a particular object

If you have the uid of an object, you can retrieve that object instantly. Let's say you want to retrieve the 'Super Project #41' object that we created just a while ago in the above section. To do this, use the code mentioned below.

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltObject *projectObject = = [projectClass objectWithUID:@"blt0ae4df463e93f6f5"];;
[projectObject fetch:^(BuiltResponseType responseType, BuiltObject *object, NSError *error) {
  if(error == nil){
      // object is fetched successfully
  } else {
      // there was an error in fetching the object
      // error.userinfo contains more details regarding the same
  }}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectObject:BuiltObject = projectClass.objectWithUID("blt0ae4df463e93f6f5")
projectObject.fetch { (responseType: BuiltResponseType, object:BuiltObject!, error:NSError!) -> Void in
  if (error == nil) {
      // object is fetched successfully
  }else {
      // there was an error in fetching the object
      // error.userinfo contains more details regarding the same
  }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication  = Built.application(context,"blt5d4sample2633b");
 
BuiltObject projectObject   = builtApplication.classWithUid("project").object("blt0ae4df463e93f6f5");
 
projectObject.fetch(new BuiltResultCallBack() {
 
  @Override
  public void onCompletion(BuiltResponseType responseType, BuiltError error) {
      
      if(error == null){
           // object fetched successfully.
      }else{
           // some error has occurred.
           // refer to the 'error' object for more details.    
      }
  }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'blt0ae4df463e93f6f5' is a uid of an object in 'Project' class
var project = Built.App('blt5d4sample2633b').Class('project').Object('blt0ae4df463e93f6f5');
project
.fetch()
.then(function(project) {
    console.log(project.toJSON());
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'blt0ae4df463e93f6f5' is a uid of an object in 'Project' class
var project = Built.App("blt5d4sample2633b").Class("project").Object("blt0ae4df463e93f6f5");
project.Fetch().ContinueWith(objectTask =>
{
    if (objectTask.IsFaulted)
    {
        // some error has occurred.
        // objectTask.Exception.Flatten().InnerException contains more details regarding the same                     
    }
    else
    {
        // object fetched successfully.
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
https://api.built.io/v1/classes/project/objects/blt0ae4df463e93f6f5
RESPONSE:
{
    "object": {
        "published": true,
        "uid": "blt0ae4df463e93f6f5",
        "name": "Super Project #41!",
        "description": "We use this project internally",
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Updating object

You can update any details of any objects you have created in your class. To get a hang of it, let's try to simply change the description of the 'Super Project #41' object from 'This is a very cool project' to 'We use this project internally'.

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
// When a object is initiated using a uid, save method will make an update call instead of create.
BuiltObject *projectObject = [projectClass objectWithUID:@"blt0ae4df463e93f6f5"];
projectObject[@"description"] = @"We use this project internally";
[projectObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
        // object is updated successfully
    } else {
        // there was an error in updating the object
        // error.userinfo contains more details regarding the same
    }
}];
 
// Alternatively, use the "eventually" format to save it when network is available: 
[projectObject saveEventually:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
        // object is updated successfully
    } else {
        // there was an error in updating the object
        // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
// When a object is initiated using a uid, save method will make an update call instead of create.
var projectObject:BuiltObject = projectClass.objectWithUID("blt0ae4df463e93f6f5")
projectObject["description"] = "We use this project internally"
projectObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
        // object is created successfully
    }else {
        // there was an error in creating the object
        // error.userinfo contains more details regarding the same
    }
}
 
// Alternatively, use the "eventually" format to save it when network is available: 
projectObject.saveEventually { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend.

BuiltApplication builtApplication  = Built.application(context,"blt5d4sample2633b");

// setUid will identify the object, and calling save will update it.
BuiltObject projectObject = builtApplication.classWithUid("project").object("blt0ae4df463e93f6f5");
projectObject.set("description", "We use this project internally");

projectObject.save(new BuiltResultCallBack() {
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
        if(error == null){
             // object updated successfully
        }else{
             // some error has occurred
             // refer to the 'error' object for more details    
        }
    }
 });

// Alternatively, use the "eventually" format to save it when network is available:
projectObject.saveEventually(new BuiltResultCallBack() {
 ...
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'project' is a uid of a class on Built.io Backend
var Project = Built.App('blt5d4sample2633b').Class('project').Object;

// When a object is initiated using a uid, save method will make an update call instead of create.
var project = Project('blt0ae4df463e93f6f5');

project = project.set('description', 'We use this project internally');

project
.save()
.then(function(project) {
    // object updated successfully
    console.log(project.toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class("class_uid").Object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend
// setUid will identify the object, and calling save will update it.
var project = Built.App("blt5d4sample2633b").Class("project").Object().SetUid("blt0ae4df463e93f6f5");

project["description"] = "We use this project internally";
project.Save().ContinueWith(objectTask =>
{
        if (objectTask.IsFaulted)
        {
                // some error has occurred
                // objectTask.Exception.Flatten().InnerException contains more details regarding the same                     
        }
        else
        {
                // object updated successfully
        }
});
 
 
// Alternatively, use the "eventually" format to save it when network is available:
project.SaveEventually().ContinueWith(objectTask=>
{
...
});
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
       "object": {
           "description": "We use this project internally"
       }
    }' \
https://api.built.io/v1/classes/project/objects/bltf4fbbc94e8c851db
RESPONSE:
{
    "notice": "Object updated successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "name": "Super Project #41!",
        "description": "We use this project internally",
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Upsert objects

Upsert (UPdate or inSERT) allows you to update an existing object by specifying a criteria to search for it. If the object is not found, a new object will be created using the parameters supplied.

An upsert operation will take two sets of parameters. The first is a criteria to search for objects. The second is a set of parameters using which the update or create operation will be performed.

In the SDKs, upsert is implemented as a method that only takes the search criteria. The upsert call is executed when you save that object.

The following is an upsert operation on the Application User Roles class. With this upsert operation, a role object will be created or updated with the name 'Friends':

// 'blt5d4sample2633b' is a dummy Application API key
// 'built_io_application_user_role' refers to an inbuilt 'Application User Role' class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *roleClass = [builtApplication classWithUID:@"built_io_application_user_role"];
BuiltObject *roleObject = [roleClass object];
roleObject[@"users"] = @[@"bltf4fbbc94e8c85g1db"];
roleObject[@"name"] = @"Friends";    
[roleObject upsert:@{@"name":@"Friends"}]; //upserting will search for value "Friends" in "name" and that record will be updated with "users" value specified
[roleObject save:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
        // object is upserted successfully
    } else {
      // there was an error in upserting the object
      // error.userinfo contains more details regarding the same
    }
}];

// 'blt5d4sample2633b' is a dummy Application API key
// 'built_io_application_user_role' refers to an inbuilt 'Application User Role' class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var roleClass:BuiltClass = builtApplication.classWithUID("built_io_application_user_role")
var roleObject:BuiltObject = roleClass.object()
roleObject["users"] = ["bltf4fbbc94e8c85g1db"]
roleObject["name"] = "Friends"
roleObject.upsert(["name":"Friends"]) //upserting will search for value "Friends" in "name" and that record will be updated with "users" value specified
roleObject.save{ (response : BuiltResponseType, error : NSError!) -> Void in
    if (error == nil) {
        // object is upserted successfully
    }else {
      // there was an error in upserting the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltObject projectObject = builtApplication.classWithUid("built_io_application_user_role").object();
 
HashMap<String, Object> searchCriteria = new HashMap<String, Object>();
searchCriteria.put("name", "Friends");
 
HashMap<String, Object> replaceCriteria = new HashMap<String, Object>();
replaceCriteria.put("name", "Friends");
replaceCriteria.put("users", "bltf4fbbc94e8c85g1db");
 
projectObject.upsert(searchCriteria);
projectObject.set(replaceCriteria);
 
projectObject.save(new BuiltResultCallBack() {
 
  @Override
  public void onCompletion(BuiltResponseType responseType, BuiltError error) {
      
    if(error == null){
        //object is upserted successfully
    }else{
        // some error has occurred
        // refer to the 'error' object for more details    
      }
  }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'Built.Constants.APP_ROLE_CLS' refers to an inbuilt 'Application User Role' class on Built.io Backend
var Role = Built.App('blt5d4sample2633b').Class(Built.Constants.APP_ROLE_CLS).Object;
var role = Role();
role = role.assign({
    name: 'Friends',
    users: ['bltf4fbbc94e8c85g1db']
});
role = role.upsert({
    name: 'Friends'
});
role
.save()
.then(function(role) {
    //object is upserted successfully
    console.log(role.toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend
var Role = Built.App("blt5d4sample2633b").Class("built_io_application_user_role").Object();
Dictionary<string, object> searchCriteria = new Dictionary<string,object>();
searchCriteria["name"] = "Friends";
Role["name"] ="Friends";
Role["users"] = "bltf4fbbc94e8c85g1db";
BuiltObject.Upsert upsert = new BuiltObject.Upsert (searchCriteria, Role);
Role.UpsertObject(upsert).ContinueWith((objectTask) => 
{
        if(objectTask.IsFaulted)
        {
                // some error has occurred
                // refer to the objectTask.Exception.Flatten().InnerException for more details    
        }
        else
        {
                //object is upserted successfully
        }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "UPSERT": {
          "name": "Friends"
      },
      "object": {
          "name": "Friends",
          "users": [
              "bltf4fbbc94e8c85g1db"
          ]
       }
   }' \
https://api.built.io/v1/classes/built_io_application_user_role/objects
RESPONSE:
 {
    "notice": "Object created successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "name": "Friends",
        "users": [
            "bltbcbbb4730c4af8f1"
        ],
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Draft functionality

Saving an object as a draft enables you to save the object even though it is incomplete, and you can complete the object later. Since these objects remain unpublished, the validations for uniqueness or mandatory will not work.

To save an object as draft with REST, set the 'published' attribute of the object to 'false'. With the SDKs, call saveAsDraft

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltObject *projectObject = [projectClass object];
projectObject[@"name"] = @"Super Project #41!";
projectObject[@"description"] = @"This is a very cool project";
[projectObject saveAsDraft:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
        // object is saved as draft
    } else {
        // there was an error in saving the object
        // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectObject:BuiltObject = projectClass.object()
projectObject["name"] = "Super Project #41!"
projectObject["description"] = "This is a very cool project"
projectObject.saveAsDraft{ (response : BuiltResponseType, error : NSError!) -> Void in
    if (error == nil) {
        // object is saved as draft
    }else {
      // there was an error in saving the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltObject projectObject = builtApplication.classWithUid("project").object();
 
projectObject.set("name", "Super Project #41!");
projectObject.set("description", "This is a very cool project");
 
projectObject.saveAsDraft(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
        
        if(error == null){
            // object is created successfully
 
        }else{
            // some error has occurred.
            // refer to the 'error' object for more details.
        }
 
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var project = Built.App('blt5d4sample2633b').Class('project').Object();

project = project.assign({
    name: 'Super Project #41!',
    description: 'This is a very cool project'
});

project
.saveAsDraft()
.then(function(project) {
    console.log(project.toJSON())
}, function(error) {
    // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var project = Built.App("blt5d4sample2633b").Class("project").Object();

project["name"] = "Super Project #41!";
project["description"] ="This is a very cool project";
project.SaveAsDraft().ContinueWith(objectTask =>
{
        if (objectTask.IsFaulted)
        {
                // some error has occurred
                // refer to the objectTask.Exception.Flatten().InnerException for more details    
        }
        else
        {
                // object is created successfully
        }

});
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
        "object": {
            "published": false
         }
     }' \
https://api.built.io/v1/classes/project/objects/bltf4fbbc94e8c851db
RESPONSE:
 {
    "notice": "Object updated successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "name": "Super Project #41!",
        "description": "We use this project internally",
        "updated_at": "2015-02-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
 }

Here's how you get the object back to the published state:

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltObject *projectObject = [projectClass objectWithUID:@"blt81b274bc5217389a"];
projectObject[@"published"] = @(YES);
[projectObject save:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
      // object is published
    } else {
      // there was an error in saving the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var projectObject:BuiltObject = projectClass.objectWithUID("blt81b274bc5217389a")
projectObject["published"] = NSNumber(bool:true)
projectObject.save{ (response : BuiltResponseType, error : NSError!) -> Void in
    if (error == nil) {
      // object is published
    }else {
      // there was an error in saving the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
 
// setUid will identify the object, and calling save will update it.
BuiltObject projectObject = builtApplication.classWithUid("project").object("blt0ae4df463e93f6f5");
 
projectObject.set("published", true);
 
projectObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
        
        if(error == null){
             // object updated successfully
        }else{
             // some error has occurred
             // refer to the 'error' object for more details    
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'project' is a uid of a class on Built.io Backend
var Project = Built.App('blt5d4sample2633b').Class('project').Object;
var project = Project('blt81b274bc5217389a');

project = project.set('published', true);

project
.save()
.then(function(project) {
    // object updated successfully
    console.log(project.toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'project' is a uid of a class on Built.io Backend
// setUid will identify the object, and calling save will update it.
var project = Built.App("blt5d4sample2633b").Class("project").Object().SetUid("blt81b274bc5217389a");
 
project["published"] = true;
 
project.Save().ContinueWith(objectTask =>
{
        if (objectTask.IsFaulted)
        {
                // some error has occurred
                // refer to the objectTask.Exception.Flatten().InnerException for more details    
        }
        else
        {
                // object updated successfully
        }
});
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "object": {
          "published": true
      }
   }' \
https://api.built.io/v1/classes/project/objects/bltf4fbbc94e8c851db
RESPONSE:
{
    "notice": "Object updated successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "name": "Super Project #41!",
        "description": "We use this project internally",
        "updated_at": "2015-02-28T09:05:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

References

Set reference

Reference fields are arrays of uids that refers another objects. For our project, each of the classes (Task, Milestone, Bug and Comment) has a reference to the 'Projects' class. Let's say we want to create a milestone for our project. To do this, we will have to set a reference in the milestone object referring to that project. Let's consider an example to understand this better. Suppose we have a project with uid: bltb6202sample73a1, and we wish to create a milestone for it. To do this, while creating the milestone, we set this 'uid' in its reference field 'project'.

// 'blt5d4sample2633b' is a dummy Application API key
// 'milestone' is a uid of a class on Built.io Backend Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *milestoneClass = [builtApplication classWithUID:@"milestone"];
BuiltObject *milestoneObject = [milestoneClass object];
milestoneObject[@"name"] = @"First milestone";
milestoneObject[@"description"] = @"It may take a long time to get here";
// 'bltb6202sample73a1' is an uid of an object of 'project' class, to which miltestone is setting a reference.
[milestoneObject setReference:@[@"bltb6202sample73a1"] forKey:@"project"];
[milestoneObject save:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
      // object is created successfully
    } else {
      // there was an error in saving the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'milestone' is a uid of a class on Built.io Backend Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var milestoneClass : BuiltClass = builtApplication.classWithUID("milestone")
var milestoneObject:BuiltObject = milestoneClass.object()
milestoneObject["name"] = "First milestone"
milestoneObject["description"] = "It may take a long time to get here"
// 'bltb6202sample73a1' is an uid of an object of 'project' class, to which miltestone is setting a reference.
milestoneObject.setReference(["bltb6202sample73a1"], forKey: "project")
milestoneObject.save{ (response : BuiltResponseType, error : NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in saving the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'milestone' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltClass milestoneClass = builtApplication.classWithUid("milestone");
BuiltObject milestoneObject = milestoneClass.object();
 
milestoneObject.set("name", "First milestone");
milestoneObject.set("description", "It may take a long time to get here");
 
// 'bltb6202sample73a1' is an uid of an object of 'project' class, to which miltestone is setting a reference.
milestoneObject.setReference("project", "bltb6202sample73a1");
 
milestoneObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
        
        if(error == null){
          // object is created successfully
        }else{
          // some error has occurred.
          // refer to the 'error' object for more details.
        }
 
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'milestone' is a uid of a class on Built.io Backend
var Milestone = Built.App('blt5d4sample2633b').Class('milestone').Object;
var milestone = Milestone();

milestone = milestone.assign({
    name: 'First milestone',
    description: 'It may take a long time to get here'
});

// 'bltb6202sample73a1' is an uid of an object of 'project' class, to which miltestone is setting a reference.
milestone = milestone.setReference('project', ["bltb6202sample73a1"]);

milestone
.save()
.then(function(milestone) {
    // object created successfully
    console.log(milestone.toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'milestone' is a uid of a class on Built.io Backend
var milestoneObject = Built.App("blt5d4sample2633b").Class("milestone").Object();

 
milestoneObject["name"] = "First milestone";
milestoneObject["description"] = "It may take a long time to get here";
 
// 'bltb6202sample73a1' is an uid of an object of 'project' class, to which miltestone is setting a reference.
milestoneObject.SetReference("project",new string[] { "bltb6202sample73a1"});
 
milestoneObject.Save().ContinueWith(objectTask =>
{
    if (objectTask.IsFaulted)
    {
        // some error has occurred
        // refer to the objectTask.Exception.Flatten().InnerException for more details    
    }
    else
    {
        // object created successfully
    }
});
curl -X POST 
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json"
-d '{
    "object": {
        "name": "First milestone",
        "description": "It may take a long time to get here",
        "project": [
            "bltb6202sample73a1"
        ]
    }
}'\
https://api.built.io/v1/classes/milestone/objects
RESPONSE:
{
    "notice": "Woot! Object created successfully.",
    "object": {
        "uid": "bltdb09bce27e904ceb",
        "published": true,
        "project": [
            "blt0ae4df463e93f6f5"
        ],
        "description": "It may take a long time to get here",
        "name": "First milestone",
        "created_at": "2015-04-22T10:11:06.639Z",
        "updated_at": "2015-04-22T10:11:06.639Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

You can also set reference inside the group field. To understand it better, let’s us have a look at an example. Suppose you create a new group field ‘Project Manager’ in the Project class, which has three sub-fields: Name, Age, and Department. In the following code snippet, we will see how to set reference in the ‘Department’ sub-field.

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
 
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltObject *projectObject = [projectClass object];
 
BuiltGroup* projectManager = [BuiltGroup groupWithFieldName:@"project_manager"];
projectManager[@"name"] = @"John";
projectManager[@"age"] = @(32);
[projectManager setReference:@[@"blt124sample2122l", @"blt311sample2324G"] forKey:@"departments"];
 
projectObject.addGroup(projectManager);
 
[projectObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];	
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
 
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectObject:BuiltObject = projectClass.object()
 
var projectManager:BuiltGroup = BuiltGroup(fieldName:"project_manager")
projectManager["name"] = "John"
projectManager["age"] = NSNumber(Int: 32)
projectManager.setReference(["blt124sample2122l", "blt311sample2324G"], forKey:"departments")
 
projectObject.addGroup(projectManager)
 
projectObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend

BuiltObject projectObject = Built.application(context, "blt5d4sample2633b").classWithUid("project").object();
 
BuiltGroup pm = new BuiltGroup("project_manager");
pm.set("name", "John");
pm.set("age", 32);
pm.setReference("departments", new String[]{"blt124sample2122l", "blt311sample2324G"});
 
projectObject.addGroup(pm);
 
projectObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
         if(error == null){
              // object is created successfully.
         }else{
              // some error has occurred
              // refer to the 'error' object for more details    
         }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'project' is a uid of a class on Built.io Backend
var Project = Built.App('blt5d4sample2633b').Class('project').Object
var project = Project()

var pm = Built.Group('project_manager', [{
    name: 'John',
    age: 32
}])

pm = pm.setReference("departments", ["blt124sample2122l", "blt311sample2324G"])

project = project.addGroup(pm)

console.log("Project object", project.toJSON())

project
.save()
.then(function (project) {
    console.log(project.toJSON())
})
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var projectObject = Built.App("blt5d4sample2633b").Class("project").Object();

BuiltGroup pm = Built.Group("project_manager", new Dictionary { { "name", "John" }, {"age", 32} });

pm.SetReference("departments", new string[]{"blt124sample2122l", "blt311sample2324G"});
 
projectObject.AddGroup(pm);
 
projectObject.Save().ContinueWith(objectTask =>
{
    if (objectTask.IsFaulted)
    {
        // some error has occurred
        // refer to the objectTask.Exception.Flatten().InnerException for more details    
    }
    else
    {
        // object is created successfully.
    }

});
curl -X POST 
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json"
-d '{
    "object": {
        "name": "test",
        "description": "test",
        "project_manager": {
            "name": "John",
            "age": 32,
            "department": [
                "blt124sample2122l",
                "blt311sample2324G"
            ]
        }
    }
}'\
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
    "notice": "Woot! Object created successfully.",
    "object": {
        "uid": "bltdb09bce27e904ceb",
        "published": true,
        "project": [
            "bltb6202sample73a1"
        ],
        "name": "Super Project #41!",
        "description": "This is a very cool project",
        "project_manager": {
            "name": "John",
            "age": 32,
            "department": [
                "blt124sample2122l",
                "blt311sample2324G"
            ]
        },
        "created_at": "2015-04-22T10:11:06.639Z",
        "updated_at": "2015-04-22T10:11:06.639Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

There may be times when you do not know the uid of the reference object, but know certain conditions that only that reference object will satisfy. Built.io Backend allows you to set reference field using a query (set of conditions). It is important to note that only one reference object should satisfy these conditions, as Built.io Backend does not allow multiple references to be set using query. In the following snippet, we specify that the project having name as 'Super Project #41!'to be set as a reference in the 'project' field:

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
 
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltObject *bugsObject = [bugsClass objectWithUID:@"blt0ae4df463e22a6f5"];
 
// Object having name as 'Super Project #41!' is assigned as reference 
[bugsObject setReferenceWhere:@{@"name":@"Super Project #41!"} forKey:@"project"];
 
[bugsObject save:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
      // object is created successfully
    } else {
      // there was an error in saving the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
 
var bugClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugObject:BuiltObject = builtApplication.objectWithUID("blt0ae4df463e22a6f5")
 
// Object having name as 'Super Project #41!' is assigned as reference 
bugsObject.setReferenceWhere(["name":"Super Project #41!"] forKey:"project"])
 
bugsObject.save{ (response : BuiltResponseType, error : NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in saving the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltClass bugsClass = builtApplication.classWithUid("bugs");
BuiltObject bugsObject = bugsClass.object();
 
// Object having name as 'Super Project #41!' is assigned as reference 
HashMap<String,Object> hash = new HashMap<String, Object>();
hash.put("name", "Super Project #41!");
bugsObject.setReferenceWhere("project", hash);
 
bugsObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
        
        if(error == null){
          // object is created successfully
 
        }else{
          // some error has occurred.
          // refer to the 'error' object for more details.
        }
 
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var app = Built.App('blt5d4sample2633b');
var bug = app.Class('bugs').Object('blt0ae4df463e22a6f5');

// Object having name as 'Super Project #41!' is assigned as reference 
bug = bug.setReferenceWhere('project',{name: "Super Project #41!"}); 
bug.save()
.then(function(res){
  // object's ref_address field is updated
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
var bugsObject = Built.App("blt5d4sample2633b").Class("bugs").Object();

var project = Built.App("blt5d4sample2633b").Class("project").Object();
// Object having name as 'Super Project #41!' is assigned as reference 
project["name"] = "Super Project #41!";
bugsObject.SetReferenceWhere("project", project);
 
bugsObject.Save().ContinueWith(objectTask =>
{
    if (objectTask.IsFaulted)
    {
        // some error has occurred
        // refer to the objectTask.Exception.Flatten().InnerException for more details    
    }
    else
    {
        // object is created successfully.
    }
});
curl -X POST 
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json"
-d '{
    "object": {
        "name": "Issues while creating data",
        "project": {
            "WHERE": {
                "name": "Super Project #41!"
            }
        }
    }
}'\
https://api.built.io/v1/classes/bugs/objects
RESPONSE:
{
    "notice": "Woot! Object created successfully.",
    "object": {
        "uid": "blte9ab0d760c45957c",
        "published": true,
        "app_user_object_uid": "bltdbsample904ceb",
        "tags": [],
        "project": [
            "blt0ae4df463e93f6f5"
        ],
        "status": "",
        "severity": "",
        "due_date": "2015-12-15T11:11:11.639Z",
        "reproducible": "",
        "description": "Issues while creating project data",
        "name": "Issues while creating data",
        "created_at": "2015-04-22T10:11:06.639Z",
        "updated_at": "2015-04-22T10:11:06.639Z"
    }
}

If you want to achieve this for a field that is part of a group field, use the code given below:

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
 
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltObject *projectObject = [projectClass object];
 
BuiltGroup *projectManager = [BuiltGroup groupWithFieldName:@"project_manager"];
projectManager[@"name"] = @"John";
projectManager[@"age"] = @(32);
 
[projectManager setReferenceWhere:@{@"department_type":@"type1"} forKey:@"departments"];
 
projectObject.addGroup(projectManager);
 
[projectObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
 
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectObject:BuiltObject = projectClass.object()
 
var projectManager:BuiltGroup = BuiltGroup(fieldName:"project_manager")
projectManager["name"] = "John"
projectManager["age"] = NSNumber(Int:32)
projectManager.setReferenceWhere(["department_type":"type1"], forKey:"departments")
 
projectObject.addGroup(projectManager)
 
projectObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend

BuiltObject projectObject = Built.application(context, "blt5d4sample2633b").classWithUid("project").object();
 
BuiltGroup pm = new BuiltGroup("project_manager");
pm.set("name", "John");
pm.set("age", 32);
 
HashMap<String, Object> conditionHash = new HashMap<String, Object>();
conditionHash.put("department_type", "type1");
 
pm.setReferenceWhere("departments", conditionHash);
 
projectObject.addGroup(pm);
 
projectObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
         if(error == null){
              // object is created successfully.
         }else{
              // some error has occurred
              // refer to the 'error' object for more details    
         }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'project' is a uid of a class on Built.io Backend

var Project = Built.App('blt5d4sample2633b').Class('project').Object
var project = Project()
var pm = Built.Group('project_manager', [{
        name: 'John',
        age: 32
    }])
    // All the departments which have department type as 'type1' should be set as reference
pm = pm.setReferenceWhere("departments", {
    department_type: "type1"
})
project = project.addGroup(pm)
console.log("Project object", project.toJSON())
project
.save()
.then(function(project) {
    console.log(project.toJSON())
})
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var projectObject = Built.App("blt5d4sample2633b").Class("project").Object();

 
BuiltGroup pm = Built.Group("project_manager", new Dictionary { { "name", "John" }, {"age", 32} });

   Dictionary condition = new Dictionary();

condition.Add("department_type","type1");
 
pm.SetReferenceWhere("departments", condition);
 
projectObject.AddGroup(pm);
 
projectObject.Save().ContinueWith(objectTask =>
{
    if (objectTask.IsFaulted)
    {
        // some error has occurred
        // refer to the objectTask.Exception.Flatten().InnerException for more details    
    }
    else
    {
        // object is created successfully.
    }
});
curl -X POST 
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json"
-d '{
    "object": {
        "name": "Super Project #42!",
        "description": "This is a very good project",
        "project_manager": {
            "name": "John",
            "age": 32,
            "department": {
                "WHERE": {
                    "name": "Cloud"
                }
            }
        }
    }
}'\
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
  "notice": "Woot! Object created successfully.",
  "object": {
    "uid": "blt9e8199adc3170d2c",
    "published": true,
    "app_user_object_uid": "blt9esample70d2c",
    "tags": [],
    "project_manager": {
      "name": "John",
      "age": 32,
      "department": [
        "blte9ab0d760c45957c"
      ]
    },
    "name": "Super Project #42!",
    "description": "This is a very good project",
    "created_at": "2015-04-22T10:11:06.639Z",
    "updated_at": "2015-04-22T10:11:06.639Z"
  }
}

Set reference with object

As you saw in the 'setReference' method, you can assign an array of uids to a reference field of an object. This is the case when referred objects already exist. However, if the objects that you want to refer to, do not exist, you can use the 'setReferenceWithObject' method. This method will first create objects of the referenced class(Project), and then assign their uids in the reference field.

In order to create the referenced object while executing the 'setReferenceWithObject' method, we need to provide the data, using which the new referenced object would be created. The following code snippet demonstrates this:

//'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend 
 
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
 
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltObject *projectObject  = [projectClass object];
projectObject[@"name"] = @"Super Project #41!";
 
BuiltClass *taskClass = [builtApplication classWithUID:@"task"];
BuiltObject *taskObject  = [taskClass object];
 
// setting the project reference
[taskObject setReferenceWithObject:projectObject forKey:@"project"];

//'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend 
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
 
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectObject:BuiltObject = projectClass.object()
projectObject["name"] = "Super Project #41!"
 
var taskClass:BuiltClass = builtApplication.classWithUID("task")
var taskObject:BuiltObject = taskClass.object()
 
// setting the project reference
taskObject.setReferenceWithObject(projectObject, forKey:"project")
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
 
// 'project' is a uid of a class on Built.io Backend 
BuiltObject projectObject = builtApplication.classWithUid("project").object();
projectObject.set("name", "Super Project #41!");     
 
// 'task' is a uid of a class on Built.io Backend
BuiltObject taskObject  = builtApplication.classWithUid("task").object();
taskObject.setReferenceWithObject("project", projectObject);
 
taskObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
  
         if(error == null){
              // object is created successfully.
         }else{
              // some error has occurred
              // refer to the 'error' object for more details    
         }
    }
});
//'blt5d4sample2633b' is a dummy Application API key
// Class('class_name').Object returns an Object constructor
// 'task' is a uid of a class on Built.io Backend 
// 'blt12sampleb09111' is uid of an object on Built.io Backend
var app  = Built.App('blt5d4sample2633b');
var Task  = app.Class('tasks').Object;
var task  = Task('blt12sampleb09111');       

task    = task.setReferenceWithObject('project', [{
  name: 'Super Project #41!'
}]); 

task
.then(function(task) { 
  console.log(task.toJSON()) 
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend 
BuiltObject projectObject = Built.App("blt5d4sample2633b").Class("project").Object();
projectObject["name"] = "Super Project #41!";     

// 'task' is a uid of a class on Built.io Backend
BuiltObject taskObject = Built.App("blt5d4sample2633b").Class("task").Object();
taskObject.SetReferenceWhere("project", projectObject);

taskObject.Save().ContinueWith(objectTask =>
{
    if(objectTask.IsFaulted)
    {         
        // some error has occurred
        // refer to the objectTask.Exception.Flattern().InnerException for more details 
    }
    else
    {
        // object is created successfully.   
    }
});

Get referenced objects

If you get a particular object, you would normally get the referenced objects uids. However, if you want to fetch the referenced objects itself(not just their uids), Built.io Backend allows you to do that as well. Let us understand this with an example. If you want to fetch the 'project' object itself while fetching the bug object, you need to specify Built.io Backend that you want the referenced object 'project' in response. This is done by passing the parameter 'include[]=project', where project is the name of the reference field.

// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on built.io
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
 
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltQuery *bugsQuery = [bugsClass query];  
 
[bugsQuery includeReference:@[@"project"]];
 
[bugsQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on built.io
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
 
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugsQuery:BuiltQuery = bugsClass.query()
 
bugsQuery.includeReference(["project"])
 
bugsQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
 
BuiltClass bugsClass = builtApplication.classWithUid("bugs");
BuiltQuery bugsQuery = bugsClass.query();  
 
ArrayList<String> array = new ArrayList<String>();
array.add("project");
bugsQuery.includeReference(array);
 
bugsQuery.exec(new QueryResultsCallBack() {
 
  @Override
  public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
 
      if(error == null){
        // the queryResultObject will contain the objects of the class.
        List<BuiltObject> objects = queryResultObject.getResultObjects();
 
      }else{
        // some error has occurred.
        // refer to the 'error' object for more details.
      }
  }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var app = Built.App('blt5d4sample2633b');

var bugsQuery = app.Class('bugs').Query()

bugsQuery
.include(['project'])
.exec()
.then(function(bugs) {
    // bugs is array of SDK objects
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var app = Built.App("blt5d4sample2633b");
 
var bugsQuery = app.Class("bugs").Query()
 
bugsQuery.Include(new List<string>()
                                {
                                        "project"
                                });
bugsQuery.Exec().ContinueWith(queryTask =>
{
     if(queryTask.IsFaulted)
     {
           // some error has occurred
           // refer to the queryTask.Exception.Flatten().InnerException object for more details
     }
     else
     {    
         // queryTask.Result is array of SDK objects
     }
});
curl -X GET 
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \ 

https://api.built.io/v1/classes/bugs/objects?include[]=project
RESPONSE:
{
  "objects": [{
    "updated_at": "2015-04-22T10:44:38.346Z",
    "created_at": "2015-04-22T10:44:38.346Z",
    "name": "bug",
    "description": "",
    "reproducible": "",
    "due_date": "2015-04-22T19:31:20.460Z",
    "severity": "",
    "status": "",
    "project": [{
      "updated_at": "2015-04-22T09:31:20.460Z",
      "created_at": "2015-04-22T09:31:20.460Z",
      "name": "Super Project #41!",
      "description": "",
      "tags": [],
      "published": true,
      "uid": "bltf4fbbc94e8c851db"
    }],
    "published": true,
    "uid": "blt11e439867fb674d4",
    "tags": [],
    "ACL": {
      "can": []
    }
  }]
}

You can also filter out objects using certain conditions, and then have its referenced objects filled in the response. In the following snippet, we filter out only those bug objects whose status is 'open', and request its referenced field 'project' to be filled.

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
 
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltQuery *bugsQuery = [bugsClass query];  
 
[bugsQuery includeReference:@[@"project"]];
[bugsQuery whereKey:@"status" equalTo:@"open"];
 
[bugsQuery exec:^(BuiltResponseType type, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
 
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugsQuery:BuiltQuery = bugsClass.query()
 
bugsQuery.includeReference(["project"])
bugsQuery.whereKey("status", equalTo:"open")
 
bugsQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
 
BuiltClass bugsClass = builtApplication.classWithUid("bugs");
BuiltQuery bugsQuery = bugsClass.query();  
 
ArrayList<String> array = new ArrayList<String>();
array.add("project");
bugsQuery.includeReference(array);
 
bugsQuery.where("status", "open");
 
bugsQuery.exec(new QueryResultsCallBack() {
 
  @Override
  public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
 
      if(error == null){
        // the queryResultObject will contain the objects of the class.
        List<BuiltObject> objects = queryResultObject.getResultObjects();
 
      }else{
        // some error has occurred.
        // refer to the 'error' object for more details.
      }
  }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var app = Built.App('blt5d4sample2633b');
var projectQuery = app.Class('project').Query();
 
var bugsQuery = app.Class('bugs').Query()
 
bugsQuery
.include(['project'])
.where ('status', 'open');
.exec()
.then(function(bugs) {
  // bugs is array of SDK objects
}, function(error) {
  // some error has occurred
  // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
BuiltQuery bugsQuery = Built.App("blt5d4sample2633b").Class("bugs").Query(); 
 
List<String> list = new List<String>();
list.Add("project");
bugsQuery.Include(list);
 
bugsQuery.Where("status", "open");
 
bugsQuery.Exec().ContinueWith(queryTask =>
{
        if(queryTask.IsFaulted)
        {
                //some error has occured.
                // refet to the queryTask.Exception.Flatten().InnerException to see the more details
        }
        else
        {
                // the queryTask.Result will contain the objects of the class.
        }
});

Upsert reference

In Objects section, we saw that you can upsert (Update or insert) an object. Built.io Backend provides the same functionality for reference fields as well. 

Whenever Built.io Backend is asked to perform an 'upsert' operation, it first searches for the given object. If the object exists, it updates the object with the given update parameters; else, it uses the update parameters to create a new object. 

Let's understand this with the help of an example.   

Let's say you want to create a task for a project and want to perform a 'upsert' operation on its referenced field 'project'. To do this you first need to specify that if a object with name 'Super Project #41!' exist in Projects class, updates its name with 'Super Project A'. If it does not exist, create a new object with name 'Super Project A'.

In both the cases, the referenced object's uid will be set in the bug object's referenced field 'project'.

// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
 
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *taskClass = [builtApplication classWithUID:@"task"];
BuiltObject *taskObject = [taskClass object];
 
// The method would first check Projects class (the class referred by 'Task' class using 'project' field) and 
// checks if any object with name 'Super Project #41!' exists; if yes, it would be replaced by 'Super Project'.
// If not, a new entry would be made with name as 'Super Project A'.
 
 // For multiple reference use addUpsertForReferences:condition:replaceWith:
[taskObject addUpsertForReferences:@"project" condition:@{@"name":@"Super Project #41!"} replaceWith:@{@"name":@"Super Project A"}];

// For single references use addUpsertForReference:condition:replaceWith:
[taskObject addUpsertForReference:@"my_project" condition:@{@"name":@"Super Project #42!"} replaceWith:@{@"name":@"Super Project 42"}];
 
[taskObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
 
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var taskClass:BuiltClass = builtApplication.classWithUID("task")
var taskObject:BuiltObject = taskClass.object()
 
// The method would first check Projects class (the class referred by 'Task' class using 'project' field) and 
// checks if any object with name 'Super Project #41!' exists; if yes, it would be replaced by 'Super Project'.
// If not, a new entry would be made with name as 'Super Project A'.
 
// For multiple reference use addUpsertForReferences:condition:replaceWith:
taskObject.addUpsertForReferences("project", condition:["name":"Super Project #41!"], replaceWith:["name":"Super Project 42"])

// For single reference use addUpsertForReference:condition:replaceWith:
taskObject.addUpsertForReference("my_project", condition:["name":"Super Project #42!"], replaceWith:["name":"Super Project 42"])
 
taskObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'project' is a uid of a class on Built.io Backend
// 'blt5d4sample2633b' is uid of an object on Built.io Backend
 
BuiltObject taskObject = Built.application(context, "blt5d4sample2633b").classWithUid("task").object();
 
// The method would first check Projects class (the class referred by 'Task' class using 'project' field) and
// checks if any object with name 'Super Project #41!' exists; if yes, it would be replaced by 'Super PropsertGroupForRefernceject A'.
// If not, a new entry would be made with name as 'Super Project A'.
HashMap<String, Object> searchCriteria = new HashMap<String, Object>();
searchCriteria.put("name", "Super Project #41!");
 
HashMap<String, Object> replaceCriteria = new HashMap<String, Object>();
replaceCriteria.put("name", "Super Project A");

//If project reference field with multiple true. 
taskObject.addUpsertForReferences("project", searchCriteria, replaceCriteria);

//If my_project reference field with multiple false. 
taskObject.addUpsertForReference("my_project", searchCriteria, replaceCriteria);
 
taskObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
         if(error == null){
              // object is created successfully.
         }else{
              // some error has occurred
              // refer to the 'error' object for more details    
         }
    }
});
// 'project' is a uid of a class on Built.io Backend 
// 'Class('class_name').Object returns an 'Object' constructor
// 'blt12sampleb09157' is uid of an object on Built.io Backend
var app  = Built.App('blt5d4sample2633b')
var Task = app.Class('task').Object
var task = Task()
 
// The method would first check Projects class (the class referred by 'Task' class using 'project' field) and 
// checks if any object with name 'Super Project #41!' exists; if yes, it would be replaced by 'Super Project'.
// If not, a new entry would be made with name as 'Super Project A'.
var upsertOps = Built.Upsert([{
    condition: {
        name: 'Super Project #41!'
    },
    replacement: {
        name: 'Super Project A'
    }
}])
task = task.upsertForReference('project', upsertOps)
 
task
.save()
.then(function(task) {
    console.log(task.toJSON())
})
// 'project' is a uid of a class on Built.io Backend
// 'blt5d4sample2633b' is uid of an object on Built.io Backend
BuiltObject taskObject = Built.App("blt5d4sample2633b").Class("task").Object();
 
// The method would first check Projects class (the class referred by 'Task' class using 'project' field) and
// checks if any object with name 'Super Project #41!' exists; if yes, it would be replaced by 'Super Project A'.
// If not, a new entry would be made with name as 'Super Project A'.
Dictionary<String, Object> searchCriteria = new Dictionary<String, Object>();
searchCriteria.Add("name", "Super Project #41!");
 
BuiltObject replaceCriteria = Built.App("blt5d4sample2633b").Class("project").Object();
replaceCriteria["name"] = "Super Project A";
 
List<BuiltObject.Upsert> upsert = new List<BuiltObject.Upsert>(){new BuiltObject.Upsert(searchCriteria, replaceCriteria)};
 
taskObject.UpsertForReference("project", upsert);
 
taskObject.Save().ContinueWith(objectTask =>
{
        if(objectTask.IsFaulted)
        {
                // some error has occurred
                // refer to the objectTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // object is created successfully.
        }
});

If you want to achieve this for a field that is part of a group field, use the code given below:

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
 
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltObject *projectObject = [projectClass object];
 
BuiltGroup *projectManager = [BuiltGroup groupWithFieldName:@"project_manager"];
projectManager[@"name"] = @"John";
projectManager[@"age"] = @(32);
 
[projectManager addUpsertForReferences:@"departments" condition:@{@"name":@"Department A1"} replaceWith:@{@"name":@"Department A", @"department_type":@"type1"}];
[projectManager addUpsertForReferences:@"departments" condition:@{@"name":@"Department B1"} replaceWith:@{@"name":@"Department B", @"department_type":@"type1"}];
 
projectObject.addGroup(projectManager)
 
[projectObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
 
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectObject:BuiltObject = projectClass.object()
 
var projectManager:BuiltGroup = BuiltGroup(fieldName:"project_manager")
projectManager["name"] = "John";
projectManager["age"] = NSNumber(Int:32)
 
projectManager.addUpsertForReferences("departments", condition:["name":"Department A1"], replaceWith:["name":"Department A", "department_type":"type1"])
projectManager.addUpsertForReferences("departments", condition:["name":"Department B1"], replaceWith:["name":"Department B", "department_type":"type1"])
 
projectObject.addGroup(projectManager)
 
projectObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
 
BuiltObject projectObject = Built.application(context, "blt5d4sample2633b").classWithUid("project").object();
psertGroupForRefernce
HashMap<String, Object> firstCondition = new HashMap<String, Object>();
firstCondition.put("name", "Department A1");
 
HashMap<String, Object> firstReplacement = new HashMap<String, Object>();
firstReplacement.put("name", "Department A");
firstReplacement.put("department_type", "type1");
 
HashMap<String, Object> secondCondition = new HashMap<String, Object>();
secondCondition.put("name", "Department B1");
 
HashMap<String, Object> secondReplacement = new HashMap<String, Object>();
secondReplacement.put("name", "Department B");
secondReplacement.put("department_type", "type1");
 
BuiltGroup pm = new BuiltGroup("project_manager");
pm.set("name", "John");
pm.set("age", 32);
 
//If departments reference field with multiple true. 
pm.addUpsertForReferences("departments", firstCondition, firstReplacement);
pm.addUpsertForReferences("departments", secondCondition, secondReplacement);
 
projectObject.addGroup(pm);
 
projectObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
         if(error == null){
              // object is created successfully.
         }else{
              // some error has occurred
              // refer to the 'error' object for more details    
         }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'project' is a uid of a class on Built.io Backend
var Project = Built.App('blt5d4sample2633b').Class('project').Object
var project = Project()

// Creates a instance of Built.Upsert which will represent the Upsert scenario
var upsertDep = Built.Upsert([{
    conditions: {
        name: "Department A1"
    },
    replacement: {
        name: "Department A",
        department_type: "type1"
    }
}, {
    conditions: {
        name: "Department B1"
    },
    replacement: {
        name: "Department B",
        department_type: "type1"
    }
}])

var pm = Built.Group('project_manager', [{
    name: 'John',
    age: 32
}])

pm = pm.upsertForReference('departments', upsertDep)

project
.addGroup(pm)
.save()
.then(function(project) {
    console.log(project.toJSON())
})
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltObject taskObject = Built.App("blt5d4sample2633b").Class("project").Object();


Dictionary<string, object> firstCondition = new Dictionary<string, object>();
firstCondition.Add("name", "Department A1");
BuiltObject firstReplacement = Built.App("blt5d4sample2633b").Class("departments").Object();
firstReplacement["name"] = "Department A";
firstReplacement["department_type"]=  "type1";
Dictionary<string, object> secondCondition = new Dictionary<string, object>();
secondCondition.Add("name", "Department B1");
BuiltObject secondReplacement = Built.App("blt5d4sample2633b").Class("departments").Object();
secondReplacement["name"] = "Department B";
secondReplacement["department_type"] = "type1";
BuiltGroup pm = Built.Group("project_manager", new Dictionary<string, object>(){{"name", "John"}, {"age", 32}} );
//adding condition and replacement respectively
pm.UpsertForReference("departments", new List(){new BuiltGroup.Upsert(){Condition = firstCondition, NewObject = firstReplacement},new BuiltGroup.Upsert(){Condition= secondCondition, NewObject = secondReplacement}});
projectObject.AddGroup(pm);
projectObject.Save().ContinueWith(objectTask=>
{
    if(objectTask.IsFaulted)
    {
        // some error has occurred
        // refer to the objectTask.Exception.Flattern().InnerException for more details 
    }   
    else
    {
        // object is created successfully.
    }
});

Tags

Objects can have tags attached to them. Tags are simply an array of values that allow you to categorize content. You can attach one or more tags to an object. Here's how you attach tags to an existing milestone object, categorizing it as 'interface' and 'ui':

// 'blt5d4sample2633b' is a dummy Application API key
// 'milestone' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *milestoneClass = [builtApplication classWithUID:@"milestone"];
BuiltObject *milestoneObject = [milestoneClass objectWithUID:@"blt73815f9c277d2d98"]; 
milestoneObject.tags = @[@"interface", @"ui"];
[milestoneObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'milestone' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var milestoneClass:BuiltClass = builtApplication.classWithUID("milestone")
var milestoneObject:BuiltObject = milestoneClass.objectWithUID("blt73815f9c277d2d98") 
milestoneObject.tags = ["interface", "ui"]
milestoneObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'milestone' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
 
// setUid will identify the object, and calling save will update it.
BuiltObject milestoneObject = builtApplication.classWithUid("milestone").object("blt0ae4df463e93f6f5");
 
milestoneObject.setTags(new String[] {"interface", "ui"});
 
milestoneObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
        
        if(error == null){
             // object updated successfully
        }else{
             // some error has occurred
             // refer to the 'error' object for more details    
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'milestone' is a uid of a class on Built.io Backend
var Milestone = Built.App('blt5d4sample2633b').Class('milestone').Object;
var milestone = Milestone('blt73815f9c277d2d98');

milestone = milestone.setTags(['interface', 'ui']);

milestone
.save()
.then(function(milestone) {
    // object updated successfully
    console.log(milestone.toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'milestone' is a uid of a class on Built.io Backend
var milestoneObject = Built.App("blt5d4sample2633b").Class("milestone").Object().SetUid("blt73815f9c277d2d98");
 
milestoneObject = milestoneObject.SetTags(new string[] { "interface", "ui"});

milestoneObject.Save().ContinueWith(objectTask =>
{
     if (objectTask.IsFaulted)
    {
        // some error has occurred
        // refer to the objectTask.Exception.Flatten().InnerException for more details    
    }
    else
    {
        // object updated successfully
    }
});
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "objects": {
          "tags": [
             "interface",
             "ui"
          ]
       }
    }' \
https://api.built.io/v1/classes/milestone/objects/bltf4fbbc94e8c851db
RESPONSE:
{
    "notice": "Object updated successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "name": "First milestone",
        "description": "It may take a long time to get here",
        "project": [
            "bltf4fbbc94e8c361cb"
        ],
        "updated_at": "2015-01-10T09:02:02Z"
        "created_at": "2015-01-10T09:02:02Z"
        "ACL": {
            "can": []
        },
        "tags": [
            "interface",
            "ui"
        ]
    }
}

In the query section, we will see how to query objects for tags.

Multiple

While creating a class, we had come across an option called 'Multiple', which allows a particular field to accepts multiple values. The 'multiple' aspect is an array of field values instead of a single value. Let’s understand this with the help of an example.

Consider we wish to store the details of all the team members working on a particular project. In a traditional way, we would have created a field for each team member, thus decreasing the flexibility. However, with the ‘Multiple’ feature, you can achieve this easily, as it enables you to store multiple values in a single field. Here is how you can achieve this:

// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
 
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *taskClass = [builtApplication classWithUID:@"task"];
BuiltObject *taskObject = [taskClass object];
 
taskObject[@"name"] = @"SessionEntries";
taskObject[@"description"] = @"Task to include session entries";
taskObject[@"assigned_to"] = @[@"John", @"Jack"];
 
[taskObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
 
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var taskClass:BuiltClass = builtApplication.classWithUID("task")
var taskObject:BuiltObject = taskClass.object()
taskObject["name"] = "SessionEntries"
taskObject["description"] = "Task to include session entries"
taskObject["assigned_to"] = ["John", "Jack"]
taskObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend

BuiltObject taskObject = Built.application(context, "blt5d4sample2633b").classWithUid("task").object();
 
ArrayList<String> assignedMember = new ArrayList<String>();
assignedMember.add("John");
assignedMember.add("Jack");
 
taskObject.set("name", "SessionEntries");
taskObject.set("description", "Task to include session entries");
taskObject.set("assigned_to", assignedMember);
 
taskObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
         if(error == null){
              // object is created successfully.
         }else{
              // some error has occurred
              // refer to the 'error' object for more details    
         }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'task' is a uid of a class on Built.io Backend

var Task = Built.App('blt5d4sample2633b').Class('task').Object
var task = Task()

project = project.assign({
    name: 'SessionEntries',
    description: 'Task to include session entries',
    assigned_to: ["John", "Jack"]
})

project
.save()
.then(function(project) {
    // object created successfully
    console.log(project.toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
})
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
var taskObject = Built.App("blt5d4sample2633b").Class("task").Object();

string[] asignedMember =new string[] {
"John",      "Jack"    }  ;
 
taskObject["name"] = "SessionEntries";
taskObject["description"] = "Task to include session entries";
taskObject["assigned_to"] = asignedMember;
 
taskObject.Save().ContinueWith(objectTask =>
{
    if (objectTask.IsFaulted)
    {
        // some error has occurred
        // refer to the objectTask.Exception.Flatten().InnerException for more details    
    }
    else
    {
        // object created successfully
    }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
         "object": {
            "name": "build this great feature!",
            "description": "This could help increase customer interest!",
            "steps": [
                {
                    "name": "first do this",
                    "description": "should be done neatly"
                },
                {
                    "name": "then do this",
                    "description": "perfect"
                }
            ],
            "project": [
                "bltf4fbbc94e8c851db"
            ]
        }
    }' \
https://api.built.io/v1/classes/task/objects
RESPONSE:
{
    "notice": "Object created successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851eb",
        "name": "build this great feature!",
        "description": "This could help increase customer interest!",
        "steps": [
            {
                "name": "first do this",
                "description": "should be done neatly"
            },
            {
                "name": "then do this",
                "description": "perfect"
            }
        ],
        "project": [
            "bltf4fbbc94e8c361cb"
        ],
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Groups fields

Let us consider an example to understand 'Groups field' in detail. The ‘Tasks’ class already contains the following fields: Name, Description, Steps, Assignees, and Project, of which ‘Steps’ is a group field. With the help of the following code, we will create an objects, and set data in the ‘Steps’ field.

// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
 
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *taskClass = [builtApplication classWithUID:@"task"];
BuiltObject *taskObject = [taskClass object];
 
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay|NSCalendarUnitMonth|NSCalendarUnitYear fromDate:[NSDate date]];
components.month += 1;
NSDate *estDate = [[NSCalendar currentCalendar] dateFromComponents:components];
 
// Creating instance of Built.Group to represent the 'details' group
BuiltGroup *details = [BuiltGroup groupWithFieldName:@"details"];
details[@"start_date"] = [NSDate date];
details[@"est_end_date"] = estDate;
details[@"priority"] = @"Medium";
 
taskObject.addGroup(details)
 
[taskObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
 
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var taskClass:BuiltClass = builtApplication.classWithUID("task")
var taskObject:BuiltObject = taskClass.object()
 
var currentDate = NSDate()
var components:NSDateComponents = NSCalendar.currentCalendar().components(NSCalendarUnit.CalendarUnitDay|NSCalendarUnit.CalendarUnitMonth|NSCalendarUnit.CalendarUnitYear, fromDate: NSDate())
components.month += 1
var estDate = NSCalendar.currentCalendar().dateFromComponents(components)
 
// Creating instance of Built.Group to represent the 'details' group
var details:BuiltGroup = BuiltGroup(fieldName:"details")
details["start_date"] = NSDate()
details["est_end_date"] = estDate
details["priority"] = "Medium"
 
taskObject.addGroup(details)
taskObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend

BuiltObject taskObject = Built.application(context, "blt5d4sample2633b").classWithUid("task").object();
 
// creating instance of BuiltGroup to represent the 'details' group
BuiltGroup details = new BuiltGroup("details");
 
Calendar currentDate = Calendar.getInstance();
details.set("start_date", currentDate);
 
currentDate.add(Calendar.MONTH, 1);
details.set("est_end_date", currentDate);
 
details.set("priority", "Medium");
 
taskObject.addGroup(details);
 
taskObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
         if(error == null){
              // object is created successfully.
         }else{
              // some error has occurred
              // refer to the 'error' object for more details    
         }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'task' is a uid of a class on Built.io Backend

var Task = Built.App('blt5d4sample2633b').Class('task').Object
var task = Task()

var estDate = new Date()
estDate.setMonth(CurrentDate.getMonth() + 1)

// Creating instance of Built.Group to represent the 'details' group
var details = Built.Group('details', {
    start_date: new Date(),
    est_end_date: estDate,
    priority: "Medium"
})

task = task.addGroup(details)

console.log("Task object", task)

task
.save()
.then(function(task) {
    console.log(task.toJSON())
})
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
BuiltObject taskObject = Built.App("blt5d4sample2633b").Class("task").Object();
 
// creating instance of BuiltGroup to represent the 'details' group
BuiltGroup details = Built.Group("details", new Dictionary{{"start_date", DateTime.Now}, {"est_end_date", DateTime.Now.Month + 1}, {"priority", "Medium"}});
 
taskObject.AddGroup(details);
 
taskObject.Save().ContinueWith(objectTask =>
{
        if(objectTask.IsFaulted)
        {
                // some error has occurred
                // refer to the objectTask.Exception.Flattern().InnerException for more details    
        }
        else
        {
                // object is created successfully.
        }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
         "object": {
            "name": "build this great feature!",
            "description": "This could help increase customer interest!",
            "steps": [
                {
                    "name": "first do this",
                    "description": "should be done neatly",
                    "complete": true
                }
            ],
            "project": [
                "bltf4fbbc94e8c851db"
            ]
        }
    }' \
https://api.built.io/v1/classes/task/objects
RESPONSE:
{
    "notice": "Object created successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851eb",
        "name": "build this great feature!",
        "description": "This could help increase customer interest!",
        "steps": [
            {
                "name": "first do this",
                "description": "should be done",
                "complete": true
            }
        ],
        "project": [
            "bltf4fbbc94e8c361cb"
        ],
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Please note that ‘Details’ field has not been added to the original schema of the Projects-On-The-Go app. The above code is just an example to understand Groups better.

Groups can also be marked as Multiple, which would enable it to hold an array of JSON objects. Let’s have a look at an example of this, where we create an object in the ‘Tasks’ class having a multiple group field called ‘Steps’.

// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
 
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *taskClass = [builtApplication classWithUID:@"task"];
BuiltObject *taskObject = [taskClass object];
 
BuiltGroupMultiple *steps =  [BuiltGroupMultiple groupMultipleWithFieldName:@"steps"];
 
BuiltGroup *step1 = [BuiltGroup group];
step1[@"name"] =  @"first do this";
step1[@"description"] =  @"should be done neatly";
step1[@"complete"] =  @(YES);
 
BuiltGroup *step2 = [BuiltGroup group];
step2[@"name"] =  @"then do this";
step2[@"description"] =  @"perfect";
step2[@"complete"] =  @(NO);
 
steps.addGroup(step1);
steps.addGroup(step2);
 
taskObject.addGroupMultiple(steps);
 
[taskObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
 
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var taskClass:BuiltClass = builtApplication.classWithUID("task")
var taskObject:BuiltObject = taskClass.object()
 
var steps:BuiltGroupMultiple = BuiltGroupMultiple(fieldName:"steps")
 
var step1:BuiltGroup = BuiltGroup()
step1["name"] =  "first do this"
step1["description"] =  "should be done neatly"
step1["complete"] =  NSNumber(bool: true)
 
var step2:BuiltGroup = BuiltGroup()
step2["name"] =  "then do this"
step2["description"] =  "perfect"
step2["complete"] =  NSNumber(bool: false)
 
steps.addGroup(step1)
steps.addGroup(step2)
 
taskObject.addGroupMultiple(steps)
taskObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend

BuiltObject taskObject = Built.application(context, "blt5d4sample2633b").classWithUid("task").object();
 
// creating instances of BuiltGroup with default constructor to add in BuiltGroupMultiple
BuiltGroup step1 = new BuiltGroup();
step1.set("name", "first do this");
step1.set("description", "should be done neatly");
step1.set("complete", true);
 
BuiltGroup step2 = new BuiltGroup();
step2.set("name", "then do this");
step2.set("description", "perfect");
step2.set("complete", false);
 
//creating instance of BuiltGroupMultiple to represent the 'steps' group
//and adding two level of steps using BuiltGroup instances.
BuiltGroupMultiple steps = new BuiltGroupMultiple("steps");
steps.addGroup(step1);
steps.addGroup(step2);
 
taskObject.addGroupMultiple(steps);
 
taskObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
         if(error == null){
              // object is created successfully.
         }else{
              // some error has occurred
              // refer to the 'error' object for more details    
         }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'task' is a uid of a class on Built.io Backend
var Task = Built.App('blt5d4sample2633b').Class('task').Object
var task = Task()

var steps = Built.GroupMultiple('steps', [{
    name: 'first do this',
    description: 'should be done neatly',
    complete: true
}, {
    name: 'then do this',
    description: 'perfect',
    complete: false
}])

task = task.addGroup(steps)

console.log("Task object", task.toJSON())

task
.save()
.then(function(task) {
    // Object created succesfully
    console.log(task.toJSON())
})
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
BuiltObject taskObject = Built.App("blt5d4sample2633b").Class("task").Object();
 
//creating instance of BuiltGroupMultiple to represent the 'steps' group
//and adding two level of steps using BuiltGroup instances.
var steps = Built.GroupMultiple("steps", new []{new Dictionary {{"name", "first do this"},{"description", "should be done neatly"},{"complete", true}},
new Dictionary {{"name", "then do this"},{"description", "perfect"},{"complete", false}}});

taskObject.AddGroup(steps);
 
taskObject.Save().ContinueWith(objectTask=>
{
        if(objectTask.IsFaulted)
        {
                // some error has occurred
                // refer to the objectTask.Exception.Flattern().InnerException for more details
        }  
        else
        {
                // object is created successfully.
        }
});    
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
         "object": {
            "name": "build this great feature!",
            "description": "This could help increase customer interest!",
            "steps": [
                {
                    "name": "first do this",
                    "description": "should be done neatly",
                    "complete": true
                },
                {
                    "name": "Then do this",
                    "description": "should be done",
                    "complete": true
                }
            ],
            "project": [
                "bltf4fbbc94e8c851db"
            ]
        }
    }' \
https://api.built.io/v1/classes/task/objects
RESPONSE:
{
    "notice": "Object created successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851eb",
        "name": "build this great feature!",
        "description": "This could help increase customer interest!",
        "steps": [
            {
                "name": "first do this",
                "description": "should be done neatly",
                "complete": false
            },
            {
                "name": "Then do this",
                "description": "should be done",
                "complete": true
            }
        ],
        "project": [
            "bltf4fbbc94e8c361cb"
        ],
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Number

Number datatype is used to express numerical data. Numerical data is different from textual data, for example 1 is different from "1". Such numerical data can have atomic operations performed on it, like addition and subtraction.

In the following sample, we'll check out these operators:

// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *personClass = [builtApplication classWithUID:@"person"];
BuiltObject *personObject = [personClass objectWithUID:@"blt3a7323f0ee933fc7"];
// 'age' is a number field in 'person' class  
[personObject incrementKey:@"age" by:@(2)]; 
[personObject decrementKey:@"age" by:@(2)]; 
[personObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var personClass:BuiltClass = builtApplication.classWithUID("person")
var personObject:BuiltObject = personClass.objectWithUID("blt3a7323f0ee933fc7")
// 'age' is a number field in 'person' class  
personObject.incrementKey("age", by: NSNumber(int: 2))
personObject.decrementKey("age", by: NSNumber(int: 2))
personObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'person' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
// setUid will identify the object, and calling save will update it
BuiltObject personObject = builtApplication.classWithUid("person").object("bltf4fbbc94e8c851db");
personObject.increment("age", 2);
personObject.decrement("age", 2);
personObject.save(new BuiltResultCallBack() {
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError builtError) {
        if(builtError == null){
            // object is updated successfully.
        }else{
            // some error has occurred
            // refer to the 'error' object for more details
        }
    }
});

// Alternatively, use the "eventually" format to save it when network is available:
personObject.saveEventually(new BuiltResultCallBack() {
 ...
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'person' is a uid of a class on Built.io Backend
var Person = Built.App('blt5d4sample2633b').Class('person').Object;
var person = Person('blt3a7323f0ee933fc7');
// 'age' is a number field in 'person' class  
person = person.increment('age', 2);
person = person.decrement('age', 2);

person
.save()
.then(function(person) {
    // object updated successfully
    console.log(person.get('age'))
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'person' is a uid of a class on Built.io Backend
// setUid will identify the object, and calling save will update it
BuiltObject personObject = Built.App("blt5d4sample2633b").Class("person").Object().SetUid("bltf4fbbc94e8c851db");
personObject.Increment("age", 2);
personObject.Decrement("age", 2);
personObject.Save().ContinueWith(objectTask =>
{
        if(objectTask.IsFaulted)
        {
                // some error has occurred
                // refer to the objectTask.Exception.Flattern().InnerException object for more details
        }
        else
        {
                // object is updated successfully.
        }
});
// Alternatively, use the "eventually" format to save it when network is available:
personObject.SaveEventually().ContinueWith(objectTask => {
 ...
});
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
        "object": {
            "number_field": {
                "ADD": 2,
                "SUB": 2
            }
        }
    }' \
https://api.built.io/v1/classes/sample/objects/bltf4fbbc94e8c851db
RESPONSE:
{
    "notice": "Object updated successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "number_field": 30,        
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Adding Geo-location information

An object may be tagged with geo-location information. The location is represented by a longitude-latitude pair. Adding location information to an object enables you to geo-query them as well.

Here's how you can add location info to an object.

// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *personClass = [builtApplication classWithUID:@"person"];
 
// 'blt3a732sample33fc7' is uid of an object of person class
BuiltObject *personObject = [personClass objectWithUID:@"blt3a732sample33fc7"];
 
// create a location object
BuiltLocation *locObject = [BuiltLocation locationWithLongitude:72.8 andLatitude:19.4667];
//assigns a location to a person object
[personObject setLocation:locObject];
 
[personObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var personClass:BuiltClass = builtApplication.classWithUID("person")
 
// 'blt3a732sample33fc7' is uid of an object of person class
var personObject:BuiltObject = personClass.objectWithUID("blt3a732sample33fc7")
 
// create a location object
var locObject:BuiltLocation = BuiltLocation(longitude: 72.8, andLatitude: 19.4667)
//assigns a location to a person object
personObject.setLocation(locObject)
 
personObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}

// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'person' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
// setUid will identify the object, and calling save will update it
BuiltObject personObject = builtApplication.classWithUid("person").object("bltf4fbbc94e8c851db");
 
// create a location object
BuiltLocation loc = new BuiltLocation();
 
// method signature is : setLocation(LATITUDE, LONGITUDE);
loc.setLocation(19.4667, 72.8);
personObject.setLocation(loc);
 
personObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError builtError) {
        
        if(builtError == null){
            // object is updated successfully.
        }else{
            // there was an error in updating the object.
            // builtError will contain more details.
        }
    }
 });
 
// Alternatively, use the "eventually" format to save it when network is available:
personObject.saveEventually(new BuiltResultCallBack() {
...
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'person' is a uid of a class on Built.io Backend
var Person = Built.App('blt5d4sample2633b').Class('person').Object;

// 'blt3a732sample33fc7' is uid of an object of person class
var person = Person('blt3a732sample33fc7');

// create location object
// the constructor signature is : Built.Location(LONGITUDE, LATITUDE)
var loc = Built.Location(72.8, 19.4667);

//assigns a location to a person object
person = person.setLocation(loc);

person
.save()
.then(function(person) {
    // object updated successfully
    console.log(person.getLocation())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'person' is a uid of a class on Built.io Backend

// setUid will identify the object, and calling save will update it
BuiltObject personObject = Built.App("blt5d4sample2633b").Class("person").Object().SetUid("bltf4fbbc94e8c851db");

// create a location object
BuiltLocation loc = new BuiltLocation();
 
// method signature is : setLocation(LONGITUDE, LATITUDE);
loc.SetLocation(19.4667M, 72.8M);
personObject.SetLocation(loc);
 
personObject.Save().ContinueWith(objectTask =>
{
        if(objectTask.IsFaulted)
        {
                // there was an error in updating the object.
                // objectTask.Exception.Flattern().InnerException will contain more details.
        }        
        else
        {
                // object is updated successfully.
        }
});

// Alternatively, use the "eventually" format to save it when network is available:
personObject.SaveEventually().ContinueWith(objectTask => {
 ...
});
__loc is an array of [LONGITUDE, LATITUDE]
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
        "object": {
            "__loc": [
                72.8,
                19.4667
            ]
        }
    }' \
https://api.built.io/v1/classes/sample/objects/bltf4fbbc94e8c851db
RESPONSE:
{
    "notice": "Object updated successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "number_field": 30,
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "__loc": [
            72.8,
            19.4667
        ],
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Also, checkout the GeoQuery Playground Demo which will help you form geo-queries.

Querying objects

Built.io Backend has a very comprehensive set of querying capabilities. Let's check out a simple query, where we query for an object based on its uid.

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltQuery *projectQuery = [projectClass query]; 
// 'bltf4fbsample851db' is a uid of an object we wish to search
[projectQuery whereKey:@"uid" equalTo:@"bltf4fbsample851db"];
[projectQuery exec:^(BuiltResponseType type, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectQuery:BuiltQuery = projectClass.query()
// 'bltf4fbsample851db' is a uid of an object we wish to search
projectQuery.whereKey("uid", equalTo: "bltf4fbsample851db")
projectQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication    = Built.application(context, "blt5d4sample2633b");
BuiltQuery projectQuery = builtApplication.classWithUid("project").query();
 
projectQuery.where("uid", "bltf4fbbc94e8c851db");
 
projectQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('project').Query();

// 'bltf4fbsample851db' is a uid of an object we wish to search
query = query.where('uid', 'bltf4fbsample851db');

query
.exec()
.then(function(projects) {
    // projects is an array of SDK objects
    console.log(projects[0].toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var query = Built.App("blt5d4sample2633b").Class("project").Query();
 
// 'bltf4fbsample851db' is a uid of an object we wish to search
query = query.Where("uid", "bltf4fbsample851db");
 
query.Exec().ContinueWith(queryTask =>
{
    if(queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Falttern().InnerException object for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'query={"uid": "bltf4fbbc94e8c851db"}' \
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
   "objects": [
       {
           "published": true,
           "uid": "bltf4fbbc94e8c851db",
           "name": "Super Project #41!",
           "description": "We use this project internally",
           "updated_at": "2015-01-10T09:02:02Z",
           "created_at": "2015-01-10T09:02:02Z",
           "ACL": {
               "can": []
           },
           "tags": []
       }
   ]
}

As you can see, the query is the parameter we use for querying objects, 'query' can be used to issue pretty complex queries, and we'll check them out one by one.

Regex

The Regex query allows you to search the textual values based on a regular expression. The objects with values that match the expression will be returned in the query. Let's take an example where we can add search functionality to the Bugs class. We can query bug names with a pattern that matches /^browser/ (starts with browser) and is case insensitive as follows:

// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltQuery *bugsQuery = [bugsClass query]; 
[bugsQuery whereKey:@"name" matchesRegex:@"^browser" modifiers:@"i"]; 
[bugsQuery exec:^(BuiltResponseType type, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugsQuery:BuiltQuery = bugsClass.query()
bugsQuery.whereKey("name", matchesRegex: "^browser", modifiers: "i")
bugsQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltQuery bugsQuery = builtApplication.classWithUid("bugs").query();
 
bugsQuery.matches("name", "^browser", "i");
 
bugsQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('bugs').Query();

query = query.matches('name', '^browser', 'i');

query
.exec()
.then(function(bugs) {
    // bugs is an array of SDK objects
    console.log(bugs[0].toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
var query = Built.App("blt5d4sample2633b").Class("bugs").Query();
 
query.Matches("name", "^browser", "i");
 query.Exec().ContinueWith(queryTask =>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Falttern().InnerException object for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }

});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'query={
        "name": {
            "$regex": "^browser",
            "$options": "i"
        }
    }' \
https://api.built.io/v1/classes/bugs/objects
RESPONSE:
{
    "objects": [{
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "name": "Does not work in browser: IE",
        "description": "weird issue",
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }]
}

Groups

Querying inside groups means using a "." (period) symbol to delimit the hierarchy. We have a multiple group field in the Task class called steps. Let's query for those objects that have a steps. with the name 'first':

// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *taskClass = [builtApplication classWithUID:@"task"];
BuiltQuery *taskQuery = [taskClass query]; 
 
[taskQuery whereKey:@"steps.name" equalTo:@"first"];
 
[taskQuery exec:^(BuiltResponseType type, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var taskClass:BuiltClass = builtApplication.classWithUID("task")
var taskQuery:BuiltQuery = taskClass.query()
 
taskQuery.whereKey("steps.name", equalTo: "first")
 
taskQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltQuery taskQuery = builtApplication.classWithUid("task").query();
 
taskQuery.where("steps.name", "first");
 
taskQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('task').Query();
query = query.where('steps.name', 'first');

query
.exec()
.then(function(tasks) {
    // tasks is an array of SDK objects
    console.log(tasks[0].toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
var query = Built.App("blt5d4sample2633b").Class("task").Query();
 
query.Where("steps.name", "first");
 
query.Exec().ContinueWith(queryTask =>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Falttern().InnerException object for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }

});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'query={
        "steps.name": "first"
    }' \
https://api.built.io/v1/classes/task/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Super tasks",
            "description": "the task desc",
            "steps": [
                {
                    "name": "first",
                    "description": "first",
                    "complete": false
                },
                {
                    "name": "second",
                    "description": "second",
                    "complete": true
                }
            ],
            "updated_at": "2015-01-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

Logical operators: or, and

You can use or to combine two or more queries. If any of these queries are satisfied for an object, the object is returned.

Similarly, and can be used to combine two or more queries. If all of those queries are satisfied for an object, the object is returned.

The and query is implicit for multiple chained conditions, which makes it redundant for most queries. However, and is useful in some situations, such as when you want to combine two or queries.

An example of a complex query for the Task class is, where the name /or/ description can be "mytask" /and/ the name /or/ description of a step in the task can be "first". The following expression may make this clear:

(((name||description) == "mytask") && ((steps.name||steps.description) == "first"))

Now, let's look at how to achieve this complex query:

// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *taskClass = [builtApplication classWithUID:@"task"];
 
BuiltQuery *query1 = [taskClass query]; 
[query1 whereKey:@"name" equalTo:@"mytask"];
 
BuiltQuery *query2 = [taskClass query]; 
[query2 whereKey:@"description" equalTo:@"mytask"];
 
BuiltQuery *query3 = [taskClass query]; 
[query3 orWithSubqueries:@[query1, query2]];
 
BuiltQuery *query4 = [taskClass query]; 
[query4 whereKey:@"steps.name" equalTo:@"first"];
 
BuiltQuery *query5 = [taskClass query]; 
[query5 whereKey:@"steps.description" equalTo:@"first"];
 
BuiltQuery *query6 = [taskClass query]; 
[query6 orWithSubqueries:@[query4, query5]];
 
BuiltQuery *query7 = [taskClass query]; 
[query7 andWithSubqueries:@[query3, query6]];
 
[query7 exec:^(BuiltResponseType type, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var taskClass:BuiltClass = builtApplication.classWithUID("task")
var query1:BuiltQuery = taskClass.query()
query1.whereKey("name", equalTo: "mytask")
 
var query2:BuiltQuery = taskClass.query()
query2.whereKey("description", equalTo: "mytask")
 
var query3:BuiltQuery = taskClass.query()
query3.orWithSubqueries([query1, query2])
 
var query4:BuiltQuery = taskClass.query()
query4.whereKey("steps.name", equalTo: "first")
 
var query5:BuiltQuery = taskClass.query()
query5.whereKey("steps.description", equalTo: "first")
 
var query6:BuiltQuery = taskClass.query()
query6.orWithSubqueries([query4, query5])
 
var query7:BuiltQuery = taskClass.query()
query7.andWithSubqueries([query3, query6])
 
query7.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend

BuiltQuery query1 = Built.application(context, "blt5d4sample2633b").classWithUid("task").Query();
query1.where("name", "mytask");
 
BuiltQuery query2 = Built.application(context, "blt5d4sample2633b").classWithUid("task").Query();
query2.where("description", "mytask");
 
BuiltQuery query3 = Built.application(context, "blt5d4sample2633b").classWithUid("task").Query();
 
ArrayList orQuery1 = new ArrayList();
orQuery1.add(query1);
orQuery1.add(query2);
query3.or(orQuery1);
 
BuiltQuery query4 = Built.application(context, "blt5d4sample2633b").classWithUid("task").Query();
query4.where("steps.name", "first");
 
BuiltQuery query5 = Built.application(context, "blt5d4sample2633b").classWithUid("task").Query();
query5.where("steps.description", "first");
 
BuiltQuery query6 = Built.application(context, "blt5d4sample2633b").classWithUid("task").Query();
 
ArrayList orQuery2 = new ArrayList();
orQuery2.add(query4);
orQuery2.add(query5);
query6.or(orQuery2);
 
BuiltQuery query7 = Built.application(context, "blt5d4sample2633b").classWithUid("task").Query();
 
ArrayList andQuery = new ArrayList();
andQuery.add(query3);
andQuery.add(query6);
query7.and(andQuery);
 
query7.exec(new QueryResultsCallBack() {
@Override
public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        if(error == null){
            // the queryResultObject will contain the objects of the class
            List<BuiltObject> objects = queryResultObject.getResultObjects();
        }else{
            // query failed
            // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
var q1 = Built.App('blt5d4sample2633b').Class('task').Query();
q1 = q1.where('name', 'mytask');

var q2 = Built.App('blt5d4sample2633b').Class('task').Query();
q2 = q2.where('description', 'mytask');

var q3 = Built.App('blt5d4sample2633b').Class('task').Query();
q3 = q3.or([q1, q2]);

var q4 = Built.App('blt5d4sample2633b').Class('task').Query();
q4 = q4.where('steps.name', 'first');

var q5 = Built.App('blt5d4sample2633b').Class('task').Query();
q5 = q5.where('steps.description', 'first');

var q6 = Built.App('blt5d4sample2633b').Class('task').Query();
q6 = q6.or([q4, q5]);

var q7 = Built.App('blt5d4sample2633b').Class('task').Query();
q7 = q7.and([q3, q6]);

q7
.exec()
.then(function(tasks) {
    // data is an array of SDK objects
    console.log(tasks[0].toJSON())
}, function(error) {
    // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'task' is a uid of a class on Built.io Backend
BuiltQuery query1 = Built.App("blt5d4sample2633b").Class("task").Query();
query1.Where("name", "mytask");
 
BuiltQuery query2 = Built.App("blt5d4sample2633b").Class("task").Query();
query2.Where("description", "mytask");
 
BuiltQuery query3 = Built.App("blt5d4sample2633b").Class("task").Query();
 
List orQuery1 = new List();
orQuery1.Add(query1);
orQuery1.Add(query2);
 
query3.Or(orQuery1);
 
 
BuiltQuery query4 = Built.App("blt5d4sample2633b").Class("task").Query();
query4.Where("steps.name", "first");
 
BuiltQuery query5 = Built.App("blt5d4sample2633b").Class("task").Query();
query5.Where("steps.description", "first");
 
BuiltQuery query6 = Built.App("blt5d4sample2633b").Class("task").Query();
 
List orQuery2 = new List();
orQuery2.Add(query4);
orQuery2.Add(query5);
 
query6.Or(orQuery2);
 
BuiltQuery query7 = Built.App("blt5d4sample2633b").Class("task").Query();
 
List andQuery = new List();
andQuery.Add(query3);
andQuery.Add(query6);
 
query7.And(andQuery);
 
query7.Exec().ContinueWith(queryTask=>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Falttern().InnerException object for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }

});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'query={
         "$and": [
            {
                "$or": [
                    {
                        "name": "mytask"
                    },
                    {
                        "description": "mytask"
                    }
                ]
            },
            {
                "$or": [
                    {
                        "steps.name": "first"
                    },
                    {
                        "steps.description": "first"
                    }
                ]
            }
        ]
    }' \
https://api.built.io/v1/classes/task/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "mytask",
            "description": "the task desc",
            "steps": [
                {
                    "name": "first",
                    "description": "first",
                    "complete": false
                },
                {
                    "name": "second",
                    "description": "second",
                    "complete": true
                }
            ],
            "updated_at": "2015-01-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

Range Operators: lt, lte, gt, gte

The Range operators are: 'Less Than', 'Less Than or Equals', 'Greater Than', and 'Greater Than or Equals'. These allow you to specify ranges for the Number and ISODate datatypes. When a range is specified for a datatype, all objects matching that range are retrieved.

// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltQuery *bugsQuery = [bugsClass query]; 
 
[bugsQuery whereKey:@"due_date" lessThanOrEqualTo:@"2013-06-25T00:00:00+05:30"]; 
[bugsQuery whereKey:@"due_date" greaterThanOrEqualTo:@"2013-06-20T00:00:00+05:30"];
 
[bugsQuery exec:^(BuiltResponseType type, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugsQuery:BuiltQuery = bugsClass.query()
 
bugsQuery.whereKey("due_date", lessThanOrEqualTo: "2013-06-25T00:00:00+05:30")
bugsQuery.whereKey("due_date", greaterThanOrEqualTo: "2013-06-25T00:00:00+05:30")
 
bugsQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltQuery bugsQuery = builtApplication.classWithUid("bugs").query();
 
bugsQuery.lessThanOrEqualTo("due_date", "2013-06-25T00:00:00+05:30");
bugsQuery.greaterThanOrEqualTo("due_date", "2013-06-20T00:00:00+05:30");
 
bugsQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('bugs').Query();

query = query.lessThanOrEqualTo('due_date', '2013-06-25T00:00:00+05:30');
query = query.greaterThanOrEqualTo('due_date', '2013-06-20T00:00:00+05:30');

query
.exec()
.then(function(bugs) {
    // data is an array of SDK objects
}, function(error) {
    // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
BuiltQuery bugsQuery = Built.App("blt5d4sample2633b").Class("bugs").Query();
  
bugsQuery.LessThanOrEqualTo("due_date", "2013-06-25T00:00:00+05:30");
bugsQuery.GreaterThanOrEqualTo("due_date", "2013-06-20T00:00:00+05:30");
 
bugsQuery.Exec().ContinueWith(queryTask =>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Falttern().InnerException object for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'query={
      "due_date": {
          "$lte": "2015-01-10T09:02:02+05:30",
          "$gte": "2015-02-20T00:00:00+05:30"
      }
  }' \
https://api.built.io/v1/classes/bugs/objects
RESPONSE:
  {
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Does not work in browser: IE",
            "description": "weird issue",
            "updated_at": "2013-02-19T09:02:02Z",
            "created_at": "2013-01-01T09:02:02Z",
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

Multiples and Equality: in, nin, ne, exists

Multiple fields are arrays, and you can check for inclusion or exclusion of items in them. The 'In' operator checks for inclusion, whereas the 'Not In' operator checks for exclusion. Note that they are not limited to multiple values, you can also search single values for inclusion or exclusion in a provided set.

The 'Not Equals' operator checks for records which do NOT have the specified field value.

The 'Exists' operator checks for existence of a value for that field. If a value is set for the field, the object will be returned.

Let's check out an example for these operators. We'll query for bugs with severity of either 'Show Stopper' or 'Critical', while excluding those bugs which are of status 'Closed'. Also, let's only retrieve those bugs for which a Due Date is provided:

// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltQuery *bugsQuery = [bugsClass query]; 
 
[bugsQuery whereKey:@"severity" containedIn:@[@"Show Stopper", @"Critical"]]; 
[bugsQuery whereKey:@"status" notEqualTo:@"Closed"];
[bugsQuery whereKeyExists:@"due_date"];
   
[bugsQuery exec:^(BuiltResponseType type, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugsQuery:BuiltQuery = bugsClass.query()
 
bugsQuery.whereKey("severity", containedIn: ["Show Stopper","Critical"])
bugsQuery.whereKey("status", notEqualTo: "Closed")
bugsQuery.whereKeyExists("status")
 
bugsQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltQuery bugsQuery = builtApplication.classWithUid("bugs").query();
 
bugsQuery.containedIn("severity", new String[] {"Show Stopper", "Critical"});
bugsQuery.notEqualTo("status", "Closed");
bugsQuery.exists("due_date");
 
bugsQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('bugs').Query();

query = query.containedIn('severity', ['Show Stopper', 'Critical']);
query = query.notEqualTo('status', 'Closed');
query = query.exists('due_date');

query
.exec()
.then(function(bugs) {
    // bugs is an array of SDK objects
    console.log(bugs[0].toJSON())
}, function(error) {
    // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
BuiltQuery bugsQuery = Built.App("blt5d4sample2633b").Class("bugs").Query();
 
bugsQuery.ContainedIn("severity", new String[] {"Show Stopper", "Critical"});
bugsQuery.NotEqualTo("status", "Closed");
bugsQuery.Exists("due_date");
 
bugsQuery.Exec().ContinueWith(queryTask =>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Falttern().InnerException object for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'query={
        "severity": {
            "$in": [
                "Show Stopper",
                "Critical"
            ]
        },
        "status": {
            "$ne": "Closed"
        },
        "due_date": {
            "$exists": true
        }
    }' \
https://api.built.io/v1/classes/bugs/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Does not work in browser: IE",
            "description": "weird issue",
            "severity": "Show Stopper",
            "status": "Open",
            "updated_at": "2015-01-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "due_date": "2015-03-10T09:02:02+05:30",
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

References: in_query, nin_query, select, dont_select, include

You can also retrieve objects by querying the references in them. There are specific operators to let you do that. Let's take a look at each one of them:

The 'In Query' operator lets you query a reference, and retrieve objects which satisfy that query. Conversely, 'Not In Query' lets you query a reference and retrieve objects that don't match the query. With our project, we may need to query for bugs/milestones/tasks in a project which has a certain name. Here's how you would do that with 'In Query' to retrieve bugs which belong to a project with name 'Super Project #41!':

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltQuery *projectQuery = [projectClass query]; 
 
[projectQuery whereKey:@"name" equalTo:@"Super Project #41!"];
 
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltQuery *bugsQuery = [bugsClass query]; 
 
[bugsQuery inQuery:projectQuery forKey:@"project"];
 
[bugsQuery exec:^(BuiltResponseType type, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectQuery:BuiltQuery = projectClass.query()
 
projectQuery.whereKey("name", equalTo: "Super Project #41")
 
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugsQuery:BuiltQuery = bugsClass.query()
 
bugsQuery.inQuery(projectQuery, forKey:"project")
 
bugsQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' and 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltQuery bugsQuery    = builtApplication.classWithUid("bugs").query();
BuiltQuery projectQuery = builtApplication.classWithUid("project").query();
 
projectQuery.where("name", "Super Project #41!");
 
bugsQuery.inQuery("project", projectQuery);
 
bugsQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns an 'Object' constructor
// 'project' is a uid of a class on Built.io Backend
var Milestone = Built.App('blt5d4sample2633b').Class('milestone').Object;
var milestone = Milestone();

// Query which would be applied on Address class
var whereQuery = query.where('name', 'Super Project #41');
var inQuery = query.inQuery('project', whereQuery);

inQuery
.exec()
.then(function(milestones) {
    //miltestones is an array of SDK objects
    console.log(milestones[0].toJSON())
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' and 'project' is a uid of a class on Built.io Backend
BuiltQuery bugsQuery = Built.App("blt5d4sample2633b").Class("bugs").Query();

BuiltQuery projectQuery = Built.App("blt5d4sample2633b").Class("project").Query();
 
projectQuery.Where("name", "Super Project #41!");
 
bugsQuery.InQuery("project", projectQuery);
 
bugsQuery.Exec().ContinueWith(queryTask =>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Falttern().InnerException object for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'query={
        "project": {
            "$in_query": {
                "name": "Super Project #41!"
            }
        }
    }' \
https://api.built.io/v1/classes/bugs/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Does not work in browser: IE",
            "description": "weird issue",
            "updated_at": "2015-01-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "project": [
                "bltf4fbbc94e8c851db"
            ],
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

The 'Select' operator lets you issue arbitrary queries on classes, based on field data that may or may not be actual references.

In our Bugs class, we have a reference to the Project class. If, instead of the reference, we had a text field called 'project' containing the project name, how would we query the Project class and retrieve bugs based on the results of the query? This is where 'Select' comes in handy. Often there is a need for human readable attributes such as a name, instead of a reference such as a uid. Let's look at this example where we retrieve bugs whose project has the description: 'test':

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltQuery *selectQuery = [projectClass query]; 
 
[selectQuery whereKey:@"description" equalTo:@"test"];
 
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltQuery *bugsQuery = [bugsClass query]; 
 
[bugsQuery whereKey:@"project" equalToResultOfSelectQuery:selectQuery forKey:@"name"];
 
[bugsQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
 
var selectQuery:BuiltQuery = projectClass.query()
selectQuery.whereKey("description", equalTo: "test")
 
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugsQuery:BuiltQuery = bugsClass.query()
bugsQuery.whereKey("project", equalToResultOfDontSelectQuery:selectQuery, forKey: "name")
 
bugsQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' and 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltQuery bugsQuery   = builtApplication.classWithUid("bugs").query();
BuiltQuery selectQuery = builtApplication.classWithUid("project").query();
 
selectQuery.where("description", "test");
 
bugsQuery.select("project", selectQuery, "name");
 
bugsQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var app = Built.App('blt5d4sample2633b');

// 'project' is a uid of a class on Built.io Backend
var select_query = app.Class('project').Query();

select_query = select_query.where('description', 'test');

// 'bugs' is a uid of a class on Built.io Backend
var bugsQuery = app.Class('bugs').Query();

query = bugsQuery.select('project', select_query, 'name');

query
.exec()
.then(function(bugs) {
    // bugs is an array of SDK objects
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' and 'project' is a uid of a class on Built.io Backend
BuiltQuery bugsQuery = Built.App("blt5d4sample2633b").Class("bugs").Query();

BuiltQuery selectQuery = Built.App("blt5d4sample2633b").Class("project").Query();

selectQuery.Where("description", "test");

bugsQuery.Select("project", selectQuery, "name");

bugsQuery.Exec().ContinueWith(queryTask =>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Falttern().InnerException object for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'query={
    "project": {
        "$select": {
            "query": {
                "description": "test"
            },
            "class_uid": "project",
            "key": "name"
        }
    }
}' \
https://api.built.io/v1/classes/bugs/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Does not work in browser: IE",
            "description": "weird issue",
            "updated_at": "2015-01-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "project": "Super Project #49",
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

Similarly, you may use 'Don't Select' for getting a negation of the select query.

The 'include' parameter includes the referenced objects in the resultset itself. You can use this to avoid two queries, one for the main query and one for getting the referenced objects. 'include' also works with nested references, simply delimit them with a period (".").

Let's take an example where you query for comments. You want to retrieve the referred bug, as well as the project object of the bug: Comment -> Bug -> Project.

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
// 'comment' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *commentClass = [builtApplication classWithUID:@"comment"];
BuiltQuery *commentQuery = [commentClass query]; 
 
[commentQuery includeReference:@[@"for_bug.project"]];
 
[commentQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
 
      // we retrieve the first comment
      BuiltObject *first_comment = (BuiltObject *)[[result getResult] objectAtIndex:0];
     
      // we get all the bugs referenced
      NSArray *bugs = [first_comment getAllObjectsForKey:@"for_bug" withClassUID:@"bugs"];
     
      // we retrieve the first bug
      BuiltObject *bug = [bugs objectAtIndex:0];
     
      // we get all of thre referenced projects in that bug
      NSArray *projects = [bug getAllObjectsForKey:@"project" withClassUID:@"project"];
     
      // we get the project object that the bug belongs to
      BuiltObject *project = [projects objectAtIndex:0];
 
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
// 'bugs' is a uid of a class on Built.io Backend
// 'comment' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var commentClass:BuiltClass = builtApplication.classWithUID("comment")
var commentQuery:BuiltQuery = commentClass.query()
 
commentQuery.includeReference(["for_bug.project"])
 
commentQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
 
      //     we retrieve the first comment
      var first_comment = result.getResult().objectAtIndex(0) as BuiltObject
     
      //     we get all the bugs referenced
      var bugs:NSArray = first_comment.getAllObjectsForKey("for_bug", withClassUID: "bugs")
     
      //     we retrieve the first bug
      var bug:BuiltObject = bugs.objectAtIndex(0) as BuiltObject
     
      //     we get all of thre referenced projects in that bug
      var projects:NSArray = bug.getAllObjectsForKey("project", withClassUID: "project")
     
      //     we get the project object that the bug belongs to
      var project:BuiltObject = projects.objectAtIndex(0) as BuiltObject
 
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'comment' is a uid of a class on Built.io Backend

BuiltApplication builtApplication    = Built.application(context, "blt5d4sample2633b");
BuiltQuery commentQuery = builtApplication.classWithUid("comment").query();
 
ArrayList<String> list = new ArrayList<String>();
list.add("for_bug.project");
 
commentQuery.include(list);
 
commentQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError builtError) {
 
             if(builtError == null){
               BuiltObject firstComment = queryResultObject.resultObjects.get(0);
 
                // we retrieve all the referenced bugs, 
                //the second parameter to "getAllObjects" is the class uid
                ArrayList<BuiltObject> bugs = firstComment.getAllObjects("for_bug", "bugs");
 
                // we retrieve the first bug
                BuiltObject bug = bugs.get(0);
 
                // we get all the referenced projects from the bug
                ArrayList<BuiltObject> projects = bug.getAllObjects("project", "project");
 
                // we get the project object that the bug belongs to (the first one)
                BuiltObject project = projects.get(0);
 
            }else{
               // query failed
               // refer to the 'error' object for more details
            }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var App = Built.App('blt5d4sample2633b')

// App.Class returns a Class Constructor
var Class = App.Class;

// Class('bugs').Object returns a Object constructor of 'bugs' class
var Bug = Class('bugs').Object

// Class('project').Object returns a Object constructor of 'project' class
var Project = Class('project').Object

// 'comment' is a uid of a class on Built.io Backend
var myQuery = App.Class('comment').Query();

myQuery.include(['for_bug.project']);

myQuery
.exec()
.then(function(comments) {
    var firstComment = comments[0];
    // we retrieve all the referenced bugs
    var bugs = firstComment.get('for_bug').map(function(bug) {
        return Bug(bug)
    });
    // we retrieve the first bug
    var bug = bugs[0];
    // we retrieve all the referenced projects
    var projects = bug.get('project').map(function(project) {
        return new Project(project)
    });
    // we get the project object that the bug belongs to
    console.log(project[0].toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'comment' is a uid of a class on Built.io Backend
BuiltQuery commentQuery = Built.App("blt5d4sample2633b").Class("comment").Query();


List list = new List();
list.Add("for_bug.project");

commentQuery.Include(list);

commentQuery.Exec().ContinueWith(queryTask =>
{
        if(queryTask.IsFaulted)
        {
                //query failed
                // refer to the queryTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                //the queryTask.Result will contain the objects of the class

                BuiltObject[] objects = queryTask.Result.Result;

                Dictionary firstComment = objects[0].Object;

                // we retrieve all the referenced bugs,
                object[] bugs = (object[])firstComment["for_bug"];

                // we retrieve the first bug
                Dictionary bug= (Dictionary)bugs[0];

                // we get all the referenced projects from the bug
                object[] projects = (object[])bug["project"];

                // we get the project object that the bug belongs to (the first one)
                Dictionary project = (Dictionary)projects[0];
        }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'include[]=for_bug.project' \
https://api.built.io/v1/classes/comment/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "content": "This is a really good bug",
            "updated_at": "2013-06-19T09:02:02Z",
            "created_at": "2013-06-19T09:02:02Z",
            "for_bug": [
                {
                    "published": true,
                    "uid": "bltf4fbbc94e8c851db",
                    "name": "Does not work in browser: IE",
                    "description": "weird issue",
                    "severity": "Show Stopper",
                    "status": "Open",
                    "updated_at": "2015-02-10T09:02:02Z",
                    "created_at": "2015-01-10T09:02:02Z",
                    "due_date": "2015-06-10T09:02:02Z+05:30",
                    "ACL": {
                        "can": []
                    },
                    "tags": [],
                    "project": [
                        {
                            "published": true,
                            "uid": "bltf4fbbc94e8c851db",
                            "name": "Super Project #41!",
                            "description": "We use this project internally",
                            "updated_at": "2015-01-20T19:10:02Z",
                            "created_at": "2015-01-10T09:02:02Z",
                            "ACL": {
                                "can": []
                            },
                            "tags": []
                        }
                    ]
                }
            ],
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

Draft Objects

Objects that are saved as draft are not returned in regular queries. By passing the includeDrafts option, you can include draft objects in the result set. The onlyDrafts option allows you to fetch only the unpublished items. In the following sample, we'll take a look at each one of them:

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltQuery *projectQuery = [projectClass query];
 
// includeDrafts will get draft objects along with regular ones
[projectQuery includeDrafts];
 
// onlyDrafts will get only the draft objects
[projectQuery onlyDrafts];
 
[projectQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectQuery:BuiltQuery = projectClass.query()
 
// includeDrafts will get draft objects along with regular ones
projectQuery.includeDrafts()
 
// onlyDrafts will get only the draft objects
projectQuery.onlyDrafts()
 
projectQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltQuery projectQuery = builtApplication.classWithUid("project").query();
 
// includeDrafts will get draft objects along with regular ones
projectQuery.includeDrafts();
 
// onlyDrafts will get only the draft objects
projectQuery.onlyDrafts();
 
projectQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend

var query = Built.App('blt5d4sample2633b').Class('project').Query();
// includeDrafts will get draft objects along with regular ones
query = query.includeDrafts();

query
.exec()
.then(function(projects) {
    // projects is an array of SDK objects
    console.log(projects[0].toJSON())
}, function(error) {
    // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltQuery projectQuery = Built.App("blt5d4sample2633b").Class("project").Query();
// includeDrafts will get draft objects along with regular ones
projectQuery.IncludeDrafts();
 
// onlyDrafts will get only the draft objects
projectQuery.OnlyDrafts();
 
projectQuery.Exec().ContinueWith(queryTask =>
{
    if(queryTask.IsFaulted)
        {
                // query failed
        // refer to the queryTask.Exception.Flatten().InnerException for more details
    }
        else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'include_unpublished=true' \
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
    "objects": [
        {
            "published": false,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Aardvark",
            "description": "First word in the dictionary",
            "updated_at": "2015-02-10T09:02:02Z",
            "created_at": "2015-02-10T09:02:02Z",
            "ACL": {
                "can": [
                ]
            },
            "tags": [
            ]
        },
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Super Project #41!",
            "description": "We use this project internally",
            "updated_at": "2015-02-10T09:02:02Z",
            "created_at": "2015-02-10T09:02:02Z",
            "ACL": {
                "can": [
                ]
            },
            "tags": [
            ]
        },
        ...
    ]
}
// retrieving only the draft items
curl -i -X GET \
-H "application_api_key: api_key" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'include_unpublished=true&query={"published": false}' \
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
    "objects": [
        {
            "published": false,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Aardvark",
            "description": "First word in the dictionary",
            "updated_at": "2013-06-19T09:02:02Z",
            "created_at": "2013-06-19T09:02:02Z",
            "ACL": {
                "can": [
                ]
            },
            "tags": [
            ]
        },
        {
            "published": false,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Some Project",
            "description": "Random Project",
            "updated_at": "2013-06-19T09:02:02Z",
            "created_at": "2013-06-19T09:02:02Z",
            "ACL": {
                "can": [
                ]
            },
            "tags": [
            ]
        },
        ...
    ]
}

Tags

Objects can be queried for one or more tags. Specify tags to search for, and the query will retreive those objects that have the tag attached. Here's how to search for project objects with the tag, 'ui':

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
 
//Obj-C
 
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltQuery *projectQuery = [projectClass query]; 
 
[projectQuery whereTagsEqualTo:@[@"ui"]];
 
[projectQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectQuery:BuiltQuery = projectClass.query()
 
projectQuery.whereTagsEqualTo(["ui"])
 
projectQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltQuery projectQuery = builtApplication.classWithUid("project").query();
 
projectQuery.whereTags(new String[] {"ui"});
 
projectQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
//getTags() not available

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('project').Query();

query.containedIn('tags', ['ui'])

myQuery
.exec()
.then(function(projects) {
    console.log(projects[0].toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltQuery projectQuery = Built.App("blt5d4sample2633b").Class("project").Query();
 
projectQuery.WhereTags(new String[] {"ui"});
 
projectQuery.Exec().ContinueWith(queryTask=>
{
    if(queryTask.IsFaulted)
{
        // query failed
       // refer to the queryTask.Exception.Flatten().InnerException for more details
    }
else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'tags=ui' \
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
    "objects": [
        {
            "published": false,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Aardvark",
            "description": "First word in the dictionary",
            "updated_at": "2015-02-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "ACL": {
                "can": [
                ]
            },
            "tags": [
                'ui'
            ]
        },
        ...
    ]
}

Pagination

You can use pagination to display large amounts of data. The following operators control the number of objects returned in a query, and thus enable pagination.

  • skip
    Skip n number of objects
  • limit
    Limit to n number of objects
  • include_count, count
    Gives count of the number of objects

Here's how you can achieve pagination using these operators. Suppose that you want to display 50 objects per page:

  • Retrieve the first 50 objects with limit=50. You can get the total count in the same call with include_count, then divide the total count by 50 to get the number of pages to be displayed.
  • Retrieve the next 50 objects: use skip=50 to skip over the first 50, and limit=50 to limit the objects retrieved to the next 50..
  • Retrieve the next batch of 50 objects with skip=100, and again use limit=50 to limit the retrieval to 50 again.
  • and so on for the number of pages to be displayed.

The following is an example where we query for bugs. We skip the first 50 objects and limit the objects we retrieve to 100. We also include the count as well.

// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltQuery *bugsQuery = [bugsClass query]; 
 
[bugsQuery skipObjects: @(50)];
[bugsQuery limitObjects: @(100)];
 
[bugsQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugsQuery:BuiltQuery = bugsClass.query()
 
bugsQuery.skipObjects(NSNumber(integer: 50))
bugsQuery.limitObjects(NSNumber(integer: 100))
 
bugsQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltQuery bugsQuery = builtApplication.classWithUid("bugs").query();
 
bugsQuery.skip(50);
bugsQuery.limit(100);
 
bugsQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('bugs').Query();
query = query.skip(50).limit(100);

query.exec()
.then(function(bugs) {
    // bugs is an array of SDK objects
    console.log(bugs[0].toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is a uid of a class on Built.io Backend
BuiltQuery bugsQuery = Built.App("blt5d4sample2633b").Class("bugs").Query();

 
bugsQuery.Skip(50);
bugsQuery.Limit(100);
 
bugsQuery.Exec().ContinueWith(queryTask =>
{
    if(queryTask.IsFaulted)
        {
        // query failed
       // refer to the queryTask.Exception.Flatten().InnerException for more details
    }
        else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'skip=50&limit=100' \
https://api.built.io/v1/classes/bugs/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Does not work in browser: IE",
            "description": "weird issue",
            "severity": "Show Stopper",
            "status": "Open",
            "updated_at": "2015-02-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "due_date": "2013-06-20T00:00:00+05:30",
            "ACL": {
                "can": [
                ]
            },
            "tags": [
            ]
        },
        ...
    ]
}

Sorting

Sorting is accomplished by the asc and desc operator (ascending and descending). The operators expect the name of the field as a parameter on which the sorting is to be carried out.

Sorting is useful when you wish to display your data in a particular order. For example, sort on the created_at field to get objects in the order in which they were created. asc sorts in the ascending order, while desc sorts in the descending order.

The ISODate datatype also allows sorting. However, the data in that field must be an uniform date, time, or datetime throughout the dataset. That is, if you choose to store only the date in an ISODate field, then only the date field must be stored. The following is allowed for a sort:

  • 2013-06-26
  • 2013-06-27
  • 2013-06-28
  • 2013-06-29

But the following is not allowed for a sort:

  • 2013-06-26
  • 2013-06-27T01:00:00+01:00
  • 2013-06-28
  • 2013-06-29

In the following example, we sort projects by the "name" field in ascending alphabetical order:

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltQuery *projectQuery = [projectClass query]; 
 
[projectQuery orderByAscending:@"name"];
 
[projectQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectQuery:BuiltQuery = projectClass.query()
 
projectQuery.orderByAscending("name")
 
projectQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication     = Built.application(context, "blt5d4sample2633b");
BuiltQuery projectQuery     = builtApplication.classWithUid("project").query();
 
projectQuery.ascending("name");
 
projectQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('project').Query();

query = query.ascending('name');

query
.exec()
.then(function(projects) {
    // projects is an array of SDK objects
}, function(error) {
    // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltQuery projectQuery = Built.App("blt5d4sample2633b").Class("project").Query();
 
projectQuery.Ascending("name");
 
projectQuery.Exec().ContinueWith(queryTask=>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Flatten().InnerException for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'asc=name' \
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Aardvark",
            "description": "First word in the dictionary",
            "updated_at": "2015-02-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "ACL": {
                "can": [
                ]
            },
            "tags": [
            ]
        },
        {
            "published": true,
            "uid": "bltf5fbbc94e8c789cb",
            "name": "Super Project #41!",
            "description": "We use this project internally",
            "updated_at": "2015-02-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "ACL": {
                "can": [
                ]
            },
            "tags": [
            ]
        },
        ...
    ]
}

Retrieve limited fields: only, except

You can limit the fields that are returned in a query. This is useful for when you want to retrieve large datasets, and you need to limit the amount of data that is returned. The operators to do this are only, to return only the fields specified, and except to retrieve all fields except the fields that are specified. In the following query sample, we retrieve all projects, but return only the "name" parameter for those projects:

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltQuery *projectQuery = [projectClass query]; 
 
[projectQuery includeOnlyFields:[NSArray arrayWithObjects: @"name", nil]];
 
[projectQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectQuery:BuiltQuery = projectClass.query()
 
projectQuery.includeOnlyFields(["name"])
 
projectQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltQuery projectQuery = builtApplication.classWithUid("project").query();
 
ArrayList<String> list = new ArrayList<String>();
list.add("name");
 
projectQuery.only(list);
 
projectQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('project').Query();

query = query.only(['name']);

query
.exec()
.then(function(projects) {
    // projects is an array of SDK objects
}, function(error) {
    // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltQuery projectQuery = Built.App("blt5d4sample2633b").Class("project").Query();
 
List<String> list = new List<String>();
list.Add("name");
 
projectQuery.Only(list);
 
projectQuery.Exec().ContinueWith(queryTask=>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Flatten().InnerException for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'only[BASE][]=name' \
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
    "objects": [
        {
            "uid": "bltf4fbbc94e8c851db",
            "name": "Aardvark",
            "ACL": {
                "can": [
                ]
            }
        },
        {
            "uid": "bltf4fbbc94e8c851db",
            "name": "Super Project #41!",
            "ACL": {
                "can": [
                ]
            }
        },
        ...
    ]
}

You may similarly use except for excluding fields.

Geo-location queries

Objects can also be queried for their location. There are two types of queries, near and within.

The near query accepts a coordinate and a radius. A coordinate (represented as BuiltLocation in the SDKs) is just a pair of longitude and latitude. The radius is provided in meters. The query will return all objects near the coordinate by the given radius. The following sample will query for all objects within 1000 meters of a given coordinate:

// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *personClass = [builtApplication classWithUID:@"person"];
BuiltQuery *personQuery = [personClass query]; 
 
// create a location object
BuiltLocation *locationObj = [BuiltLocation locationWithLongitude:72.8 andLatitude:19.4667]; 
[personQuery nearLocation:locationObj withRadius:1000];
 
[personQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var personClass:BuiltClass = builtApplication.classWithUID("person")
var personQuery:BuiltQuery = personClass.query()
 
// create a location object
var locationObj:BuiltLocation = BuiltLocation(longitude: 72.8, andLatitude: 19.4667) 
personQuery.nearLocation(locationObj, withRadius: 1000)
 
personQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend

BuiltApplication builtApplication   = Built.application(context, "blt5d4sample2633b");
BuiltQuery personQuery = builtApplication.classWithUid("person").query();
 
// create a location object
BuiltLocation loc = new BuiltLocation();
 
// method signature is : setLocation(LATITUDE, LONGITUDE);
loc.setLocation(19.4667, 72.8);
 
personQuery.nearLocation(loc, 1000);
 
personQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
var query = Built.App('blt5d4sample2633b').Class('person').Query();

// create location object
// the constructor signature is : Built.Location(LONGITUDE, LATITUDE)
var loc = Built.Location(72.8, 19.4667);

query = query.nearLocation(loc, 1000);

query
.exec()
.then(function(persons) {
    // persons is an array of SDK objects
    console.log(persons[0].toJSON())
}, function(error) {
    // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
BuiltQuery personQuery = Built.App("blt5d4sample2633b").Class("person").Query();

 
// create a location object
BuiltLocation loc = new BuiltLocation();

// method signature is : setLocation(LONGITUDE, LATITUDE);
loc.SetLocation(19.4667M, 72.8M);
 
personQuery.NearLocation(loc, 1000);
 
personQuery.Exec().ContinueWith(queryTask =>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Flatten().InnerException for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'query={
        "$near": {
            "coords": [
                72.8,
                19.4667
            ],
            "radius": 1000
        }
    }' \
https://api.built.io/v1/classes/sample/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "updated_at": "2015-02-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "__loc": [
                72.8,
                19.4667
            ],
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

The within query accepts a set of coordinates. The objects that are located within this set of coordinates are returned. This is more popularly known as a 'geo-fencing' query. At least three coordinates must be provided (in order to form a polygon). If the third coordinate is not provided, a coordinate of [0,0] is chosen instead. Here's how you issue a within query:

// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *personClass = [builtApplication classWithUID:@"person"];
BuiltQuery *personQuery = [personClass query]; 
 
// create a location object
BuiltLocation *locationObj1 = [BuiltLocation locationWithLongitude:72.82519 andLatitude:19.47468]; 
BuiltLocation *locationObj2 = [BuiltLocation locationWithLongitude:72.83172 andLatitude:19.47582]; 
BuiltLocation *locationObj3 = [BuiltLocation locationWithLongitude:72.82854  andLatitude:19.47161];
 
[personQuery withinLocations:@[locationObj1, locationObj2, locationObj3]];
 
[personQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
      // the query has executed successfully.
      // [result getResult] will contain a list of objects
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var personClass:BuiltClass = builtApplication.classWithUID("person")
var personQuery:BuiltQuery = personClass.query()
 
// create a location object
var locationObj1:BuiltLocation = BuiltLocation(longitude: 72.82519, andLatitude: 19.47468)
var locationObj2:BuiltLocation = BuiltLocation(longitude: 72.83172, andLatitude: 19.47582)
var locationObj3:BuiltLocation = BuiltLocation(longitude: 72.82854, andLatitude: 19.47161)
 
personQuery.withinLocations([locationObj1, locationObj2, locationObj3])
 
personQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
      // the query has executed successfully.
      // result.getResult() will contain a list of objects        
    }else {
      // query execution failed.
      // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend

BuiltApplication builtApplication   = Built.application(context, "blt5d4sample2633b");
BuiltQuery personQuery = builtApplication.classWithUid("person").query();
 
// create a location object
BuiltLocation point1 = new BuiltLocation();
point1.setLocation(19.47468, 72.82519);
 
BuiltLocation point2 = new BuiltLocation();
point2.setLocation(19.47582, 72.83172);
 
BuiltLocation point3 = new BuiltLocation();
point3.setLocation(19.47161, 72.82854);
 
ArrayList<Object> locations = new ArrayList<Object>();
locations.add(point1);
locations.add(point2);
locations.add(point3);
 
personQuery.withInLocation(locations);
 
personQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
        
        if(error == null){
             // the queryResultObject will contain the objects of the class
             List<BuiltObject> objects = queryResultObject.getResultObjects();
 
        }else{
             // query failed
             // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend

var query = Built.App('blt5d4sample2633b').Class('person').Query();

// create location object
// the constructor signature is : Built.Location(LONGITUDE, LATITUDE)
var location1 = Built.Location(60, 80);
var location2 = Built.Location(41, 90);
var location3 = Built.Location(52, 72);

query = query.withinLocation([location1, location2, location3]);

query
.exec()
.then(function(persons) {
    console.log(persons[0].toJSON())
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'person' is a uid of a class on Built.io Backend
BuiltQuery personQuery = Built.App("blt5d4sample2633b").Class("person").Query();

// create a location object
BuiltLocation point1 = new BuiltLocation();
point1.SetLocation(19.47468M, 72.82519M);
 
BuiltLocation point2 = new BuiltLocation();
point2.SetLocation(19.47582M, 72.83172M);
 
BuiltLocation point3 = new BuiltLocation();
point3.SetLocation(19.47161M, 72.82854M);
 
List locations = new List();
locations.Add(point1);
locations.Add(point2);
locations.Add(point3);
 
personQuery.WithInLocation(locations);
 
 
personQuery.Exec().ContinueWith(queryTask=>
{
    if (queryTask.IsFaulted)
    {
        // query failed
        // refer to the queryTask.Exception.Flatten().InnerException for more details
    }
    else
    {
        // the queryTask.Result will contain the objects of the class
    }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'query={
      "$within": [
          [
              72.82519,
              19.47468
          ],
          [
              72.83172,
              19.47582
          ],
          [
              72.82854,
              19.47161
          ]
     ]
  }' \
https://api.built.io/v1/classes/sample/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "updated_at": "2015-02-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "__loc": [
                72.82519,
                19.47468
            ],
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

Deleting objects

Now, to wrap it up, let's delete the project object that we were working on.

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
 
// 'bltf4fsamplec851db' is uid of an object of 'project' class 
BuiltObject *projectObject = [projectClass objectWithUID:@"bltf4fsamplec851db"];
 
[projectObject destroy:^(BuiltResponseType responseType, NSError *error) {
        if (error == nil) {
            // object is deleted
        }else {
          // there was an error in deleting the object
          // error.userinfo contains more details regarding the same
        }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
 
// 'bltf4fsamplec851db' is uid of an object of 'project' class 
var projectObject:BuiltObject = projectClass.objectWithUID("bltf4fsamplec851db")
projectObject.destroy { (responseType:BuiltResponseType, error:NSError!) -> Void in
      if (error == nil) {
          // object is deleted
      }else {
        // there was an error in deleting the object
        // error.userinfo contains more details regarding the same
      }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication   = Built.application(context,"blt5d4sample2633b");
BuiltObject projectObject    = builtApplication.classWithUid("project").object("blt0ae4df463e93f6f5");
 
projectObject.destroy(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
        
            if(error == null){
               // object is deleted successfully
 
            }else{
               // some error has occurred.
               // refer to the 'error' object for more details.
            }
 
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var Project = Built.App('blt5d4sample2633b').Class('project').Object;

// 'bltf4fsamplec851db' is uid of an object of 'project' class 
var project = Project('bltf4fsamplec851db');

project
.delete()
.then(function() {
    // object is deleted successfully
}, function(error) {
    // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class("class_uid").Object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend
// 'bltf4fsamplec851db' is uid of an object of 'project' class 
BuiltObject projectObject = Built.App("blt5d4sample2633b").Class("project").Object().SetUid("bltf4fsamplec851db");
 
projectObject.Delete().ContinueWith(objectTask=>
{
    if (objectTask.IsFaulted == null)
    {
         // some error has occurred.
        //  refer to the objectTask.Exception.Flatten().InnerException for more details.
    }
    else
    {
        // object is deleted successfully
    }
});
curl -i -X DELETE \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
https://api.built.io/v1/classes/project/objects/bltf4fbbc94e8c851db
RESPONSE:
{
    "notice": "Object deleted successfully"
}

Users

These are the users of your application.

Your application users can sign-up, login and logout. You can also allow the users to login using their Google, Facebook, tibbr, and Twitter credentials via a mechanism called 'Federated Login'. We will discuss Federated Login in detail later in this section.

Built.io Backend provides a predefined class called 'Application User', which contains all the data related to the users of your application. To locate this class, click on 'Classes' on the left panel in the management console, and then select 'System Classes' on the top. System classes are ready-made classes provided by the system itself. They contain specialized functionality and behavior, along with all the regular features provided by Classes and Objects.

System Classes

The Application User class is the one we are interested in. To understand this class better, edit the class and take a look at its schema. There are fields for email, username, first name, last name and 'active' status. Since this is also a regular class, we may add more fields to suit our application. However, deleting or modifying the existing fields is not allowed. While having a look at it, also note the uid for the class: built_io_application_user. This uid can be used later, for example, when querying the user's class.

A user owns any object that he creates. This means that the user has exclusive access to that object. That user is the only one who can read, modify, and delete that object. In the Security section of this guide, you will learn how to securely grant access of a user's object to other users as well.

We'll now look at how to register a user.

Register

The very first thing your app will do is ask the user to register. In order to do this, you require a minimum of three attributes: email, password, and password_confirmation. As soon as you run the code given below, Built.io Backend will create a new user for your app. However, before creating the user, Built.io Backend checks if the entered email id is unique. Like for every other object, Built.io Backend generates a random and unique uid for the user. Any operation which requires identifying a user requires his unique uid.

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *userObject = [builtApplication user];
userObject.email = @"test@email.com";
userObject.password = @"password";
userObject.confirmPassword = @"password";
 
[userObject registerUser:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
        // user has signed up successfully
    }else {
        // there was an error in signing up the user
        // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var userObject:BuiltUser = builtApplication.user()
userObject.email = "test@email.com";
userObject.password = "password";
userObject.confirmPassword = "password";
userObject.registerUser { (responseType:BuiltResponseType, error:NSError!) -> Void in
if (error == nil) { // user has signed up successfully }else { // there was an error in signing up the user // error.userinfo contains more details regarding the same } }
// 'blt5d4sample2633b' is a dummy Application API key
BuiltUser userObject = Built.application(context, "blt5d4sample2633b").user();
 
userObject.setEmail("test@email.com");
userObject.setPassword("password");
userObject.setConfirmPassword("password");
 
userObject.register(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType resType, BuiltError error) {
 
          if(error == null){
              // user is registered successfully.
          }else{
              // some error has occurred
              // refer to the 'error' object for more details
          }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var user = Built.App('blt5d4sample2633b').User();

user
.register("test@email.com", "password", "password")
.then(function(user) {
    // user registered successfully
    console.log(user.toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltUser userObject = Built.App("blt5d4sample2633b").User();

Dictionary<string, object> userInfo = new Dictionary<string,object>();
userInfo.Add("email","test@email.com");
userInfo.Add("password","password");
userInfo.Add("password_confirmation","password");

userObject.Register(userInfo).ContinueWith(userTask=>
{
        if(userTask.IsFaulted)
        {
                // some error has occurred
                // refer to the userTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // user is registered successfully.
        }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "application_user": {
          "email": "test@email.com",
          "password": "password",
          "password_confirmation": "password"
      }
  }' \
https://api.built.io/v1/application/users
RESPONSE:
{
    "notice": "Woot! Application user created successfully!",
    "application_user": {
        "active": false,
        "app_user_object_uid": "system",
        "created_at": "2015-01-10T09:02:02Z",
        "email": "john@malkovich.com",
        "published": true,
        "uid": "app_bltbcbbb4730c4af8f1",
        "updated_at": "2015-02-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

When an application user registers on your app, the SDK automatically detects the device type of the user. Let's say that an Android user registers on your app, the SDK informs Built.io Backend about the device type and saves the info in the Application User class. To find out the device type of any user, go to Data > System Classes > Application User in the management console. 

You can get a quick overview of the total number of users with particular device type in API Metrics.

Once the user is created, Built.io Backend sends a verification link to the given email address. The user will be allowed to login only after verifying his/her email address. If you do not want the users to go through the process of activating the account, Built.io Backend allows you to do so. You can also customize the content of the activation email. You can do all this and more by going into the Settings section in the application:

Settings-Mail

Login

Once the user is registered and activated, you can log him in. On logging a user in, you also receive the access_token, which identifies the users's session.You must include the access_token in all of the subsequent calls in order to identify the user.

Note: We will continue to support authtokens for all the apps based on versions v1, v2, and v3.

Here's a short snippet to log a user in. Note how the access_token is extracted from the response:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *userObject = [builtApplication user];
[userObject loginWithEmail:@"test@email.com" andPassword:@"password" completion:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
          // user has logged in successfully
          // user.authtoken contains the session authtoken
    }else {
          // login failed
          // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var userObject:BuiltUser = builtApplication.user()
userObject.loginWithEmail("test@email.com", andPassword: "password") { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
          // user has logged in successfully
          // user.authtoken contains the session authtoken
    }else {
          // login failed
          // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
BuiltUser userObject  =  builtApplication.user();
 
userObject.login("test@email.com", "password", new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
     
          if(error == null){
            // user has logged in successfully.
          }else{
            // login failed
            // refer to the 'error' object for more details
          }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var user = Built.App('blt5d4sample2633b').User();

user
.login('test@email.com', 'password')
.then(function(user) {
    // user logged in successfully
    console.log(user.toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltUser userObject = Built.App("blt5d4sample2633b").User();

userObject.Login("test@email.com", "password").ContinueWith(userTask=>
{
        if(userTask.IsFaulted)
        {
                // login failed
                // refer to the userTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // user has logged in successfully
        }
});
curl -X POST \
-H "application_api_key: blt5b49f08d34eebfe6" 
-H "Content-Type: application/json" 
-d '{
         "application_user": {
             "email": "test@email.com",
             "password": "password"
         }
     }' \ 
https://api.built.io/v1/application/users/login
RESPONSE:
{
    "notice": "Woot! Logged in successfully!",
    "application_user": {
        "updated_at": "2015-01-09T05:38:14.100Z",
        "created_at": "2015-01-09T12:18:42.922Z",
        "ACL": {
            "disable": false,
            "others": [],
            "can": []
        },
        "__loc": null,
        "username": "",
        "email": "hulk@mailinator.com",
        "first_name": "",
        "last_name": "",
        "device_type": "",
        "auth_data": {
            "twitter": {
                "user_id": ""
            },
            "facebook": {
                "user_id": ""
            },
            "tibbr": {
                "host": "",
                "user_id": ""
            },
            "google": {
                "email": ""
            }
        },
        "active": true,
        "tags": [],
        "updated_by": "sys_blt0887d88779a854dc",
        "created_by": "sys_blt0887d88779a854dc",
        "app_user_object_uid": "system",
        "published": true,
        "uid": "bltc452462322deb2d3",
        "_version": 5,
        "auth": {
         "access_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiYmx0YjJmNTY4ODgwMDYwNTQ5ZWI3MGZlYWE0IiwicnVmcmVzaF90b2SAmpleJsdDM1tWI5ODk2NDIwNWZlNjI1NGU0OSaMpLEInVzZXJfdWlkIjoiYmx0ODQ4YzQ2OWM4NjJlMGIxOCIsImV4dHmhX2RhdGEiOnt9LCJpYXQiOjE1MTE1MTgyNTZ9.M5NtqlOh8gLL8MiEo76sxeqqziySxBsaT1VerC9BmAo",
         "refresh_token": "blt351b98sample54e49c33"
        }
    }
}

Below is the detailed explanation of Access Token being introduced in Built.io Backend version 4.

Access Token

Access token is a means by which you can grant secure and temporary access to the users for your application. For earlier versions of Built.io Backend (v1 to v3), we used authtokens which had no expiration time. With the release of version 4,  we have switched to access tokens where you can opt to set an expiration time for the access tokens associated with your application.

Need for Access Tokens

The main motive for moving to access tokens from authtokens is enhanced security. The authtoken, once created, remains valid till the user manually logs out from the system. Consider a scenario, where an authtoken for company data is accidentally shared by the company employee with an outsider. In this case, the outsider can use the authtoken to access the company data till the company employee is logged in to the company system. This poses a serious threat to the company and its confidential data.

Using access tokens helps you minimize this threat by allowing you to set expiration time limit after which it cannot be used to access data. By default, the access tokens have no expiration time limit. Users have to toggle-on the ‘Session Timeout’ feature in the app and specify the duration (minimum one minute and maximum 24 hours) after which the access token should be expired.

How it works

The working of the access tokens for which session timeout has been enabled is primarily based on two factors:

  1. Expiration Time Limit  - Time after which the current access token is expired.
  2. Refresh Token - Time after which the current access token is expired.

The detailed working of the expiration enabled access tokens is given below: 

  access_token.jpg

Device Linking

  • With the latest release of Built.io Backend, users can restrict the use of a particular access_token to a specific device by using this feature. Built.io Backend uses the device_id (a unique number associated with each handheld device ) of the device to link it with the access_token. Users can use libraries such as ‘fingerprint’ to acquire the device_id for web browsers.
  • This means that only the device linked with a specific access_token can use it to send requests to the Built.io Backend.
  • Once the link is established, the device sends the unique ID as well as the access_token in all the requests made to the Built.io Backend. This allows Built.io Backend to verify that the request has been invoked by the authorized device only.
  • To enable this feature, users should send the device_id in the headers of the login request invoked on Built.io Backend. On receiving this request, Built.io Backend  generates an access_token, which is  linked  with the specified device_id, and sends it back to the user. For every subsequent request, the user has to send the same device_id and the access_token in the header.This allows Built.io Backend to uniquely identify the device. If a device is linked to an access_token and user fails to send the device_id in the header of the subsequent API calls, an ‘invalid access_token’ error will be displayed.

Device-Linking-Diagram.jpg

Object Owners

As we learned earlier, an object created by a user falls under that user's ownership. In a mature app, we will have many users sharing objects with each other. In such a situation, you will want to know which object belongs to which owner. The include_owner filter allows you to retrieve the owner's profile for each object returned in a query.

In the following example, we use include_owner to retrieve the owners as well when we query for projects:

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
BuiltQuery *projectQuery = [projectClass query]; 
 
[projectQuery includeOwner];
 
[projectQuery exec:^(BuiltResponseType responseType, BuiltQueryResult *result, NSError *error) {
    if (error == nil) {
        // the query has executed successfully.
        // [result getResult] will contain a list of objects
        NSString *owner = [(BuiltObject *)[[result getResult] objectAtIndex:0] owner];
    }else {
        // query execution failed.
        // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
var projectQuery:BuiltQuery = projectClass.query()
 
projectQuery.includeOwner()
 
projectQuery.exec { (responseType:BuiltResponseType, result:BuiltQueryResult!, error:NSError!) -> Void in
    if (error == nil) {
        // the query has executed successfully.
        // result.getResult() will contain a list of objects        
    }else {
        // query execution failed.
        // error.userinfo contains more details regarding the same        
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication builtApplication    = Built.application(context, "blt5d4sample2633b");
BuiltQuery projectQuery = builtApplication.classWithUid("project").query();
 
projectQuery.includeOwner();
 
projectQuery.exec(new QueryResultsCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltQueryResult queryResultObject, BuiltError error) {
      
        if(error == null){
            //the queryResultObject will contain the objects of the class
            List<BuiltObject> objects = queryResultObject.getResultObjects();
 
            //the following is the owner of the first object in hashmap
            HashMap<String, Object> owner = objects.get(0).getOwner();
        }else{
            //query failed
            // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var myQuery = Built.App('blt5d4sample2633b').Class('project').Query();

myQuery = myQuery.includeOwner();

myQuery
.exec()
.then(function(projects) {
    // projects is an array of SDK objects
    // To get the owner of the first object
    console.log(projects[0].get('_owner'));
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltQuery projectQuery = Built.App("blt5d4sample2633b").Class("project").Query();

projectQuery.IncludeOwner();

projectQuery.Exec().ContinueWith(queryTask =>
{
        if(queryTask.IsFaulted)
        {
                //query failed
                // refer to the queryTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                //the queryTask.Result will contain the objects of the class
                BuiltObject[] objects = queryTask.Result.Result;

                //the following is the owner of the first object in dictionary
                Dictionary<string, object> owner = objects[0].GetOwner();
        }
});
curl -i -X GET \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-G \
--data-urlencode 'include_owner=true' \
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
    "objects": [
        {
            "published": true,
            "uid": "bltf4fbbc94e8c851db",
            "name": "Super Project #41!",
            "description": "We use this project internally",
            "updated_at": "2015-02-10T09:02:02Z",
            "created_at": "2015-01-10T09:02:02Z",
            "_owner": {
                "active": true,
                "app_user_object_uid": "system",
                "created_at": "2013-06-16T15:55:13Z",
                "email": "john@malkovich.com",
                "published": true,
                "uid": "app_bltc361f02bcdcfab3f",
                "updated_at": "2013-06-27T08:53:02Z",
                "ACL": {
                    "can": []
                },
                "tags": []
            },
            "ACL": {
                "can": []
            },
            "tags": []
        }
    ]
}

Logout

Logging out a user is simple. The SDKs guarantee that the access_token is sent in all of the subsequent calls after logging in, and it will do so in the logout call as well. In case of the REST API, you will have to pass the access_token manually in the header. Here's a sample:

[userObject logout:^(BuiltResponseType responseType, NSError *error) {
        if (error == nil) {
            // user has logged out successfully
        }else {
              // login failed
              // error.userinfo contains more details regarding the same
        }
}];
userObject.logout { (responseType:BuiltResponseType, error:NSError!) -> Void in
        if (error == nil) {
            // user has logged out successfully
        }else {
              // login failed
              // error.userinfo contains more details regarding the same
        }
}
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
BuiltUser userObject  =  builtApplication.user();
 
userObject.logout(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
     
          if(error == null){
              // user is logged out successfully.
          }else{
             // login failed
             // refer to the 'error' object for more details
          }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var user = Built.App('blt5d4sample2633b').User();

user
.logout()
.then(function() {
    // User logged out successfully
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltUser userObject = Built.App("blt5d4sample2633b").User();
userObject.SetHeader("access_token","eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiYmx0YjJmNTY4ODgwMDYwNTQ5ZWI3MGZlYWE0IiwicnVmcmVzaF90b2SAmpleJsdDM1tWI5ODk2NDIwNWZlNjI1NGU0OSaMpLEInVzZXJfdWlkIjoiYmx0ODQ4YzQ2OWM4NjJlMGIxOCIsImV4dHmhX2RhdGEiOnt9LCJpYXQiOjE1MTE1MTgyNTZ9.M5NtqlOh8gLL8MiEo76sxeqqziySxBsaT1VerC9BmAo");
userObject.Logout().ContinueWith(userTask =>
{
        if(userTask.IsFaulted)
        {
                // login failed
                // refer to the userTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // user is logged out successfully.
        }
});
curl -i -X DELETE \
-H "application_api_key: blt5d4sample2633b" \
-H "access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiYmx0YjJmNTY4ODgwMDYwNTQ5ZWI3MGZlYWE0IiwicnVmcmVzaF90b2SAmpleJsdDM1tWI5ODk2NDIwNWZlNjI1NGU0OSaMpLEInVzZXJfdWlkIjoiYmx0ODQ4YzQ2OWM4NjJlMGIxOCIsImV4dHmhX2RhdGEiOnt9LCJpYXQiOjE1MTE1MTgyNTZ9.M5NtqlOh8gLL8MiEo76sxeqqziySxBsaT1VerC9BmAo" \
https://api.built.io/v1/application/users/logout
RESPONSE:
{
    "notice": "Woot! Application user logged out successfully."
}

Update User Profile

Updating the logged in user's profile is similar to updating an object of the Application User class. Aside from the regular attributes of first/last name, username, etc. you can also update any custom fields defined in the Application User class.

It is necessary to be logged in before you try to update the user profile. A sample for updating an user's first/last name is given below:

// 'blt5d4sample2633b' is a dummy Application API key
// 'bltba9a44506dd9e741' is a uid of an object of inbuilt Application User class
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *userObject = [builtApplication userWithUID:@"bltba9a44506dd9e741"];
 
userObject.email = @"john@email.com";    
userObject.firstName = @"John";
userObject.lastName = @"Joseph";
 
[userObject updateUserWithAuthData:nil completion:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
        // user profile updated successfully
    }else {
        // there was an error in updating the user profile
        // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'bltba9a44506dd9e741' is a uid of an object of inbuilt Application User class
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var userObject : BuiltUser = builtApplication.userWithUID("bltba9a44506dd9e741")
 
userObject.email = "john@email.com"
userObject.firstName = "John"
userObject.lastName = "Joseph"
 
userObject.updateUserWithAuthData(nil, completion: { (response:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
        // user profile updated successfully
    }else {
        // there was an error in updating the user profile
        // error.userinfo contains more details regarding the same
    }
})
// 'blt5d4sample2633b' is a dummy Application API key
// 'bltba9a44506dd9e741' is a uid of an object of inbuilt Application User class

BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
BuiltUser userObject  =  builtApplication.user("bltba9a44506dd9e741");
 
userObject.setFirstName("John");
userObject.setUserName("Joseph");
userObject.setEmail("john@email.com");
 
userObject.updateUserInfo(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
     
          if(error == null){
             // user profile is updated successfully.
          }else{
             // login failed
             // refer to the 'error' object for more details
          }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bltba9a44506dd9e741' is a uid of an object of inbuilt Application User class
var user = Built.App('blt5d4sample2633b').User('bltba9a44506dd9e741');

// 'updateUserProfile' Updates user's profile on built.io as well as local storage if 'Session' is set to Built.Session.LOCAL_STORAGE
user
.updateUserProfile({
    email: "john@email.com",
    first_name: "john",
    last_name: "joseph",
})
.then(function(user) {
    // user profile update successfully
    console.log(user.toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bltba9a44506dd9e741' is a uid of an object of inbuilt Application User class
BuiltUser userObject = Built.App("blt5d4sample2633b").User();
userObject.Uid = "bltba9a44506dd9e741";
Dictionary<string, object> dict = new Dictionary<string, object>();
                dict.Add("first_name", "John");
                dict.Add("username", "Malkovich");  


userObject.SetHeader("access_token", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiYmx0YjJmNTY4ODgwMDYwNTQ5ZWI3MGZlYWE0IiwicnVmcmVzaF90b2SAmpleJsdDM1tWI5ODk2NDIwNWZlNjI1NGU0OSaMpLEInVzZXJfdWlkIjoiYmx0ODQ4YzQ2OWM4NjJlMGIxOCIsImV4dHmhX2RhdGEiOnt9LCJpYXQiOjE1MTE1MTgyNTZ9.M5NtqlOh8gLL8MiEo76sxeqqziySxBsaT1VerC9BmAo");
userObject.UpdateUserProfile(dict).ContinueWith(userTask =>
{
        if(userTask.IsFaulted)
        {
                // some erro has occured
                // refer to the userTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // user profile is updated successfully.
        }
});
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiYmx0YjJmNTY4ODgwMDYwNTQ5ZWI3MGZlYWE0IiwicnVmcmVzaF90b2SAmpleJsdDM1tWI5ODk2NDIwNWZlNjI1NGU0OSaMpLEInVzZXJfdWlkIjoiYmx0ODQ4YzQ2OWM4NjJlMGIxOCIsImV4dHmhX2RhdGEiOnt9LCJpYXQiOjE1MTE1MTgyNTZ9.M5NtqlOh8gLL8MiEo76sxeqqziySxBsaT1VerC9BmAo" \
-H "Content-Type: application/json" \
-d '{
      "application_user": {
          "first_name": "John",
          "last_name": "joseph"
      }
   }' \
https://api.built.io/v1/application/users/app_bltbcbbb4730c4af8f1
RESPONSE:
{
    "notice": "Woot! Application user updated successfully!",
    "application_user": {
        "active": false,
        "app_user_object_uid": "system",
        "created_at": "2015-01-10T09:02:02Z",
        "email": "john@malkovich.com",
        "first_name": "John",
        "last_name": "joseph",
        "published": true,
        "uid": "app_bltbcbbb4730c4af8f1",
        "updated_at": "2015-02-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Here's how you can update any custom fields defined in the schema. We update a 'company' field:

// 'blt5d4sample2633b' is a dummy Application API key
// 'bltba9a44506dd9e741' is a uid of an object of inbuilt Application User class
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *userObject = [builtApplication user];
 
userObject.customProperties = @{@"company": @"raw engineering"};
 
[userObject updateUserWithAuthData:nil completion:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
        // user profile updated successfully
    }else {
        // there was an error in updating the user profile
        // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'bltba9a44506dd9e741' is a uid of an object of inbuilt Application User class
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var userObject : BuiltUser = builtApplication.user()
 
userObject.customProperties = ["company": "raw engineering"]
 
userObject.updateUserWithAuthData(nil, completion: { (response:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
        // user profile updated successfully
    }else {
        // there was an error in updating the user profile
        // error.userinfo contains more details regarding the same
    }
})
// 'blt5d4sample2633b' is a dummy Application API key
// 'bltba9a44506dd9e741' is a uid of an object of inbuilt Application User class
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
BuiltUser userObject  =  builtApplication.user("bltba9a44506dd9e741");
 
userObject.set("company", "raw engineering");
 
userObject.updateUserInfo(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(ResponseType responseType, BuiltError error) {
     
          if(error == null){
             // user profile is updated successfully.
          }else{
             // login failed
             // refer to the 'error' object for more details
          }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bltba9a44506dd9e741' is a uid of an object of inbuilt Application User class

var user = Built.App('blt5d4sample2633b').User('bltba9a44506dd9e741');

// 'updateUserProfile' Updates user's profile on built.io as well as local storage if 'Session' is set to Built.Session.LOCAL_STORAGE
user
.updateUserProfile({
    company: "raw engineering"
})
.then(function(user) {
    // user profile update successfully
    console.log(user.toJSON())
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'bltba9a44506dd9e741' is a uid of an object of inbuilt Application User class
BuiltUser userObject = Built.App("blt5d4sample2633b").User();
userObject.Uid = "bltba9a44506dd9e741";
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("company", "raw engineering");
                 
userObject.SetHeader("access_token", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiYmx0YjJmNTY4ODgwMDYwNTQ5ZWI3MGZlYWE0IiwicnVmcmVzaF90b2SAmpleJsdDM1tWI5ODk2NDIwNWZlNjI1NGU0OSaMpLEInVzZXJfdWlkIjoiYmx0ODQ4YzQ2OWM4NjJlMGIxOCIsImV4dHmhX2RhdGEiOnt9LCJpYXQiOjE1MTE1MTgyNTZ9.M5NtqlOh8gLL8MiEo76sxeqqziySxBsaT1VerC9BmAo");
userObject.UpdateUserProfile(dict).ContinueWith(userTask =>
{
        if(userTask.IsFaulted)
        {
                // some erro has occured
                // refer to the userTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // user profile is updated successfully.
        }
});
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiYmx0YjJmNTY4ODgwMDYwNTQ5ZWI3MGZlYWE0IiwicnVmcmVzaF90b2SAmpleJsdDM1tWI5ODk2NDIwNWZlNjI1NGU0OSaMpLEInVzZXJfdWlkIjoiYmx0ODQ4YzQ2OWM4NjJlMGIxOCIsImV4dHmhX2RhdGEiOnt9LCJpYXQiOjE1MTE1MTgyNTZ9.M5NtqlOh8gLL8MiEo76sxeqqziySxBsaT1VerC9BmAo" \
-H "Content-Type: application/json" \
-d '{
       "application_user": {
           "company": "raw engineering"
      }
  }' \
https://api.built.io/v1/application/users/app_bltbcbbb4730c4af8f1
RESPONSE:
{
    "notice": "Woot! Application user updated successfully!",
    "application_user": {
        "active": false,
        "app_user_object_uid": "system",
        "created_at": "2015-01-10T09:02:02Z",
        "email": "john@malkovich.com",
        "first_name": "John",
        "last_name": "Malkovich",
        "company": "raw engineering",
        "published": true,
        "uid": "app_bltbcbbb4730c4af8f1",
        "updated_at": "2015-02-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Federated Login

Federated Login is a mechanism, through which you can allow users to login using their Google, Facebook, tibbr or Twitter accounts. Federated login removes the need to go through the signup-activation-login cycle, instead, we authenticate the user using one of their federated accounts, and log the user in.

The users are logged into their federated account when they provide credentials of that account. A corresponding account is created for the federated account, with its own authtoken for session maintenance. This means that we only rely on the federated account to provide us details for authentication, after which we use the regular Built.io Backend mechanisms of session maintenance.

The details for federated accounts are provided in a field called auth_data.Use this field to retrieve details like the user's Google, Facebook, tibbr or Twitter profile.In the newer version we have access-token,for more info please refer here

Google
Google provides the OAuth2 protocol to help with federated logins. You need to follow the OAuth routine to access Google APIs for your platform, the details of which are given here. Also, you may want to reference the OAuth doc for installed applications (mobile devices). At the end of this routine, you will receive an access_token, which you can then use to login to Built.io Backend. it will only expect the access_token to be provided.

On the Built.io Backend side, we use the access_token to fetch the user's profile, and log the user in. The user's google profile that is retrieved using the access_token is stored in auth_data, in the key user_profile. The email of the user is populated in the email field, which also means that a user with such an existing email will have the auth_data linked to his account.

For our project, here's how you would allow users to login using Google:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *googleUser = [builtApplication user];
 
[googleUser loginWithGoogleAuthAccessToken:@"ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8" completion:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
        // user has logged in successfully
        // user.authtoken contains the session authtoken
    }else {
        // login failed
        // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var googleUser:BuiltUser = builtApplication.user()
 
googleUser.loginWithGoogleAuthAccessToken("ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8") { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
        // user has logged in successfully
        // user.authtoken contains the session authtoken
    }else {
        // login failed
        // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
BuiltUser userObject  =  builtApplication.user();
 
/*
  Argument to loginWithGoogle is as follows
  access_token  => Access token from Google
*/
 
userObject.loginWithGoogle("ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8", new BuiltResultCallBack() {
 
  @Override
  public void onCompletion(BuiltResponseType responseType, BuiltError error) {
   
      if(error == null){
         // user has logged in successfully
      }else{
         // login failed
         // refer to the 'error' object for more details
      }
  }
});
// 'blt5d4sample2633b' is a dummy Application API key
var user = Built.App('blt5d4sample2633b').User();

/*
  Argument to loginWithGoogle is as follows
  access_token  => Access token from Google
*/

user.loginWithGoogle('ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8')
.then(function(user) {
    //do something here
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltUser userObject = Built.App("blt5d4sample2633b").User();

/*
Argument to loginWithGoogle is as follows
access_token  => Access token from Google
*/

userObject.LoginWithGoogle("ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8").ContinueWith(userTask =>
{
        if(userTask.IsFaulted)
        {
                // login failed
                // refer to the userTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // user has logged in successfully
        }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "application_user": {
          "auth_data": {
              "google": {
                  "access_token": "ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8"
              }
          }
      }
  }' \
https://api.built.io/v1/application/users
RESPONSE:
{
    "notice": "Application user logged in successfully!",
    "application_user": {
        "active": true,
        "app_user_object_uid": "system",
        "created_at": "2015-01-10T09:02:02Z",
        "email": "john@malkovich.com",
        "published": true,
        "uid": "app_bltc361f02bcdcfab3f",
        "updated_at": "2015-01-10T09:02:02Z",
        "auth_data": {
            "google": {
                "user_profile": {
                    ...google user profile...
                }
            }
        }"ACL": {
            "can": [
            ]
        },
        "tags": [
        ],
        "auth": {
         "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiYmx0YjJmNTY4ODgwMDYwNTQ5ZWI3MGZlYWE0IiwicnVmcmVzaF90b2SAmpleJsdDM1tWI5ODk2NDIwNWZlNjI1NGU0OSaMpLEInVzZXJfdWlkIjoiYmx0ODQ4YzQ2OWM4NjJlMGIxOCIsImV4dHmhX2RhdGEiOnt9LCJpYXQiOjE1MTE1MTgyNTZ9.M5NtqlOh8gLL8MiEo76sxeqqziySxBsaT1VerC9BmAo",
         "refresh_token": "blt351b98sample54e49c33"
        }
    }
}

Facebook
Facebook uses the OAuth2 protocol to help with federated logins. Depending on your platform, you will need to perform a few steps to enable Facebook login. Click the links below for the Facebook steps for each platform:

After you perform the steps to enable login for your platform, you will obtain an access_token which you can then use to login to Built.io Backend. it will only expects the access_token to be provided.

On the Built.io Backend side, we use the access_token to fetch the user's profile, and log them in. The user's Facebook profile that is retrieved using the access_token is stored in auth_data, in the key user_profile. You may fetch it anytime after logging in, by fetching the user's profile.

For our project, here's how you would allow them to login using Facebook:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *facebookUser = [builtApplication user];
[facebookUser loginWithFacebookAccessToken:@"ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8" completion:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
        // user has logged in successfully
        // user.authtoken contains the session authtoken
    }else {
        // login failed
        // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var facebookUser:BuiltUser = builtApplication.user()
 
facebookUser.loginWithFacebookAccessToken("ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8") { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
        // user has logged in successfully
        // user.authtoken contains the session authtoken
    }else {
        // login failed
        // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
BuiltUser userObject  =  builtApplication.user();
 
/*
  Arguments to loginWithFacebook are as follows
  access_token  => Access token from Facebook
*/
 
userObject.loginWithFacebook("ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8", new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
   
        if(error == null){
          // user has logged in successfully
        }else{
           // login failed
           // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var user = Built.App('blt5d4sample2633b').User();

/*
  Arguments to loginWithFacebook are as follows
  access_token  => Access token from Facebook
*/

user.loginWithFacebook('ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8')
.then(function(user) {
    // do something here
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltUser userObject = Built.App("blt5d4sample2633b").User();
 
/*
  Arguments to loginWithFacebook are as follows
  access_token  => Access token from Facebook
*/
 
userObject.LoginWithFacebook("ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8").ContinueWith(userTask =>
{
    if (userTask.IsFaulted)
    {
        // login failed
        // refer to the userTask.Exception.Flattern().InnerException for more details
    }
    else
    {
        // user has logged in successfully
    }

});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "application_user": {
          "auth_data": {
              "facebook": {
                  "access_token": "ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8"
              }
          }
      }
  }' \
https://api.built.io/v1/application/users
RESPONSE:
{
    "notice": "Application user logged in successfully!",
    "application_user": {
        "active": true,
        "app_user_object_uid": "system",
        "created_at": "2015-01-10T09:02:02Z",
        "published": true,
        "uid": "app_bltc361f02bcdcfab3f",
        "updated_at": "2015-01-10T09:02:02Z",
        "auth_data": {
            "facebook": {
                "user_profile": {
                    ...face book user profile...
                }
            }
        }"ACL": {
            "can": [
            ]
        },
        "tags": [
        ],
        "auth": {
         "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiYmx0YjJmNTY4ODgwMDYwNTQ5ZWI3MGZlYWE0IiwicnVmcmVzaF90b2SAmpleJsdDM1tWI5ODk2NDIwNWZlNjI1NGU0OSaMpLEInVzZXJfdWlkIjoiYmx0ODQ4YzQ2OWM4NjJlMGIxOCIsImV4dHmhX2RhdGEiOnt9LCJpYXQiOjE1MTE1MTgyNTZ9.M5NtqlOh8gLL8MiEo76sxeqqziySxBsaT1VerC9BmAo",
         "refresh_token": "blt351b98sample54e49c33"
        }        
    }
}

Twitter
Twitter uses the OAuth 1.0a protocol for federated logins. Please refer the documentation for the same.

For logging in, the following parameters are required:

  • consumer_key 
  • consumer_secret 
  • token 
  • token_secret

The consumer_key and consumer_secret identifies the application. The token and token_secret identifies the user who wants to log in.

On the Built.io Backend side, we use the above parameters to fetch the user's profile, and log them in. The user's Twitter profile that is retrieved in the call is stored in auth_data, in the key user_profile. You may fetch it anytime after logging in, by fetching the user's profile.

For our project, here's how you would allow them to login using Twitter:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *twitterUser = [builtApplication user];
   
//request access for twitter account configured in device.
ACAccountStore *account = [[ACAccountStore alloc] init];
ACAccountType *accountType = [account accountTypeWithAccountTypeIdentifier: ACAccountTypeIdentifierTwitter];  
 
[account requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error) {
    if (granted) {
        NSArray *arrayOfAccounts = [account accountsWithAccountType:accountType];
 
        if ([arrayOfAccounts count] > 0)
        {
            ACAccount *twitterUserAccount = [arrayOfAccounts lastObject];
 
            [twitterUser loginWithTwitterAccount:twitterUserAccount consumerKey:@"aMpLeToKeNVowjHEZrJA_J0k8kjfs78" consumerSecret:@"aMpLeToKeNVowjHEZrJA_J0kfd878" completion:^(BuiltResponseType responseType, NSError *error) {
                if (error == nil) {
                    // twitterUser will contain user profile that is obtained from twitter
                }else {
                    // login failed
                    // error.userinfo contains more details regarding the same
                }
            }];                              
        }else {
            // No twitter account
        }
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var twitterUser:BuiltUser = builtApplication.user()
 
//request access for twitter account configured in device.
var account:ACAccountStore = ACAccountStore()
var accountType:ACAccountType = account.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter)
 
account.requestAccessToAccountsWithType(accountType, options: nil) { (granted:Bool, errors:NSError!) -> Void in
    if (granted) {
        var arrayOfAccounts : NSArray = account.accountsWithAccountType(accountType)
        if (arrayOfAccounts.count > 0) {
            var twitterUserAccount:ACAccount = arrayOfAccounts.lastObject;
            var error : NSError?
            twitterUser.loginWithTwitterAccount(twitterUserAccount, consumerKey: "aMpLeToKeNVowjHEZrJA_J0k8kjfs78", consumerSecret: "aMpLeToKeNVowjHEZrJA_J0kfd878", completion: { (responseType :BuiltResponseType, error:NSError!) -> Void in
                if (error == nil) {
                    // twitterUser will contain user profile that is obtained from twitter
                }else {
                    // login failed
                    // error.userinfo contains more details regarding the same
                }
            })
        }else {
            // No twitter account
        }
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
BuiltUser userObject  =  builtApplication.user();
/*
  Arguments to loginWithTwitter are as follows
  access_token  => Access token from Twitter
*/
userObject.loginWithTwitter("ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8", "aMpLeToKeNVowjHEZrJA_J0k8", 
"aMpLeToKeNVowjHEZrJA_J0k8kjfs78", "aMpLeToKeNVowjHEZrJA_J0kfd878", new BuiltResultCallBack() {
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
      if(error == null){
        // user has logged in successfully
      }else{
        // login failed
        // refer to the 'error' object for more details
      }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var user = Built.App('blt5d4sample2633b').User();

/*
  Arguments to loginWithTwitter are as follows
  token  ==>  Token from Twitter used to identify user
  token_secret Secret ==> Token from Twitter used to identify user
  consumer_key ==> Consumer key used to identify application
  consumer_secret ==> Consumer secret key used to identify application
*/

user.loginWithTwitter('ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8', 'aMpLeToKeNVowjHEZrJA_J0k8', 'aMpLeToKeNVowjHEZrJA_J0k8kjfs78', 'aMpLeToKeNVowjHEZrJA_J0kfd878')
.then(function(user) {
    // do something here
}, function(error) {
    // some error has occurred
    // refer to the 'error' object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltUser userObject = Built.App("blt5d4sample2633b").User();
 
/*
  Arguments to loginWithTwitter are as follows
  token  ==>  Token from Twitter used to identify user
  token_secret Secret ==> Token from Twitter used to identify user
  consumer_key ==> Consumer key used to identify application
  consumer_secret ==> Consumer secret key used to identify application
*/
 
userObject.LoginWithTwitter("ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8", "aMpLeToKeNVowjHEZrJA_J0k8", "aMpLeToKeNVowjHEZrJA_J0k8kjfs78", "aMpLeToKeNVowjHEZrJA_J0kfd878").ContinueWith(userTask =>
{
    if (userTask.IsFaulted)
    {
        // login failed
        // refer to the userTask.Exception.Flattern().InnerException for more details
    }
    else
    {
        // user has logged in successfully
    }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "application_user": {
          "auth_data": {
              "twitter": {
                  "token": "ya29.AHES6ZSvSaMpLeToKeNVowjHEZrJA_J0k8",
                  "token_secret": "aMpLeToKeNVowjHEZrJA_J0k8",
                  "consumer_key": "aMpLeToKeNVowjHEZrJA_J0k8kjfs78",
                  "consumer_secret": "aMpLeToKeNVowjHEZrJA_J0kfd878"
              }
          }
      }
  }' \
https://api.built.io/v1/application/users
RESPONSE:
{
    "notice": "Application user logged in successfully!",
    "application_user": {
        "active": true,
        "app_user_object_uid": "system",
        "created_at": "2015-01-10T09:02:02Z",
        "published": true,
        "uid": "app_bltc361f02bcdcfab3f",
        "updated_at": "2015-01-10T09:02:02Z",
        "auth_data": {
            "twitter": {
                "user_profile": {
                    ...twitter user profile...
                }
            }
        }"ACL": {
            "can": [
            ]
        },
        "tags": [
        ],
        "auth": {
         "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiYmx0YjJmNTY4ODgwMDYwNTQ5ZWI3MGZlYWE0IiwicnVmcmVzaF90b2SAmpleJsdDM1tWI5ODk2NDIwNWZlNjI1NGU0OSaMpLEInVzZXJfdWlkIjoiYmx0ODQ4YzQ2OWM4NjJlMGIxOCIsImV4dHmhX2RhdGEiOnt9LCJpYXQiOjE1MTE1MTgyNTZ9.M5NtqlOh8gLL8MiEo76sxeqqziySxBsaT1VerC9BmAo",
         "refresh_token": "blt351b98sample54e49c33"
        }        
    }
}

AnyAuth

Through Federated Login, Built.io Backend has already made it simple to authenticate via Facebook, twitter, Google and tibbr. AnyAuth takes it a step further. Depending on the type of application you develop, you may want to roll out your own login mechanism. AnyAuth allows you to do just that. AnyAuth leverages Built Extensions and Master Key to enable you to do just this. Now, you can write custom login solutions that could connect to your corporate LDAP, Active Directory, SAML, etc.

At the heart of AnyAuth is an API called generateAccesstoken. This API allows you to login as any user without requiring credentials for the same. This is because the API uses Master Key. Master Key overrides usual restrictions, enabling you to work as a privileged user. This API needs to be used on the server side, where Master Key is not exposed to the client. Thus, it can be safely used in Built Extensions code.

Once you authenticate a user manually, you can issue a query via generateAccesstoken to find the user in Built.io Backend. If the user is found, the API will log him in (and return his  access_token). You can also provide data for creating the user if he doesn't already exist.

To illustrate, suppose we want to authenticate users with just a username (we login the user if he knows the right username). We can create a list of users who can log in via our management console. Below, we are creating a user object with the username "james":

Create User Object


Now, let's write an extension function that uses AnyAuth:

// In extensions we need  to 'require' Built.io Backend package
var BuiltSDK = require('built.io')

// 'blt5d4sample2633b' is a dummy Application API key
// 'blt48f2deca473xxxxx' is a dummy master key
var app = BuiltSDK.App('blt5d4sample2633b').setMasterKey('blt48f2deca473xxxxx');
var User = app.User;

Built.Extension.define('login', function(request, response) {

  // Built.Constants.APPLICATION_USER refers to inbuilt 'Application User' class
  // our query for an existing user with the username
  var query = app.Class(Built.Constants.APPLICATION_USER).Query();

  query = query.where('username', request.params.username);

  User.generateAccessToken(
      query,
      // we *don't* want to create a new user if he doesn't exist
      false,
      // update the user with the following parameters
      {
        username: 'new_username'
      }
    )
    .then(function(user) {
      console.log(user.toJSON())
      return response.success(res)
    }, function(error) {
      return response.error('error', res)
    });
})

Next, we invoke this function in our clients, and login the user:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *anyAuthUser = [builtApplication user];
 
[anyAuthUser loginWithAnyAuthName:@"login" withParameter:@{@"username": @"james",@"password":@"jamespassword"} completion:^(BuiltResponseType responseType, id responseObject, NSError *error){
    if (error == nil) {
        // response will contain the response of the user object
        // here, the response is the user profile, with the authtoken
    }else {
        // error block in case of any error
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var anyAuthUser:BuiltUser = builtApplication.user()
 
anyAuthUser.loginWithAnyAuthName("login", withParameter: ["username":"james","password":"jamespassword"]) { (responseType, responseObject, error) -> Void in
    if (error == nil) {
        // response will contain the response of the user object
        // here, the response is the user profile, with the authtoken
    }else {
        // error block in case of any error
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication   = Built.application(context, "blt5d4sample2633b");
BuiltUser userObject   =  builtApplication.user();
 
HashMap<String, Object> propertiesHash = new HashMap<String, Object>();
propertiesHash.put("username", "james");
propertiesHash.put("password", "jamespassword");
 
userObject.loginWithAnyAuth("login", propertiesHash ,new BuiltResultCallBack() {
 
   @Override
   public void onCompletion(BuiltResponseType resType, BuiltError error) {
               
      if(error == null){
         // user has logged in successfully
      }else{
         // there was an error in updating.
         // refer to the 'error' object for more details
      }
   }
});
// 'blt5d4sample2633b' is a dummy Application API key
// App('api_key').User returns a 'Application User' class constructor
var User = Built.App('blt5d4sample2633b').User;

User.anyAuth('login', {
    username: 'james'
})
.then(function(user) {
    // Logged-in user's details
    console.log(user.toJSON());
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltUser userObject = Built.App("blt5d4sample2633b").User();

userObject.AnyAuthBody =  new Dictionary<string, object>() { 
         {"username", "james"},
         {"password", "jamespassword"}};


userObject.AnyAuth("login").ContinueWith(userTask =>
{
        if(userTask.IsFaulted)
        {
                // there was an error 
                // refer to the userTask.Exception.Flattern().InnerException object for more details
        }
        else
        {
                // user has logged in successfully
        }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
       "username": "james"
    }' \
https://api.built.io/v1/functions/login
RESPONSE:
{
    "result": {
        ...
    }
}

That's all you need for using AnyAuth.

An interesting option is the second parameter of generateAccesstoken. This is a boolean parameter that lets us create a new user, if querying returns nothing. We have set this to false in the above implementation, since we only want existing users to login (which we can control via the management console).

For a more concrete, real world example, please checkout a sample project that implements LinkedIn login using AnyAuth

Retrieve a user's uid

There may be times when you want to assign certain permissions to a particular user, or you may want to address a particular user in Built.io Backend, but you only have the user's email address and not the uid. However, in order to set permissions, you require the user's uid.

In such cases, you can easily retrieve the user's uid using his/her email id. Give below is the code snippet to do this.

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *userObject = [builtApplication user];
 
// get the user's uid by providing the email id used for registration on built.io
[userObject fetchUserUidForEmail:@"test@email.com" completion:^(BuiltResponseType responseType, NSString *userUID, NSError *error) {
        // userUID will contain the user's uid
}];
 
// for facebook, we supply a valid facebook user id
[userObject fetchUserUidForFacebookUserId:@"dummy_facebook_uid" completion:^(BuiltResponseType responseType, NSString *userUID, NSError *error) {
        // userUID will contain the user's uid
}];
 
// similarly, for google we supply an email
[userObject fetchUserUidForGoogleEmail:@"test@gmail.com" completion:^(BuiltResponseType responseType, NSString *userUID, NSError *error) {
        // userUID will contain the user's uid
}];
 
// for facebook, we supply a valid facebook user id
[userObject fetchUserUidForTwitterUserId:@"dummy_twitter_user_id" completion:^(BuiltResponseType responseType, NSString *userUID, NSError *error) {
        // userUID will contain the user's uid
}];

// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var userObject:BuiltUser = builtApplication.user()
 
// get the user's uid by providing the email id used for registration on built.io
userObject.fetchUserUidForEmail("test@email.com", completion: { (responseType, userUID, error) -> Void in
    // userUID will contain the user's uid
})
 
// for facebook, we supply a valid facebook user id
userObject.fetchUserUidForFacebookUserId("dummy_facebook_uid", completion: { (responseType, userUID, error) -> Void in
    // userUID will contain the user's uid
})
 
// similarly, for google we supply an email
userObject.fetchUserUidForGoogleEmail("test@gmail.com", completion: { (responseType, userUID, error) -> Void in
    // userUID will contain the user's uid
})
 
//fetches the user's uid based on Twitter's user id
userObject.fetchUserUidForTwitterUserId("dummy_twitter_user_id", completion: { (responseType, userUID, error) -> Void in
    // userUID will contain the user's uid
})
// 'blt5d4sample2633b' is a dummy Application API key
BuiltUser userObject = Built.App("blt5d4sample2633b").User();
userObject.FetchUserUidByEmail("test@email.com").ContinueWith(userTask =>
{
        if(userTask.IsFaulted)
        {
                // there was an error in fetching uid.
                // refer to the userTask.Exception.Flattern().InnerException object for more details
        }
        else
        {
                var user_uid = userTask.Result;
        }
});
           

// for facebook, we supply a valid facebook user id
userObject.FetchUserUidByFacebookUserId("dummy_facebook_uid").ContinueWith(userTask => { .... });
// similarly, for google we supply an email:
userObject.FetchUserUidByGoogleEmail("test@gmail.com").ContinueWith(userTask => { .... });
//fetches the user's uid based on Twitter's user id
userObject.FetchUserUidByTwitter("dummy_twitter_user_id").ContinueWith(userTask => { .... });
//'blt5d4sample2633b' is a dummy Application API key

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltUser userObject =  builtApplication.user();

userObject.fetchUserUidForEmail("test@email.com", new BuiltUserResultCallback() {
      @Override
      public void onCompletion(BuiltResponseType resType, String userUid, BuiltError error) {
          if(error == null){
            Log.i("user_uid", "" + userUid);
          }else{
            // there was an error in fetching uid.
            // refer to the 'error' object for more details
          }
    }
});

// for facebook, we supply a valid facebook user id
userObject.fetchUserUidForFacebook("dummy_facebook_uid", new BuildUserResultCallback() {...});

// similarly, for google we supply an email:
userObject.fetchUserUidForGoogleEmail("test@gmail.com", new BuildUserResultCallback() {...});

//fetches the user's uid based on Twitter's user id
userObject.fetchUserUidForTwitter("dummy_twitter_user_id", new BuildUserResultCallback() {...});

// 'blt5d4sample2633b' is a dummy Application API key
var user = Built.App('blt5d4sample2633b').User();

// get the user's uid by providing the email id used for registration on built.io
user.fetchUserUidByEmail('test@email.com')
.then(function(user) {
	console.log(user.toJSON())
});

// for facebook, we supply a valid facebook user id
user.fetchUserUidByFacebookUserId('dummy_facebook_uid')
.then(function(user) {
	console.log(user.toJSON())
});

// similarly, for google we supply an email
user.fetchUserUidByGoogleEmail('test@gmail.com')
.then(function(user) {
	console.log(user.toJSON())
});

//fetches the user's uid based on Twitter's user id
user.fetchUserUidByTwitterUserId('dummy_twitter_user_id')
.then(function(user) {
	console.log(user.toJSON())
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
       "application_user": {
          "email": "test@email.com"
        }
    }' \
https://api.built.io/v1/application/users/retrieve_user_uid
RESPONSE:
{
    "uid": "app_bltbcbbb4730c4af8f1"
}

Once you get the uid of the user, you can easily assign permissions to the user. This was an example of retrieving a user's uid when the user is present in the system, but you do not know the uid.

If the user is not present in the system, we generate a uid against the email id when you execute this code. This generated uid is then assigned to the user whenever he signs up.

Password Reset

You can reset passwords for users who forget it. The following flow is adopted for resetting the password:

  • The user inputs his email. 
  • A mail is sent to that email with a link containing a secret reset password token. 
  • The user clicks on the link and inputs his new password.

Use the following call to request a password reset:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *userObject = [builtApplication user];
 
[userObject forgotPasswordForEmail:@"test@email.com" completion:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
        // A password reset request is sent on test@email.com
    }else {
        // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var userObject:BuiltUser = builtApplication.user()
 
userObject.forgotPasswordForEmail("test@email.com", completion: { (responseType, error) -> Void in
      if (error == nil) {
        // A password reset request is sent on test@email.com
    }else {
        // error.userinfo contains more details regarding the same
    }
})
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltUser userObject =  builtApplication.user();
 
userObject.forgotPassword("test@email.com", new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
          if(error == null){
              // the reset password mail is sent
          }else{
              // some error occured.
              // refer to the 'error' object for more details
          }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var user = Built.App('blt5d4sample2633b').User();

user.forgotPassword('test@email.com')
.then(function() {
    // A password reset request is sent on test@email.com
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltUser userObject = Built.App("blt5d4sample2633b").User();

userObject.ForgotPassword("test@email.com").ContinueWith(userTask =>
{
        if(userTask.IsFaulted)
        {
                // some error has occurred
                // refer to the userTask.Exception.Flattern().InnerException object for more details
        }
        else
        {
                // the reset password mail is sent on 'test@email.com'
        }
});
curl -X POST \
-H "application_api_key: blt5b49f08d34eebfe6" \
-H "Content-Type: application/json" \
-d '{
        "application_user": {
            "email": "test@email.com"
        }
    }' \
http://api.built.io/v1/application/users/forgot_password/request_password_reset
RESPONSE:
{
    "notice": "OK! We've sent you an email. Please check it for further instructions."
}

When you make this call, the user receives a mail with a link for resetting his password. The content for this mail can be customized by going to Settings > Mail > Forgot Password section.

The variable reset_password_link is a link provided by Built.io Backend to let your users reset their password. Clicking on that link will direct your users to a page where they can input their new passwords.

You can also provide your own link, pointing to your domain, and hide any mention of "built.io". Your link should show a page where users can input their new password. The link should also accept reset_password_token in its URL. You can interpolate 'reset_password_token' in your link in this way:

http://yourdomain.com/reset_password/{{user.reset_password_token}}

Once you have the password and password_confirmation, send it along with the reset_password_token with a POST call to finally reset the password:

curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "application_user": {
          "password": "wxyz",
          "password_confirmation": "wxyz",
          "reset_password_token": "d6c6hid4332d76sds23"
      }
  }' \
https://api.built.io/v1/application/users/forgot_password/reset_password
RESPONSE:
{
    "notice": "Woot! You've successfully reset your password."
}

Customize Password Reset Email

While logging in, a user may forget his/her login password, and may want to reset it. Built.io Backend provides this functionality for your apps. It also provides a customizable email template that you can send to the users as notifications when they click on 'Forgot your password?' link.

To find the default email template, log in to your Built.io Backend account, and then go to Settings > Mail, and scroll down to the bottom of the page.

Forgot Password Mail Template

If you keep the template unchanged, the user will receive the default email. Alternatively, you can customize the 'Forgot Password' mail that is sent to your application users. You can use variables in the templates. These variables can be your application variables as well as some predefined variables that are given below. You can also specify your application user values here such as firstname, lastname, email, uid, etc. in the application user class.

Predefined variables:

{{application_link}} – The application link that you can customize in application variables.
{{login_link}} – The link that your user may go to for logging into your application.

Predefined user variables:

{{user.email}} – User's email
{{user.first_name}} – User's first name
{{user.last_name}} – User's last name
{{user.uid}} – User's unique identifier
{{reset_password_link}} – The link generated by Built.io Backend for resetting the user's password
{{user.reset_password_token}} – The unique token that is needed for resetting the user's password

Retrieving reset password token using master key

The above section helps you understand how you can customize password reset email. Built.io Backend also allows you to send emails from your own SMTP server by customizing the SMTP settings.

However, there may be times, when, instead of Built.io Backend, you wish to send password reset email by yourself. In such cases, you will have to request Built.io Backend for user's password reset token, so that you, as an admin, can send the password reset mail.

In such cases, you can retrieve the password reset token for the user using your app's master key. To request the token, you need to make the following GET API call:

https://api.built.io/v1/application/users/{{user_uid}}/token

In the header, pass master_key along with the application_api_key.

This will help you retrieve the password reset token of the user. You can then attach this token to the password reset link, and send it to the user through your server.

If you notice, the API call mentioned above requires {{user_uid}}. However, when users request for password reset, you only have the user's email id, and not the uid. As a result, you will have to first retrieve the user's uid using his/her email id.

With Built.io Backend, you can also create your own custom password reset page, if you wish.

Custom password reset page:

Instead of using the default password reset page provided by Built.io Backend, you can host this page on your own server. Here's how to do it.

Usually, when an app user requests for password reset, Built.io Backend sends an email to the user with a link to a page, where he/she can change the password. Instead of this, you can direct the user to your own password reset page, by changing the link sent to the user.

However, please note that it is important to include the {{user.reset_password_token}} variable in the link. So, your new password reset link would look something like this:

http://yourdomain.com/reset_password/{{user.reset_password_token}}

Replace this link with the default link in the password reset mail, to direct users to your own page. You can find the password reset email template in Settings; Mail section of your app.

When the app user receives this email link, he/she will be directed to your custom password reset page. Here, the user will enter the new password and confirm password, and will click on 'Submit' button.

Now, before you request Built.io Backend to reset the password, you can also check whether the password reset token (available in the URL) is valid. To validate the token, make the following API call.

https://api.built.io/v1/application/users/forgot_password/validate_token

And query parameter as:
application_user[reset_password_token]:

If the token is valid, you need to make the following POST API call to request password reset to Built.io Backend:

https://api.built.io/v1/application/users/forgot_password/reset_password

And the body would be:

{
    "application_user": {
        "reset_password_token": "bltd7572c1908143f29606e7045",
        "password": "password",
        "password_confirmation": "password"
    }
}

Built.io Backend will then reset the password for the app user.

Uploads

If you want to store any files in Built.io Backend, such as images, documents, music, videos (or any other type), you can store it as an upload.

Uploads on Built.io Backend are similar to objects. Each upload object holds a file, and they have an unique uid.

Uploads can be used independently or along with objects. In this section, we will try to understand how you can create, update and delete objects. We will also learn how you can attach an upload with an object.

Creating

Here's how you can upload a file:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUpload *uploadObject = [builtApplication upload];
UIImage *image = [UIImage imageNamed:@"iu.png"];
[uploadObject setImage:image forKey:@"newBuiltImage"];
[uploadObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      //file successfully uploaded
      //uploadObject properties are populated
    }else {
      //error in uploading
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var uploadObject:BuiltUpload = builtApplication.upload()
let image : UIImage = UIImage(named: "iu.png")!
uploadObject.setImage(image, forKey: "newBuiltImage")
uploadObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if(error == nil){
      //file successfully uploaded
      //uploadObject properties are populated
    }else {
      //error in uploading
    }
}
// 'blt5d4sample2633b' is a dummy Application API key

BuiltApplication builtApplication   = Built.application(context, "blt5d4sample2633b");
BuiltUpload uploadObject     = builtApplication.upload();
 
// you may obtain the file path using the picker object.
// that is bundled with the built.io UI elements package.
// or you may use any third party picker like OI File Manager
uploadObject.setFile("/path/to/tiger.jpg");

uploadObject.save(new BuiltUploadCallback() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError builtError) {
            if(builtError == null){
                // uploaded successfully
                Log.i("builtTestCase", " " + builtFileObject.getUploadUrl());
            }else{
                // there was an error in uploading.
                // builtError will contain more details.
            }
    }
 
    @Override
    public void onProgress(int progress) {
        // If file is uploading then progress updates received in this callback.
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var upload = Built.App('blt5d4sample2633b').Upload();

/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 There are various ways through which we can set a file for upload
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
*/

/*
  For NodeJS environment
*/

// File path
upload = upload.setFile('/home/abc/Pictures/game-over.jpg');

// Instance of NodeJS buffer 
upload = upload.setFile({
  bytes: buffer,
  name: 'test.jpg',
  contentType: 'image/jpeg'
});

//base64 encoded data
upload = upload.setFile({
  base64: "V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE=",
  name: 'test.jpg',
  contentType: 'image/jpeg'
});

/*
  For Browser environment
*/

// byte representation of file
upload = upload.setFile({
  bytes: [0xBE, 0xEF, 0xCA, 0xFE],
  name: 'test.jpg',
  contentType: 'image/jpeg'
});

//base64 encoded data
upload = upload.setFile({
  base64: "V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE=",
  name: 'test.jpg',
  contentType: 'image/jpeg'
});

//Instance of File in Browser
upload = upload.setFile(fileObj)

//Instance of FormData in Browser
upload = upload.setFile(formData)

// HTML input element
upload = upload.setFile(document.getElementById('input_element'));

upload
.save()
.then(function(upload) {
  // do something here
}, function(error) {
  // some error has occurred
});
// This is the code snippet for 'Android'

// 'blt5d4sample2633b' is a dummy Application API key
BuiltUpload uploadObject = Built.App("blt5d4sample2633b").Upload();
// File path
uploadObject.SetFile("/path/to/tiger.jpg");
uploadObject.Save().ContinueWith(uploadTask =>
{
        if(uploadTask.IsFaulted)
        {
                // there was an error in uploading.
                // uploadTask.Exception.Flattern().InnerException will contain more details.
        }
        else
        {
                // uploaded successfully
        }
});

// This is the code snippet for 'iOS'

// 'blt5d4sample2633b' is a dummy Application API key
var imagePicker = new UIImagePickerController();
imagePicker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
imagePicker.MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary);
imagePicker.FinishedPickingMedia += (s, e) =>
        {
                imagePicker.DismissModalViewController(true);
                var filePath = e.Info.ObjectForKey(UIImagePickerController.ReferenceUrl);
                var str = filePath.ToString().Replace("ext=", "ext=.");
                var data = ImageToByteArray(e.OriginalImage);
                var builtUpload = Built.App("blt5d4sample2633b").Upload();
                builtUpload.SetFile(str);
                builtUpload.SetData(data);
                builtUpload.Save().ContinueWith(uploadsuccess =>
                {
                        if(uploadTask.IsFaulted)
                        {
                                // there was an error in uploading.
                                // uploadTask.Exception.Flattern().InnerException will contain more details.
                        }
                        else
                        {
                                // uploaded successfully
                        }
                });
        };
        imagePicker.Canceled += (s, e) =>
        {
                imagePicker.DismissModalViewController(true);
        };
        NavigationController.PresentModalViewController(imagePicker, true);
}
public byte[] ImageToByteArray(UIImage image)
{
        var nsdata = image.AsPNG();
        MemoryStream ms = new MemoryStream();
        nsdata.AsStream().CopyTo(ms);
        return ms.ToArray();
}
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: multipart/form-data" \
--form 'upload[upload]=@tiger.jpg' \
https://api.built.io/v1/uploads
RESPONSE:
{
    "notice": "Woot! File created successfully.",
    "upload": {
        "app_user_object_uid": null,
        "content_type": "application/octet-stream",
        "file_size": "8804",
        "uid": "blt8f238ce78dbc1c46",
        "url": '/assets/blt5b4c5aae0db41095/built_io_logo.png',
        "filename": "tiger.jpg",
        "ACL": null,
        "tags": []
    }
}

Updating an upload

Now let's update the file we just created (replacing the image with a new one):

// 'blt5d4sample2633b' is a dummy Application API key
// 'blt111sample2655c' is a uid of an upload in 'blt5d4sample2633b' application
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUpload *uploadObject = [builtApplication uploadWithUID:@"blt111sample2655c"];
UIImage *image = [UIImage imageNamed:@"newimage.png"];
[uploadObject setImage:image forKey:@"newBuiltImage"];
[uploadObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      //file successfully updated
      //uploadObject properties are populated
    }else {
      //error in uploading
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'blt111sample2655c' is a uid of an upload in 'blt5d4sample2633b' application
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var uploadObject:BuiltUpload = builtApplication.uploadWithUID("blt111sample2655c")
let image : UIImage = UIImage(named: "newimage.png")!
uploadObject.setImage(image, forKey: "newBuiltImage")
uploadObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if(error == nil){
      //file successfully updated
      //uploadObject properties are populated
    }else {
      //error in uploading
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'blt369bb5d2b25a70dc' is a dummy Uploaded file uid.

BuiltApplication builtApplication   = Built.application(context, "blt5d4sample2633b");
BuiltUpload uploadObject = builtApplication.upload("blt369bb5d2b25a70dc");
 
// you may obtain the file path using the picker object.
// that is bundled with the built.io UI elements package.
// or you may use any third party picker like OI File Manager
uploadObject.setFile("/path/to/tiger.jpg");

uploadObject.save(new BuiltUploadCallback() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError builtError) {
            if(builtError == null){
                // updated successfully
                Log.i("builtTestCase", " " + builtFileObject.getUploadUrl());
            }else{
                // there was an error in updating.
                // builtError will contain more details.
            }
    }
 
    @Override
    public void onProgress(int progress) {
        // If file is uploading then progress updates received in this callback.
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'blt111sample2655c' is a uid of an upload in 'blt5d4sample2633b' application
var upload = Built.App('blt5d4sample2633b').Upload('blt5d4sample1213b');

/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 There are various ways through which we can set a file for upload
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
*/

/*
  For NodeJS environment
*/

// File path
upload = upload.setFile('/home/abc/Pictures/game-over.jpg');

// Instance of NodeJS buffer 
upload = upload.setFile({
  bytes: buffer,
  name: 'test.jpg',
  contentType: 'image/jpeg'
});

/*
  For Browser environment
*/

//Instance of File in Browser
upload = upload.setFile(fileObj)

//Instance of FormData in Browser
upload = upload.setFile(formData)

// HTML input element
upload.addFile(document.getElementById('input_element'));

upload
.save()
.then(function(upload) {
  // do something here
}, function(error) {
  // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'blt369bb5d2b25a70dc' is a dummy Uploaded file uid.
BuiltUpload uploadObject = Built.App("blt5d4sample2633b").Upload("blt369bb5d2b25a70dc");

// File path
uploadObject.SetFile("/path/to/tiger.jpg");
uploadObject.Save().ContinueWith(uploadTask =>
{ 
        if(uploadTask.IsFaulted)
        {
                // there was an error in updating.
                // uploadTask.Exception.Flattern().InnerException will contain more details.
        }
        else
        {
                // updated successfully
        }
});
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: multipart/form-data" \
--form 'upload[upload]=@tiger2.jpg' \
https://api.built.io/v1/uploads/blt8f238ce78dbc1c46
RESPONSE:
{
    "notice": "Woot! File updated successfully.",
    "upload": {
        "app_user_object_uid": null,
        "content_type": "application/octet-stream",
        "file_size": "8804",
        "uid": "blt8f238ce78dbc1c46",
        "url": '/assets/blt5b4c5aae0db41095/built_io_logo.png',
        "filename": "tiger2.jpg",
        "ACL": null,
        "tags": []
    }
}

Deleting an upload

…and delete it:

//destroy a file object
// 'blt5d4sample2633b' is a dummy Application API key
// 'blt111sample2655c' is a uid of an upload in 'blt5d4sample2633b' application
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUpload *uploadObject = [builtApplication uploadWithUID:@"blt111sample2655c"];
[uploadObject destroy:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      //file deleted successfully
    }else {
      //error in uploading
    }
}];
//destroy a file object
// 'blt5d4sample2633b' is a dummy Application API key
// 'blt111sample2655c' is a uid of an upload in 'blt5d4sample2633b' application
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var uploadObject:BuiltUpload = builtApplication.uploadWithUID("blt111sample2655c")
uploadObject.destroy { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if(error == nil){
      //file deleted successfully
    }else {
      //error in uploading
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'blt369bb5d2b25a70dc' is a uid of an upload in 'blt5d4sample2633b' application

BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltUpload uploadObject = builtApplication.upload("blt369bb5d2b25a70dc");
 
uploadObject.destroy(new BuiltUploadCallback() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError builtError) {
            if(builtError == null){
                // upload deleted successfully
                Log.i("builtTestCase", " " + builtFileObject.getUploadUrl());
            }else{
                // there was an error in deleting.
                // builtError will contain more details.
            }
    }
 
    @Override
    public void onProgress(int progress) {
        // If file is uploading then progress updates received in this callback.
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'blt111sample2655c' is a uid of an upload in 'blt5d4sample2633b' application
var upload = Built.App('blt5d4sample2633b').Upload('blt5d4sample1213b');

upload
.delete()
.then(function() {
  // do something here
}, function(error) {
  // some error has occurred
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'blt369bb5d2b25a70dc' is a uid of an upload in 'blt5d4sample2633b' application
BuiltUpload uploadObject = Built.App("blt5d4sample2633b").Upload("blt369bb5d2b25a70dc");

uploadObject.Delete().ContinueWith(uploadTask =>
{
        if(uploadTask.IsFaulted)
        {
                // there was an error in deleting.
                // uploadTask.Exception.Flattern().InnerException will contain more details.
        }
        else
        {
                // upload deleted successfully
        }
});
curl -i -X DELETE \
-H "application_api_key: blt5d4sample2633b" \
https://api.built.io/v1/uploads/bltfec904928e289e1f
RESPONSE:
{
  "notice":"Woot! File deleted successfully."
}

Attaching with objects

While uploads can be used independently, they can be attached to objects as well. Attaching an upload to an object is a simple process. While adding a field in a class, remember to set the datatype as 'File'. Now when you create an object, you can enter the upload's uid as input. That's it. The upload is attached to that object.

For our project, we want to allow users to attach files (such as screenshots) to bugs. Let's add a file field to the "Bug" class. Through the management interface, edit the "Bug" class and click on the "Add Field" button. Add the field:

Attach upload to object.

We mark it as 'multiple', so that you can attach multiple files on a bug. Here, 'multiple' means that this is an array of upload uids. Add the field, and click the 'Update' button to update the class.

We'll now attach the 'tiger.jpg' file to a bug:

// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is uid of an class on built.io
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltObject *bugObject = [bugsClass object];
 
// 'blt5d4sample1213b' is a uid of an upload in 'blt5d4sample2633b' application
bugObject[@"attachments"] = @["blt5d4sample1213b"];
 
// ... add name, and project reference and other properties if required
 
[bugObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'bugs' is uid of an class on built.io
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugObject:BuiltObject = bugsClass.object()
 
// 'blt5d4sample1213b' is a uid of an upload in 'blt5d4sample2633b' application
bugObject["attachments"] = ["blt5d4sample1213b"]
 
// ... add name, and project reference and other properties if required
 
bugObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'bugs' is a uid of a class on built.io

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltObject bugObject = builtApplication.classWithUid("bugs").object();
 
// ... add name, and project reference…
bugObject.set("attachments", new String[] {"blt8f238ce78dbc1c46"});
 
bugObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
        
      if(error == null){
               // object is created successfully
 
      }else{
               // some error has occurred.
               // refer to the 'error' object for more details.
      }
 
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns a Object constructor
// 'bugs' is uid of an class on built.io
var Bugs = Built.App('blt5d4sample2633b').Class('bugs').Object;
var bug = Bugs();

// 'blt5d4sample1213b' is a uid of an upload in 'blt5d4sample2633b' application
bug = bug.assign({
  attachments: ['blt5d4sample1213b']
});

// ... add name, and project reference...
obj
.save()
.then(function(bug) {
  // object created successfully
  console.log(bug.toJSON())
}, function(error) {
  // some error has occurred
  // refer to the "error" object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class("class_uid").Object() returns an 'BuiltObject' instance.
// 'bugs' is a uid of a class on built.io

BuiltObject bugObject = Built.App("blt5d4sample2633b").Class("bugs").Object();

// ... add name, and project reference…
bugObject["attachments"] = new String[] {"blt8f238ce78dbc1c46"};

bugObject.Save().ContinueWith(uploadTask =>
{
        if(uploadTask.IsFaulted)
        {
                // some error has occurred.
                // refer to the uploadTask.Exception.Flattern().InnerException for more details.
        }
        else
        {
                // object is created successfully
        }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
    "object": {
        "attachments": [
            "blt8f238ce78dbc1c46"
        ]
    }
}' \
https://api.built.io/v1/classes/bugs/objects
RESPONSE:
{
    "notice": "Object created successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "name": "...",
        "description": "...",
        "project": [
            "..."
        ],
        "attachments": [
            {
                "app_user_object_uid": null,
                "content_type": "application/octet-stream",
                "file_size": "8804",
                "uid": "blt8f238ce78dbc1c46",
                "url": '/assets/blt5b4c5aae0db41095/built_io_logo.png',
                "filename": "tiger2.jpg",
                "ACL": null,
                "tags": []
            }
        ],
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Once the file is attached, whenever you retrieve the Bug object, you will receive the upload (file) object along with it.

The advantage with this setup is that the uploads can be updated independently of the objects. When you update the upload with a new file, the object that the upload is attached to will also receive the new file since it is just a reference to that upload. This allows for great flexibility in updating content.

Issues with cross-domain uploads

We recognize that there will be issues when you try to post files cross domain, especially with the Internet Explorer browser. Read the Cross Domain Section for more details.

Security

To ensure security of your app data, Built.io Backend provides Access Control List (ACL). ACL is a set of permissions that you can attach to your app's user data. These rules define how users in Built.io Backend share their data with other users, or the outside world. It is a way to ensure the security of your user data.

ACL opens up a set of possibilities for many different types of apps. It is a basic requirement for many applications, and it fundamentally affects an app's behavior. Let us try to understand ACLs in detail.

Class-level ACL (Default ACL)

When you create a class with Built.io Backend, you can define who gets to do what in this class. You can assign Read, Create, Update and Delete permissions on class level by configuring default ACL. The permissions you set here will be applicable on all the objects of this class. By default, Create and Read permissions are set as true whenever you create a new class. So, users can create objects in and view objects of this class. You can change this ACL any time.

Let us understand how this works. When you create a new class, in step 3, you will notice an option called 'Default Permissions: Access control list (ACL)'. Click on 'Click here to configure default permissions' to change the ACL settings of this class.

Class-level ACL

You will notice that there are three sections under Configure Default ACL: Users, Roles, and Everyone else

Class-level ACL Modal

Let us understand all the three sections in detail.

Users: Here, you can add users and assign permissions for this class. Under 'Add More Users', type the email id of a user; select the permissions you want to assign to the user; and click on 'Add to List'. You will then see the name of the added user in the 'Who has access' section. So, if, for instance, you add a user John to this list and assign Create, Read, Edit, and Delete permissions to John, he will be able to:

  • Create new objects in this class
  • Get all the objects in this class 
  • Edit or make changes to all the objects in this class
  • Delete any objects from this class.

Similarly, you can keep adding users, and assign permissions to the users. For your convenience, we have already created a special group called 'Anonymous Users' for all the unregistered users of your app. By just entering 'Anonymous' in the Add More Users field, you can define the permissions for all anonymous users of your app. You can set ACL for anonymous users using the SDK as well. Read more about Anonymous Users here.   

Roles: While you can set ACL for each user one by one using the above method, the process may get extremely tiresome if the number of users is large. In such cases, you can use Roles. A Role is a group of users to which you can assign common permissions. Let's say you have 50 app users, and you want only 20 users to Read and Update objects in this class. In such cases, instead of manually assigning Read and Update permission to the 20 users, you can create a role (a group of users) and assign the permissions to that group. 

Remember that to be able to assign permissions to a Role, you will have to create a Role first. Later, in the Roles section, we will learn how to create roles using the SDK as well as the management console. 

Everyone else: As the name suggests, this includes all the users who are not added under Users and Roles in Configure Default ACL. In the above example, we had added 20 users (out of total 50 users) in a Role, and had assigned Read and Update permission to these users. So, if you assign only Read permission to Everyone Else, it would be applicable to the rest of the 30 users of your app and anonymous users.

However, it is important to remember that these three levels of ACL follow a hierarchy. The permission set for Users override those applied for Roles. Likewise, the permission applied for roles override those applied for Everyone else. The hierarchy is Users > Roles > Everyone else. This means that if you have added a user in any two or more of these ACL levels, then that user will get the permissions assigned under Users first. If he/she is not present in Users, then ACL under Roles will be applicable, and than that of Everyone Else.

To understand this hierarchy better, let us consider an example. Let's say a user 'John' has been added to a Role called 'Superstars' that has Read permission in a class. This will allow John, along with other users of Superstar, to read all the objects in that class. However, if John is specifically assigned "read": false on in Users, then he won't be able to read any objects of that class, even though he is part of Superstars that allows him to Read.

Since we now know how ACLs work, let's try it out with our Projects-On-The-Go app. As mentioned earlier, when you create a class, the default ACL is set such that everybody can Create and Read objects. This means that anyone (including anonymous non-logged-in users) can read everyone else's objects, and create new objects of their own.

Let's try this by adding a default ACL for the bugs class. In case of bugs, tasks and milestones, we don't want anonymous users (those who are not logged in) to create, read, or modify them. However, we want everyone else (those who are logged in) to create them. So in Built.io Backend, head over to the classes section and edit the Bug class. In 'Step 3: Configure', go to Default Permissions ACL, and add 'anonymous' in users. Uncheck all permissions and click on 'Add to list':

Anonymous User

Next, go to the 'Everyone else' tab and assign only the create permission:

Everyone else

That's it, and now update the class. Henceforth, all objects created in this class will receive those permissions. Note that the default permissions are overridden if that object has a different ACL. You can also set default ACLs on uploads. Go to the uploads section and select Configure Default ACL:

Configure Default ACL Button

You can then configure it in the exact same way as classes.

Object-level ACL

In the earlier section, we saw that if you assign certain permissions at class level, it is applied to all the objects of that class. However, Built.io Backend also gives you the option to assign permissions to a particular object. 

You specify ACL for an object by updating its ACL parameter, or by specifying ACL when you create the object. The ACL parameter can only be updated by the owner of the object, and no one else. Here's an example for a project, to update the ACL to enable any user to fetch (read) the object:

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
 
// 'bltf4fbbsample851db' is a uid of an object of 'project' class
BuiltObject *projectObject = [projectClass objectWithUID:@"bltf4fbbsample851db"];
 
BuiltACL *aclObject = [builtApplication acl];
[aclObject setPublicReadAccess:true];
 
[projectObject setACL:aclObject];
 
[projectObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
 
 
// Alternatively, use the "eventually" format to save it when network is available:
 
[projectObject saveEventually:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
 
// 'bltf4fbbsample851db' is a uid of an object of 'project' class
var projectObject:BuiltObject = projectClass.objectWithUID("bltf4fbbsample851db")
 
var aclObject:BuiltACL = builtApplication.acl()
aclObject.setPublicReadAccess(true)
projectObject.ACL = aclObject
 
projectObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltObject projectObject     = builtApplication.classWithUid("project").object();
 
BuiltACL aclObject = builtApplication.acl();
aclObject.setPublicReadAccess(true);
projectObject.setACL(aclObject);
 
projectObject.save(new BuiltResultCallBack() {
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
        if(error == null){
            // object is created successfully
        }else{
            // some error has occurred.
            // refer to the 'error' object for more details.
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns a Object constructor
// 'project' is a uid of a class on Built.io Backend
var Project = Built.App('blt5d4sample2633b').Class('project').Object;

// 'bltf4fbbsample851db' is a uid of an object of 'project' class
var project = Project('bltf4fbbsample851db');
var acl = Built.ACL();

acl = acl.setPublicReadAccess(true);
project = project.setACL(acl);

project
.save()
.then(function(project) {
  // object updated successfully
  console.log(project.toJSON())
}, function(error) {
  // some error has occurred
  // refer to the "error" object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class("class_uid").Object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend
// 'bltf4fbbsample851db' is a uid of an object of 'project' class

BuiltObject projectObject = Built.App("blt5d4sample2633b").Class("project").Object().SetUid("bltf4fbbsample851db");


var aclObject = Built.Acl();
aclObject.SetPublicReadAccess(true);
projectObject.SetAcl(aclObject);
projectObject.SetHeader("authtoken", "blt1dc2639741245481e7b48eca");
projectObject.Save().ContinueWith(objectTask =>
{
        if(objectTask.IsFaulted)
        {
                // some error has occurred.
                // refer to the objectTask.Exception.Flattern().InnnerException for more details.
        }
        else
        {
                // object is updated successfully
        }
});
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "object": {
          "ACL": {
              "others": {
                  "read": true
              }
          }
      }
  }' \
https://api.built.io/v1/classes/project/objects/bltf4fbbc94e8c851db
RESPONSE:
{
    "notice": "Object updated successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "name": "Super Project #41!",
        "description": "We use this project internally",
        "updated_at": "2015-02-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": [
                "update",
                "delete"
            ],
            "others": {
                "read": true
            }
        },
        "tags": []
    }
}

Now, when any user gets the list of projects, this specific project will be included as well.

It is important to note that Object-level ACLs override those applied for Class-level ACL. Also, any object created by a user belongs to that user. This means the creator has all the permissions on the object, and these permissions cannot be overridden by any other ACLs. 

Anonymous Users

The ACL in Built.io Backend applies to the users in the application. But what if we want the outside world (i.e. anonymous users who are not logged in the application) to have an ACL as well? A typical example of this is a Blog, in which the posts are publicly visible, even to a person who is not registered or logged into the blogging system. Built.io Backend allows you to specify such ACLs with the concept of 'anonymous users'.

Any user who is not logged into the system is treated as an Anonymous User. Since ACL is a whitelisting system, all anonymous users have no permissions by default to read, write or delete other user's objects. To specify an ACL for an Anonymous User, we have a special user uid, 'anonymous'. Using this uid, we can assign permissions to anonymous users. Here's an example where we assign the read: true permission for an anonymous user (as would be the case with a blogging application):

// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *projectClass = [builtApplication classWithUID:@"project"];
 
// 'bltf4fbbsample851db' is a uid of an object of 'project' class
BuiltObject *projectObject = [projectClass objectWithUID:@"bltf4fbbsample851db"];
 
BuiltACL *aclObject = [builtApplication acl];
[aclObject setWriteAccess: true forUserId:@"anonymous"];
 
[projectObject setACL: aclObject];
 
[projectObject save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // object is created successfully
    } else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
// 'project' is a uid of a class on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var projectClass:BuiltClass = builtApplication.classWithUID("project")
 
// 'bltf4fbbsample851db' is a uid of an object of 'project' class
var projectObject:BuiltObject = projectClass.objectWithUID("bltf4fbbsample851db")
 
var aclObject:BuiltACL = builtApplication.acl()
aclObject.setWriteAccess(true, forUserId: "anonymous")
projectObject.ACL = aclObject
 
projectObject.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'classWithUid("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltObject projectObject = builtApplication.classWithUid("project").object();
 
BuiltACL aclObject = builtApplication.acl();
aclObject.setUserWriteAccess("anonymous", true);
projectObject.setACL(aclObject);
 
projectObject.save(new BuiltResultCallBack() {
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
          if(error == null){
            // object is created successfully
          }else{
            // some error has occurred.
            // refer to the 'error' object for more details
          }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns a Object constructor
// 'project' is a uid of a class on Built.io Backend
var Project = Built.App('blt5d4sample2633b').Class('project').Object;

// 'bltf4fbbsample851db' is a uid of an object of 'project' class
var project = Project('bltf4fbbsample851db');
var acl = Built.ACL();

// 'anonymous' is a keyword in built.io which refers to non-logged-in users.
acl = acl.setUserUpdateAccess('anonymous', true);
project = project.setACL(acl);

project
.save()
.then(function(data) {
  // object updated successfully
}, function(error) {
  // some error has occurred
  // refer to the "error" object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class("class_uid").object() returns an 'BuiltObject' instance.
// 'project' is a uid of a class on Built.io Backend
BuiltObject projectObject = Built.App("blt5d4sample2633b").Class("project").Object();

 
var aclObject = Built.Acl();
aclObject.SetUserUpdateAccess("anonymous", true);
projectObject.setACL(aclObject);
 
projectObject.Save().ContinueWith(objectTask =>
{
        if(objectTask.IsFaulted)
        {
                // some error has occurred.
                // refer to the objectTask.Exception.Flattern().InnnerException for more details.
        }
        else
        {
                // object is updated successfully
        }
});
curl -i -X PUT \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "object": {
          "ACL": {
              "users": [
                  {
                      "uid": "anonymous",
                      "read": true
                  }
              ]
          }
      }
  }' \
https://api.built.io/v1/classes/project/objects/bltf4fbbc94e8c851db
RESPONSE:
{
    "notice": "Object updated successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "name": "Super Project #41!",
        "description": "We use this project internally",
        "updated_at": "2015-02-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": [
                "update",
                "delete"
            ],
            "users": [
                {
                    "uid": "anonymous",
                    "read": true
                }
            ]
        },
        "tags": []
    }
}

Of course, anonymous users can be assigned roles and treated just like any other user within the ACL. Note that setting permissions in others will also assign the same to an anonymous user unless the anonymous user is given a different permission.

Uploads

Uploads also enjoy the same ACL support as objects. Any upload created by a user belongs to that user. The user then has to supply the appropriate ACLs to the upload in order to allow others to access it.

It is important to note that the upload assumes the ACL of an object once it is attached to an object.  The URL returned in such upload objects are different from the regular upload URLs. So, for instance, if an upload with a restrictive ACL is attached to an object which is publicly accessible, then the upload becomes publicly accessible as well, under the object. There are two different URLs at play here, one with restrictive access, and the other with public access.

Roles

With complex apps, managing ACLs for each and every user in the system can become unwieldy. Consider this situation: you are building a social network. Users in your application has other users as 'friends'. Your friends need the permission to view your content (posts, etc) so you give them permission using the users key. However, when a new friend is added to your list, you would need to update all your objects to add his uid into the users key. This is obviously not a good idea.

The solution is roles. Roles are a sort of group containing users and other roles. So instead of giving permission to each user as they become your friend, you could instead add those users to the 'Friends' role, and assign permissions to the role. All users in the role then inherit the permissions assigned to the role.

Roles are a special class inside Built.io Backend. To create, update or retrieve roles, one would use the same APIs as those of classes and objects. The role class uid is: built_io_application_user_role. Here's an example of how to create a role, and add a user to it:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltRole *role = [builtApplication roleWithName:@"Managers"];
// 'app_f4fbbc94e8SaMpLeUid4e8' is a uid of an object of inbuilt 'Application User Role' class
[role addUser:@"app_f4fbbc94e8SaMpLeUid4e8"];
[role save:^(BuiltResponseType responseType, NSError *error) {
    if(error == nil){
      // role is created successfully
    } else {
      // there was an error in creating the role
      // error.userinfo contains more details regarding the same
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var role:BuiltRole = builtApplication.roleWithName("Managers") 
// 'app_f4fbbc94e8SaMpLeUid4e8' is a uid of an object of inbuilt 'Application User Role' class
role.addUser("app_f4fbbc94e8SaMpLeUid4e8") 
role.save { (responseType:BuiltResponseType, error:NSError!) -> Void in
    if (error == nil) {
      // object is created successfully
    }else {
      // there was an error in creating the object
      // error.userinfo contains more details regarding the same
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns a Object constructor
// 'Application User Role' class on built.io

BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltRole role                    = builtApplication.roleWithName("Managers");

role.addUser("app_f4fbbc94e8SaMpLeUid4e8");

role.save(new BuiltResultCallBack() {
      @Override
      public void onCompletion(BuiltResponseType responseType, BuiltError error) {
            if(error == null){
                // object is updated successfully
            }else{
                // there was an error in creating the role.
                // refer to the 'error' object for more details
            }
      }
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name').Object returns a Object constructor
// 'Built.Constants.APP_ROLE_CLS' refers to an inbuilt 'Application User Role' class on built.io
var Role = Built.App('blt5d4sample2633b').Class(Built.Constants.APP_ROLE_CLS).Object;
var role = Role();

role = role.setName('Managers');

// 'app_f4fbbc94e8SaMpLeUid4e8' is a uid of an object of inbuilt 'Application User Role' class
role = role.addUser('app_f4fbbc94e8SaMpLeUid4e8')

role
.save()
.then(function(role) {
  // object created successfully
  console.log(role.toJSON())
}, function(error) {
  // some error has occurred
  // refer to the "error" object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
// 'Class('class_name') returns a Object constructor
// 'Application User Role' class on built.io
BuiltClass builtClass = Built.App("blt5d4sample2633b").Class("built_io_application_user_role");
var role = builtClass.Object();
role["name"] = "Managers";
role["users"] = "app_f4fbbc94e8SaMpLeUid4e8";

role.Save().ContinueWith(roleTask=>
{
    if(roleTask.IsFaulted)
{
       // there was an error in creating the role.
      // refer to the roleTask.Exception.Flattern().InnerException for more details
    }   
else
{
         // object is created successfully
    }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "object": {
          "users": [
              "app_f4fbbc94e8SaMpLeUid4e8"
          ],
      }
  }' \
https://api.built.io/v1/classes/built_io_application_user_role/objects
RESPONSE:
{
    "notice": "Object created successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "users": [
            "app_bltbcbbb4730c4af8f1"
        ],
        "updated_at": "2013-06-19T09:02:02Z",
        "created_at": "2013-06-19T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Alternatively, you can also create Roles using the management console. Go to Classes > System Classes > Application User Role, and click on 'New Object'. Here, you can enter the required details, and create a Role. This Role will the then visible when you configure default ACL in a class.

Application User Role Mapper

With roles, the need to manually assign permissions to each user separately was eliminated. So, with the addition of a new user, one just needed to add the user UID into the ‘users’ field of the concerned role, and the user automatically inherited the permissions assigned to that particular role. However, as the number of users increased, this process of adding users within the respective role classes too became tedious. For example, if a company has done mass recruitment of employees, where they’ve recruited a few senior managers, some team leaders, and many employees of the executive level, it becomes really challenging to manually keep adding users under their respective role class.

Along with these external concerns, an internal concern was encountered too. Firstly, each time a new user was added, their details were stored within the ’users’ field of the concerned role class. However, as the ‘users’ field is an array, it has storage limitations.

So, to solve this difficulty, the ‘users’ field from the Role class was removed and a separate ‘built_io_application_user_role_mapper’ class was introduced in Built.io Backend version 3.1, which eliminated these concerns to a great extent

Now, let’s see the schema of the ‘built_io_application_user_role_mapper’ class:

Application User Role Mapper

Application User Role Mapper Class

In this schema, ‘role_uid’ and ‘user_uid’ are reference fields that refer to the Application User Role ‘built_io_application_user_role’ and Application User ‘built_io_application_user’ classes, respectively.

The ‘built_io_application_user_role_mapper’ class is a built-in class that maintains a key-value type relation between a user UID and role UID. Now, if a user-to-role mapping is added into the ‘built_io_application_user_role_mapper’ class, the user automatically inherits the permissions and the restrictions assigned to that role.

Since this class is built-in, the schema of this class cannot be modified and the data that falls under it are maintained separately. This structure tremendously reduces the load on the memory. The biggest advantage of maintaining a separate class is that it can store limitless role-to-user mappings as well as it is fully queryable like any other class on Built.io Backend. For example, if the company needs to get a count of all employees who fall in the senior manager role, they can just query the table.

Adding a new object in Application User Role

Assigning an application user to an application user role is fairly simple and can be performed via two methods provided by Built.io Backend – Add Manually and Make Query.

When the number of users are fewer, the ‘Add Manually’ option may seem feasible to use.

Create Application User Role Mapper

However, if the number of users is enormous, the ‘Make Query’ option should be used.

Make Query Option 

Note: While updating a role, you can enable the ‘Users’ field if you wish to reassign a new set of users to an existing role.

When we start adding a role using the management console. Enter the users either manually or by using query. However, adding users while creating a role has its limitations; at any instance, you can add only the threshold number of users. However, if there’s a need to add more users, this can be done by adding objects under Application User Role Mapper class. You can add unlimited such objects under the Application User Role Mapper class.

Note: Built.io Backend has set a threshold value of 15000 users. A threshold value has been set because adding a large number of users at a single instance can take a toll on the memory.

If there’s a need to update a role, the process is very similar to that of role creation but with a small difference. On updating a role, all the previously existing role-to-user mappings are deleted and all the users which satisfy the new query condition are re-assigned to this role. Once again, only a threshold value of 15000 users are allowed.

Finally, when an Application Role is deleted, all the role-to-user mappings that are linked to that role gets deleted automatically.

Master Key

Built.io Backend ACL allows you to set finegrained access controls on your data. While this works most of the time, you will still want to roll out your own access control techniques in some situations.

Master Key allows you to override all ACLs that are set in an application. Each application comes with its own secret Master Key, which can be used along with any call made to Built.io Backend. Using the Master Key in such a call ensures that you have carte blanche on every resource.

For example, you may have disallowed anonymous (non-logged in) users permission to create an object. If such a call was made with the Master Key, they will be allowed access.

With great power comes great responsibility, and hence, its necessary to secure the Master Key against disclosure. Take care to never expose the Master Key on the client side. Use Master Key solely on the server side, or in Built Extension code.

Locating the Master Key

In the management console, click on 'Settings' in the left panel, and select 'Download and info.'. Here, you will find the Master Key listed under the 'Application Keys' section:

Master Key

Using the Master Key

There are two ways of using it - via the JavaScript SDK and the REST API.

The JavaScript SDK provides the setMasterKey method to use the Key for a certain call. You may use the JavaScript SDK in Built Extension code, or in your own custom server side code.

To use it in the REST API, simply send the header master_key along with the call.

The following snippet illustrates creating an object along with the Master Key:

// 'blt5d4sample2633b' is a dummy Application API key
// 'blt48f2deca473xxxxx' is an masterkey 
// 'Class('class_name').Object returns a Object constructor
// 'Built.Constants.APP_ROLE_CLS' refers to an inbuilt 'Application User Role' class on Built.io Backend

var appWithMasterKey = Built.App('blt5d4sample2633b').setMasterKey('blt48f2deca473xxxxx');

var Project = appWithMasterKey.Class('project').Object

var project = Project({
    name       : "Super Project #41!",
    description: "This is a very cool project"
})
 
project
.save()
.then(function(project) {
  // object created successfully
  console.log(project.toJSON())
}, function(error) {
  // some error has occurred
  // refer to the "error" object for more details
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "master_key: blt48f2deca473xxxxx"
-H "Content-Type: application/json" \
-d '{
      "object": {
          "name": "Super Project #41!",
          "description": "This is a very cool project"
      }
  }' \
https://api.built.io/v1/classes/project/objects
RESPONSE:
{
    "notice": "Object created successfully",
    "object": {
        "published": true,
        "uid": "bltf4fbbc94e8c851db",
        "name": "Super Project #41!",
        "description": "This is a very cool project",
        "updated_at": "2015-01-10T09:02:02Z",
        "created_at": "2015-01-10T09:02:02Z",
        "ACL": {
            "can": []
        },
        "tags": []
    }
}

Field-level access controls

A handy use case for using the Master Key is to achieve custom field level permissions for objects. You may recall that ACL provides access control mechinisms for restricting access to an object. You can control access to update or delete a certain object. However, restricting access to a single field in the object is not supported using ACL.

A common scenario would be a Blog application, with a 'Post' class encapsulating all your blog posts. Now, you would want people to leave comments on the posts, and therefore a 'comments' field would be appropriate. However, here's the catch: to allow others to add comments, you would also need them to have update permission on the Post object. This is a security hole, since anyone will also be able to edit Post's content as well.

Using Master Key, and Built Extensions, you can setup a fairly simple solution for this problem. First, we create an Extension function that accepts a Post uid, and a comment. Using the Master Key, you can override the ACL on the post that disallows everyone but the owner to edit the object. Thus, we are now able to add just a comment to the post, without affecting the other fields. The below snippet illustrates this:

// We need to require built.io package in extension
var BuiltSDK = require('built.io');

// this ensures we can update the post, regardless of ACL
var masterKey = 'blt48f2deca473xxxxx';

// 'blt5d4sample2633b' is a dummy Application API key
var App = BuiltSDK.App('blt5d4sample2633b')

// 'post' is uid of a class on built.io
var Post = App.setMasterKey(masterKey).Class('post').Object;

Built.Extension.define('addComment', function(request, response) {

    var post = Post(request.params.post_uid);

    // 'comments' is a uid of a field in 'post' class
    post = post.pushValue('comments', request.params.comment);
    post.save()
        .then(function(data) {
            return response.success('Added the comment!');
        }, function(error) {
            return response.error('comment', 'could not be added');
        })
});

Now, in the client side code, you can safely add comments:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
//'addComment' is extension name
BuiltExtension *extensionObject = [builtApplication extensionWithName:@"addComment"]; 
[extensionObject executeWithData:@{@"post_uid": @"xxx", @"comment": @"xxx"} completion:^(BuiltResponseType responseType, id responseObject, NSError *error) {
    if (error == nil) {
        // added the comment
        // response will contain the response of the extension method
    }else {
        // error in case of any error
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
//'addComment' is extension name
var extensionObject:BuiltExtension = builtApplication.extensionWithName("addComment") 
extensionObject.executeWithData(["post_uid":"xxx","comment":"xxx"], completion: { (responseType, responseObject, error) -> Void in
    if (error == nil) {
        // response will contain the response of the extension method
        // here, the response is the user profile, with the authtoken
    }else {
        // error in case of any error
    }
})
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication= Built.application(context,"blt5d4sample2633b");
BuiltExtension extensionObject   = builtApplication.extension();
 
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("post_uid", "xxx");
hashMap.put("comment", "xxx");
 
extensionObject.execute("addComment", hashMap, new BuiltExtensionCallback() {
    @Override
    public void onCompletion(BuiltResponseType resType, Object object, BuiltError error) {
 
        if(error == null){
            Log.i("BuiltExtension", "finish-response|"+response);
        }else{
            // there was an error in executing extentation.
            // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var app = Built.App('blt5d4sample2633b');

app.Extension.execute('addComment', {
  post_uid: 'xxx',
  comment: 'xxx'
})
.then(function(result) {
  // do somethings
}, function(error) {
  // some error has occurred
  // refer to the "error" object for more details
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication= Built.App("blt5d4sample2633b");
BuiltExtension extensionObject   = builtApplication.Extension();


extensionObject["post_uid"] =  "xxx";
extensionObject["comment"] ="xxx";

extensionObject.Execute("addComment").ContinueWith(extensionTask=>
{
        if(extensionTask.IsFaulted)
        {
                // there was an error in executing extentation.
                // refer to the extensionTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // extensionTask.Result will contain the response of the extension method
        }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "post_uid": "xxx",
      "comment": "xxx"
   }' \
https://api.built.io/v1/functions/addComment
RESPONSE:
{
    "result": "Added the comment!"
}

Real-time

Depending on the way the content is presented to users, apps can be classified under two broad categories: http-based apps and real-time apps.

http-based apps are simple, information-only apps. Content changes only when the user requests for information by clicking a button or reloading a page.

Real-time apps, on the other hand, are far more engaging and dynamic. These apps push content to users instantly, as events happen. A classic example of real-time functionality is a chat messenger, where users are notified instantly when a message is received, read the message without having to refresh the page and see when buddies are typing messages.

With real-time apps, possibilities are endless. Using this functionality, you can create apps that allow you to edit documents together, play multiplayer games online, get traffic updates or locate a taxi near you instantly. And creating such responsive apps is quite simple with Built.io Backend.

Built.io Backend service integrates real-time functionality enabling you to build collaborative and responsive apps instantly using just the client-side code. When any changes are made to 'classes' or 'objects', apps are updated instantly, and users are notified without any latency. While Built.io Backend offers a number of real-time events that can be readily used, it also allows you to define your own events and customize your app accordingly. 

What's more?

Built.io Backend offers a unique Presence feature that notifies you about users' status (online/offline), status message (custom display message), and 'last seen' (time of last activity). It also allows users to customize a lot of their presence attributes and manage their privacy settings.  

Enabling real-time in your app

Once your app interface is ready, you will have to enable real-time in your app by establishing a socket connection. This can be done using just a few lines of code given below. 

// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
[builtApplication enableRealtimeWithDelegate:self];
// For custom domain
// Create BuiltConfig object and pass it to builtApplication.
BuiltConfig *config = [[BuiltConfig alloc] init];
config.realtimeSSL = true;
config.realtimeHost = @"realtime.built.io"; //your custom domain for realtime
config.realtimePort = 443; //your custom port for realtime BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b" withConfig:config]; [builtApplication enableRealtimeWithDelegate:self];
// 'blt5d4sample2633b' is dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
builtApplication.enableRealtimeWithDelegate(self)

// For custom domain
// Create BuiltConfig object and pass it to builtApplication.
var config:BuiltConfig = BuiltConfig()
config.realtimeSSL = true
config.realtimeHost = "realtime.built.io" //your custom domain for realtime
config.realtimePort = 443  //your custom port for realtime
 var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b" withConfig:config)
builtApplication.enableRealtimeWithDelegate(self)
// If class level implementation is present of RealTimeCallback interface.
public class MainActivity implements BuiltRealTimeCallback{
 
// enableRealtime function on execution initiates socket connection.
// 'blt5d4sample2633b' is dummy Application API key.
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
/*Interface will add three functions as a connection handler.*/
}
 
//Method level implementation [Optional]
 
// enableRealtime function on execution initiates socket connection.
// 'blt5d4sample2633b' is dummy Application API key.
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(new BuiltRealTimeCallback() { .... });
// enableRealtime function on execution initiates socket connection 
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

Connection handlers

The SDK allows you to listen to connection, reconnection, disconnection, and connection error events. You may accordingly define the message that will be visible to the users whenever any of the above-mentioned events occur.

//Built Realtime delegate method
 
-(void)builtRealtimeApplicationWillConnect:(BuiltApplication*)builtApplication; {
    //When application is about to connect.
}
 
-(void)builtRealtimeApplicationDidConnect:(BuiltApplication*)builtApplication; {
    //When application is connected.
}
 
-(void)builtRealtimeApplicationWillDisconnect:(BuiltApplication*)builtApplication; {
    //When application is about to disconnect.
}
 
-(void)builtRealtimeApplicationDidDisconnect:(BuiltApplication*)builtApplication; {
    //When application is disconnected.
}
 
-(void)builtRealtimeApplication:(BuiltApplication*)builtApplication didReceivedError:(NSError*)error; {
    //When application receives any error in connection.
}
 
-(void)builtRealtimeApplicationWillReconnect:(BuiltApplication*)builtApplication; {
    //When application is trying to reconnect. After sucessful reconect attempt builtRealtimeApplicationDidConnect: will get invoke.
}


//Built Realtime delegate method
 
func builtRealtimeApplicationWillConnect(builtApplication: BuiltApplication!) {
    //When application is about to connect.
}
 
func builtRealtimeApplicationDidConnect(builtApplication: BuiltApplication!) {
    //When application is connected.    
}
 
func builtRealtimeApplicationWillDisconnect(builtApplication: BuiltApplication!) {
    //When application is about to disconnect.    
}
 
func builtRealtimeApplicationDidDisconnect(builtApplication: BuiltApplication!) {
    //When application is disconnected.    
}
 
func builtRealtimeApplication(builtApplication: BuiltApplication!, didReceivedError error: NSError!) {
    //When application receives any error in connection.
}
 
func builtRealtimeApplicationWillReconnect(builtApplication: BuiltApplication!) {
    //When application is trying to reconnect. After sucessful reconect attempt builtRealtimeApplicationDidConnect: will get invoke.    
}
//Set configuration for realtime.
BuiltConfig config = new BuiltConfig();
config.setRealTimeURL("realtime.built.io", true);
config.setRealTimePort(443);

// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b", config);
builtApplication.enableRealTime(context);
 
 
// To get notified when the realtime connection/reconnection is established.
@Override
public void onRealtimeConnect(BuiltApplication application) {
    //handle connection and reconnect.
}
 
// To get notified when the realtime go for reconnecting
@Override
public void onRealtimeWillReconnect(BuiltApplication application) {
    //handle reconnection attempt.
    //after successful reconnect onRealtimeConnect() called.
}
 
// To get notified when the realtime is disconnected
@Override
public void onRealtimeDisconnect(BuiltApplication application) {
   //handle disconnection.
}
 
 
// To get notified when the realtime error occured.
@Override
public void onRealtimeError(BuiltApplication application, BuiltError builtError) {
    //handle realTime connection Error
}
// To get notified when the socket connection is established use the code below
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

app.on('connect', function() {
  // Handle connection
});

app.on('reconnect', function() {
  // Handle reconnection
});

app.on('disconnect', function() {
  // Handle disconnection
});

app.on('error', function(error) {
  console.log(error);
});

Events

Whenever an object or upload is created, updated or deleted in a class, an event describing this activity is emitted in real time. Before we get started with enabling this feature in your app, let's quickly understand the two broad categories of events: generic and specific.

Generic events

Users can listen to any changes made to any object or upload in a given class in real time. In our sample Projects-On-The-Go app, this feature could be very useful. Your app users, for instance, can choose to get notified about any changes made to objects of the Bugs class in real time. As a result, they will get real-time updates about new bugs (creation of new objects), resolved bugs (update objects), and deleted bugs (deletion of objects).

Execute the following code to listen to creation/modification/deletion of objects in the Bugs class:

// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltObject *bugObject = bugsClass.object;
[bugObject on:EventTypeCreate callback:^(id response, NSError *error) {
    if (error) {
        //some error occured while listening
    }else {
        //Built Object in response which is recently created
    }
}];
// 'blt5d4sample2633b' is dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugObject:BuiltObject = bugsClass.object()
bugObject.on(EventType.Create, callback: { (response, error) -> Void in
    if (error != nil) {
        //some error occured while listening
    }else {
        //Built Object in response which is recently created
    }
})
// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
// classWithUid('bugs').object() returns a BuiltObject instance.
BuiltObject bugObject = builtApplication.classWithUid("bugs").object();
 
// Attach a listener for 'create bug' event
bugObject.on(Built.EventType.CREATE, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
          //receive block which get call while listening a particular event happened. 
          BuiltObject builtObject = (BuiltObject) object;
 
        } else {
            //more details if error occurred while listening event. 
        }        
    }
});
 
// Attach a listener for 'update bug' event
bugObject.on(Built.EventType.UPDATE, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
          //receive block which get call while listening a particular event happened.
          BuiltObject builtObject = (BuiltObject) object;
        } else {
            //more details if error occurred while listening event. 
        }
    }
});
 
 
// Attach a listener for 'delete bug' event
bugObject.on(Built.EventType.DELETE, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
          //receive block which get call while listening a particular event happened.
          BuiltObject builtObject = (BuiltObject) object;
        } else {
            //more details if error occurred while listening event. 
        }
    }
});

// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

// Class('bugs').Object returns a Object constructor
var Bugs = app.Class('bugs').Object;

// Attach a listener for 'create bug' event 
Bugs.on('create', function(bug) {
  console.log(bug.toJSON());
});

// Attach a listener for 'update bug' event
Bugs.on('update', function(bug) {
  console.log(bug.toJSON());
});

// Attach a listener for 'delete bug' event
Bugs.on('delete', function(bug) {
  console.log(bug.toJSON());
});

Similarly, you can use the code given below to listen to creation/modification/deletion of file in the Uploads:

// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUpload *upload = [builtApplication upload];
[upload on:EventTypeCreate callback:^(id response, NSError *error) {
    if (error) {
        //some error occured while listening
    }else {
        //Built Object in response which is created
    }
}];
 
[upload on:EventTypeUpdate callback:^(id response, NSError *error) {
    if (error) {
        //some error occured while listening
    }else {
        //Built Object in response which is updated
    }
}];
 
[upload on:EventTypeDelete callback:^(id response, NSError *error) {
    if (error) {
        //some error occured while listening
    }else {
        //Built Object in response which is deleted
    }
}];
// 'blt5d4sample2633b' is dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var upload:BuiltUpload = builtApplication.upload()
 
upload.on(EventType.Create, callback: { (response, error) -> Void in
    if (error != nil) {
        //some error occured while listening
    }else {
        //Built Object in response which is updated
    }
})
 
upload.on(EventType.Update, callback: { (response, error) -> Void in
    if (error != nil) {
        //some error occured while listening
    }else {
        //Built Object in response which is updated
    }
})
 
upload.on(EventType.Delete, callback: { (response, error) -> Void in
    if (error != nil) {
        //some error occured while listening
    }else {
        //Built Object in response which is updated
    }
})
// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
// app.upload() returns a BuiltUpload instance
BuiltUpload uploadObject = builtApplication.upload();
 
// Attach a listener for 'create upload' event  
uploadObject.on(Built.EventType.CREATE, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
           //receive block which get call while listening a particular event happened.
          BuiltUpload file = (BuiltUpload) object;
        } else {
           //more details if error occured while listening event. 
        }
    }
});
 
// Attach a listener for 'update upload' event  
uploadObject.on(Built.EventType.UPDATE, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
           //receive block which get call while listening a particular event happened.
          BuiltUpload file = (BuiltUpload) object;
        } else {
           //more details if error occured while listening event. 
        }
    }
});
 
// Attach a listener for 'delete upload' event  
uploadObject.on(Built.EventType.DELETE, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
           //receive block which get call while listening a particular event happened.
          BuiltUpload file = (BuiltUpload) object;
        } else {
           //more details if error occured while listening event. 
        }
    }
});
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

// app.Upload returns a Upload constructor
var Upload = app.Upload;

// Attach a listener for 'create upload' event  
Upload.on('create', function(upload) {
  // details of upload
  console.log(upload.toJSON());
});

// Attach a listener for 'update upload' event  
Upload.on('update', function(upload) {
  // details of upload
  console.log(upload.toJSON());
});

// Attach a listener for 'delete upload' event  
Upload.on('delete', function() {
  //done
});

The above code can also be used for listening to delete events. Simply replace the word 'update' with 'delete' in your code.

Specific events

In contrast to generic events, users can choose listening to changes on a particular object or upload in a given class and ignore the rest. The app will then emit events related to only that specific object to subscribed users. Using the same example, users of your app can choose to get updates only on a specific bug object that was created, and not listen to other objects in the Bugs class.

Listen to update/delete events on a specific bug object:

// 'blt5d4sample2633b' is dummy Application API key
// 'blt5d4sample1113b' is dummy uid of an object on built.io
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltObject *bugObject = [bugsClass objectWithUID:@"blt5d4sample1113b"];
 
[bugObject on:EventTypeUpdate callback:^(id response, NSError *error) {
    if (error) {
        //some error occured while listening
    }else {
        //Built Object in response which is updated
    }
}];
 
[bugObject on:EventTypeDelete callback:^(id response, NSError *error) {
    if (error) {
        //some error occured while listening
    }else {
        //Built Object in response which is updated
    }
}];
// 'blt5d4sample2633b' is dummy Application API key
// 'blt5d4sample1113b' is dummy uid of an object on built.io
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugObject:BuiltObject = bugsClass.objectWithUID("blt5d4sample1113b")
 
bugObject.on(EventType.Update, callback: { (response, error) -> Void in
    if (error != nil) {
        //some error occured while listening
    }else {
        //Built Object in response which is updated
    }
})
 
bugObject.on(EventType.Delete, callback: { (response, error) -> Void in
    if (error != nil) {
        //some error occured while listening
    }else {
        //Built Object in response which is updated
    }
})
// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
// classWithUid("bugs").object("object_uid") returns a BuiltObject instance.
// 'blt5d4sample1113b' is dummy uid of an object on built.io.
BuiltObject bugObject      = builtApplication.classWithUid("bugs").object("blt5d4sample1113b");
 
// Attach a listener for 'update bug' event
bugObject.on(Built.EventType.UPDATE, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
            //receive block which get call while listening a particular event happened.
          BuiltObject builtObject = (BuiltObject) object;
        } else {
            //more details if error occured while listening event. 
        }
    }
});
 
// Attach a listener for 'delete bug' event
bugObject.on(Built.EventType.DELETE, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
            //receive block which get call while listening a particular event happened.
          BuiltObject builtObject = (BuiltObject) object;
        } else {
            //more details if error occured while listening event. 
        }
    }
});
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

// Class('bugs').Object returns a Object constructor
// 'blt5d4sample1113b' is dummy uid of an object on built.io 
var bug = app.Class('bugs').Object('blt5d4sample1113b');

// Attach a listener for 'update bug' event
bug.on('update', function(bug) {
  console.log(bug.toJSON());
});

// Attach a listener for 'delete bug' event
bug.on('delete', function() {
  //done
});

Use the following code to listen to update/delete events on a specific upload:

// 'blt5d4sample2633b' is dummy Application API key
// 'blt5d4sample2223b' is dummy uid of a upload on built.io
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUpload *upload = [builtApplication uploadWithUID:@"blt5d4sample2223b"];
[upload on:EventTypeUpdate callback:^(id response, NSError *error) {
    if (error) {
        //some error occured while listening
    }else {
        //BuiltFileObject in response which is recently updated
    }
}];
 
[upload on:EventTypeDelete callback:^(id response, NSError *error) {
    if (error) {
        //some error occured while listening
    }else {
        //BuiltFileObject in response which is recently deleted
    }
}];
// 'blt5d4sample2633b' is dummy Application API key
// 'blt5d4sample2223b' is dummy uid of a upload on built.io
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var upload:BuiltUpload = builtApplication.uploadWithUID("blt5d4sample2223b")
 
upload.on(EventType.Update, callback: { (response, error) -> Void in
    if (error != nil) {
        //some error occured while listening
    }else {
        //BuiltFileObject in response which is recently updated
    }
})
 
upload.on(EventType.Delete, callback: { (response, error) -> Void in
    if (error != nil) {
        //some error occured while listening
    }else {
        //BuiltFileObject in response which is recently deleted
    }
})
// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
// app.Upload returns a BuiltUpload instance
// 'blt5d4sample2223b' is dummy uid of a upload on built.io
BuiltUpload uploadObject = builtApplication.upload("blt5d4sample2223b");
 
// Attach a listener for 'update upload' event  
uploadObject.on(Built.EventType.UPDATE, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
           //receive block which get call while listening a particular event happened.
          BuiltUpload file = (BuiltUpload) object;
        } else {
           //more details if error occured while listening event. 
        }
    }
});
 
// Attach a listener for 'delete upload' event  
uploadObject.on(Built.EventType.DELETE, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
           //receive block which get call while listening a particular event happened.
          BuiltUpload file = (BuiltUpload) object;
        } else {
           //more details if error occured while listening event. 
        }
    }
});
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

// 'blt5d4sample2223b' is dummy uid of a upload on built.io 
var upload = app.Upload('blt5d4sample2223b');

// Attach a listener for 'update upload' event  
upload.on('update', function(upload) {
  console.log(upload.toJSON());
  // details of upload
});

// Attach a listener for 'delete upload' event  
upload.on('delete', function() {
  //done
});

Broadcast

Using Broadcast, you can raise customs events and send free-form messages to some or all users of particular class or an object. No record of Broadcast events is stored on the server.

To Broadcast messages, you will have to create channels/rooms. Users who are subscribed to this channel/room will receive the broadcast messages. A channel is nothing but an object, on which you will have to give certain permissions to all or some users.  

Users with 'update' permission can create and broadcast events, while users authorized to 'read' (there are subscribers) can just listen to events. You can manage users' access to this channel/room through Access Control List (ACL) and determine who gets to do what.

So, what's in it for your app?

A lot!

This can make your app more versatile and customized. For instance, you can add a 'secret chat' feature to your chat messenger or allow users to communicate while playing multiplayer games and so on. You can use this feature in your Projects-On-The-Go app as well. Using Broadcast, you can make announcements about a certain bug to the users of your app.

To allow all users to receive Broadcast messages, you can use the following code:

// 'blt5d4sample2633b' is dummy Application API key
// 'blt5d4sample1113b' is dummy uid of an object on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltObject *bugObject = [bugsClass objectWithUID:@"blt5d4sample1113b"];
[bugObject on:EventTypeBroadcast callback:^(id response, NSError *error) {
    if (error) {
        //some error occured while listening
    }else {
        //Broadcast message as string in response
    }
}];
// 'blt5d4sample2633b' is dummy Application API key
// 'blt5d4sample1113b' is dummy uid of an object on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugObject:BuiltObject = bugsClass.objectWithUID("blt5d4sample1113b")
bugObject.on(EventType.Broadcast, callback: { (response, error) -> Void in
    if (error != nil) {
        //some error occured while listening
    }else {
        //Broadcast message as string in response
    }
})
// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
// classWithUid("bugs").object("object_uid") returns a BuiltObject instance.
// 'blt5d4sample1113b' is dummy uid of an object on Built.io Backend
BuiltObject bugObject  = builtApplication.classWithUid("bugs").object("blt5d4sample1113b");
 
 
// Attach a listener for 'boroadcated message' event
bugObject.on(Built.EventType.BRODCAST, new BuiltOnEventCallback() {
 
    @Override
    public void onReceive(Object object, BuiltError error) {
 
        if (error == null) {
          // broadcasted message
          String message = (String) object;
        } else {
          //more details if error occured while listening event. 
        }
    }
});
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

// 'blt5d4sample1113b' is dummy uid of an object on Built.io Backend 
var bug = app.Class('bugs').Object('blt5d4sample1113b');
bug.on('broadcast', function(message) {
  console.log(message)
    // broadcasted message
});

However, only the users with 'update' permission are allowed to send Broadcast message. To achieve this, execute the code given below:

// 'blt5d4sample2633b' is dummy Application API key
// 'blt5d4sample1113b' is dummy uid of an object on Built.io Backend
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltClass *bugsClass = [builtApplication classWithUID:@"bugs"];
BuiltObject *bugsObject = [bugsClass objectWithUID:@"blt5d4sample1113b"];
[bugsObject broadcastWithMessage:@"Hello world" callback:^(id response, NSError *error) {
    if (error) {
        // error while sending message
    }else {
        // sent
    }
}];
// 'blt5d4sample2633b' is dummy Application API key
// 'blt5d4sample1113b' is dummy uid of an object on Built.io Backend
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var bugsClass:BuiltClass = builtApplication.classWithUID("bugs")
var bugsObject:BuiltObject = bugsClass.objectWithUID("blt5d4sample1113b")
bugsObject.broadcastWithMessage("Hello World", callback: { (response, error) -> Void in
    if (error != nil) {
        //some error occured while sending
    }else {
        //sent
    }
})
// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
// classWithUid("bugs").object("object_uid") returns a BuiltObject instance.
// 'blt5d4sample1113b' is dummy uid of an object on Built.io Backend
BuiltObject bugObject      = builtApplication.classWithUid("bugs").object("blt5d4sample1113b");
 
bugObject.broadcast("Hello world", new BuiltBroadCastCallback() {
 
      @Override
      public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
          if (error == null) {
            //message sent success block.
          } else {
            //more details if error occurred while listening event. 
          }     
      }
});
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

// 'blt5d4sample1113b' is dummy uid of an object on Built.io Backend
var bug = app.Class('bugs').Object('blt5dsamplef62a633b');

bug.broadcast('Hello world');

Presence

Built.io Backend's Presence technology notifies you when users are connected to your app and when they are not. However, its scope is not limited to just this. It offers a host of other features that are essential for enabling real-time client-to-client communication on your app. 

Listed here are a few features of Presence:

  • Status: It shows whether a user is online or offline. While this is a great add-on for all applications, it is particularly essential for instant messenger (IM) or chat applications.
  • Last activityBuilt.io Backend remembers the time when an activity was last performed by a user. Users can always access this by fetching other user's profile.

Only authorized users can access presence. Anonymous users will not be able to view anybody's status message, status or time of last activity.

Getting

You can get your own presence as well as others'. To get to your own presence, execute the code given below:

// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
[builtApplication.currentUser getPresence:^(NSError *error) {
    if (error) {
        //error occured while fetching
    }else {
        //builtApplication.currentUser.presence is updated
    }
}];
// 'blt5d4sample2633b' is dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
builtApplication.currentUser.getPresence { (error) -> Void in
    if (error != nil) {
        //error occured while fetching
    }else {
        //builtApplication.currentUser.presence is updated
    }
}
// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
// app.getCurrentUser() returns current user instance.
BuiltUser userObject =  builtApplication.getCurrentUser();
 
// fetching current user presence.
userObject.getPresence(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
        if (error == null) {
          //success block.
          BuiltPresence presence = user.getPresence();
        } else {
          //more details if error occured while fetching presence. 
        }    
    }
});
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

// app.User returns User constructor
var User = app.User;

/* getCurrentUserPresence method accepts an optional forceFetch argument
   which if set to true force fully fetches presence details from built.io
*/

User.getCurrentUserPresence(true)
.then(function(presence) {
  // Currently logged in user's presence
  console.log(presence.toJSON());
});

Here's how you can get other user's presence:

// 'blt5d4sample2633b' is dummy Application API key
// 'blt5dsamplef62a111a' is dummy object uid of an application user whose presence we are interested in
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *userObject = [builtApplication userWithUID:@"blt5dsamplef62a111a"];
[userObject getPresence:^(NSError *error) {
    if (error) {
        //error occured while fetching
    }else {
        //userObject.presence is updated
    }
}];
// 'blt5d4sample2633b' is dummy Application API key
// 'blt5dsamplef62a111a' is dummy object uid of an application user whose presence we are interested in
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var userObject:BuiltUser = builtApplication.userWithUID("blt5dsamplef62a111a")
userObject.getPresence { (error) -> Void in
    if (error != nil) {
        //error occured while fetching
    }else {
        //userObject.presence is updated
    }
}
// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
// 'blt5dsamplef62a111a' is dummy uid of an application user whose presence we are interested in.
BuiltUser userObject = builtApplication.user("blt5dsamplef62a111a");
 
// fetching other user presence.
userObject.getPresence(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
 
        if (error == null) {
          //success block.
          BuiltPresence presence = user.getPresence();
        } else {
          //more details if error occured while fetching presence. 
        }    
    }
});
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

// 'blt5dsamplef62a111a' is dummy object uid of an application user whose presence we are interested in
var user = app.User('blt5dsamplef62a111a');

/* 
getPresence method accepts an optional forceFetch argument which if
set to true force fully fetches presence details from built.io
*/

user.getPresence(true)
.then(function(presence) {
  //Presence details of the user with uid 'blt5dsamplef62a111a'
  console.log(presence.toJSON());
});

Enabling/disabling

Users can enable or disable presence. When you disable your presence, Built.io Backend will ensure that it is not broadcast to any user. You will be able to perform all routine activities without anyone being notified about it. It is similar to the 'invisible' feature offered by most IMs or chat applications.

You can disable your presence using the following code:

// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
builtApplication.currentUser.presence.enable = FALSE;
[builtApplication.currentUser.presence save:^(NSError *error) {
    if (error) {
        //some error occured while saving
    }else {
        //presence saved
    }
}];
// 'blt5d4sample2633b' is dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
builtApplication.currentUser.presence.enable = false
builtApplication.currentUser.presence.save { (error) -> Void in
    if (error != nil) {
        //some error occured while saving presence
    }else {
        //presence saved
    }
}
// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
// app.getCurrentUser() returns current user instance.
BuiltUser userObject =  builtApplication.getCurrentUser();
 
// getting current user presence.
BuiltPresence presenceObject = userObject.getPresence();
 
presenceObject.setEnable(true);
 
//saving presence.
presenceObject.save(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType resType, BuiltError error) {
 
        if(error == null) {
          //success block.
        } else {
          //more details if error occurred while saving presence. 
        }
    }
});
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

// app.User returns User constructor
var User = app.User;

/* 
getPresence method accepts an optional forceFetch argument which if
set to true force fully fetches presence details from built.io
*/

User.getCurrentUserPresence(true)
.then(function(presence) {
  var newPresence = presence.enable(false);
  return newPresence.save();
});

To enable it again, replace 'false' with 'true' using the above snippet.

ACL for Presence

In the above section, we covered how to enable and disable presence. Apart from these two options, there's an intermediary step to control the notification of a user's presence by configuring an Application User's ACL.

By default, a user's presence remains hidden to another user. In order to make a user's presence visible to a specific set of users, access rights needs to be assigned to them. Consider for example that in a team there are four members: User A, User B, User C, and User D. Now, User A wants their presence to be visible to only to User B and User C. This can be modified through ACL, where User A will need to select the 'Read' access when configuring ACL for User B and User C. When the 'Read' option is set, Built.io Backend will make sure to limit User A's visibility to only User B and User C who has been granted the access rights.

Apart from users, ACL can be applied to specific roles too. The procedure is just the same with the exception that you need to enter role objects to the list under the 'Roles' section. This option will set the visibility rights to all the users that are assigned the selected role.

Lastly, if a user wish to set their presence visible to all, click on the 'Everyone else' option and set the ‘Read’ option as true

To know more about ACL, refer the Access Control List (ACL) section

User Profile

When creating a chat roster (i.e., while fetching users' profiles), you do not have to separately fetch users' presence. This comes along with users' profile details. The following code shows how you can access users' presence from their profiles:

// 'blt5d4sample2633b' is dummy Application API key
// 'blt5dsamplef62a111a' is dummy object uid of an application user
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltUser *userObject = [builtApplication userWithUID:@"blt5dsamplef62a111a"];
[userObject fetch:^(BuiltResponseType responseType, BuiltUser *object, NSError *error) {
    if (error == nil) {
        //user object fetched
        //userObject.presence to get presence of user
    }else {        
        //some error occured
    }     
}];
// 'blt5d4sample2633b' is dummy Application API key
// 'blt5dsamplef62a111a' is dummy object uid of an application user
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var userObject:BuiltUser = builtApplication.userWithUID("blt5dsamplef62a111a")
userObject.fetch { (responseType, responseObject, error) -> Void in
    if (error == nil) {
        //user object fetched
        //userObject.presence to get presence of user
    }else {
        //some error occured
    }
}
// 'blt5d4sample2633b' is dummy Application API key
BuiltApplication builtApplication  = Built.application(context, "blt5d4sample2633b");
builtApplication.enableRealTime(context);
 
// 'blt5dsamplef62a111a' is dummy object uid of an application user whose presence we are interested in.
BuiltUser userObject = builtApplication.user("blt5dsamplef62a111a");
 
// fetching perticular user presence.
userObject.fetch(new BuiltResultCallBack() {
 
    @Override
    public void onCompletion(BuiltResponseType responseType, BuiltError error) {
            
        if (error == null) {
          //success block.
          BuiltPresence presence = userObject.getPresence();
} else { //more details if error occurred while fetching presence. } } });
// 'blt5d4sample2633b' is dummy Application API key
var app = Built.App('blt5d4sample2633b').enableRealtime();

// 'blt5dsamplef62a111a' is dummy object uid of an application user
var user = app.User('blt5dsamplef62a111a');

user.fetch()
.then(function(user) {
  // To extract presence details from user object use getPresence() with forceFetch argument kept blank
  return user.getPresence()
})
.then(function(presence) {
  console.log(presence.toJSON());
});

Extensions

Built.io Backend allows you to build your favourite apps without having to deal with servers. However, for certain complex apps, you may want to customize the behaviour of the backend. Built.io Backend's extension feature does just that. It allows you to extend the functionality of the backend by letting you write your own business logic.

The business logic is written in JavaScript, and is executed on the cloud. Using extensions, you can change your app's behaviour and introduce new features on the fly.

With Built.io Backend extensions, you can write a piece of JavaScript code in extensions which can be executed by making an API call. This piece of code is known as a function. A function may encapsulate a number of different tasks. For example, you can add a comment to a post and send a push notification to the author of the post in a single function. Bundling two or more different tasks into a single function is useful since it helps reduce the network latency caused by multiple roundtrips.

Extensions also provide webhosting. You can now host your website and migrate all your online properties to use Built.io Backend.

"Hello World"

To understand extensions better, let us try to run a very simple code in the cloud that gives an output “Hello World". This can be done in a few simple steps:

  • To start with, you will need to create two folders, a client folder and a server folder.
  • In the 'server' folder, create a new file 'app.js', and save it with the following JavaScript code:
    // This line informs Extensions to use the latest version of SDK
    Built.Extension.setVersion(2)
    Built.Extension.define('hello', function(request, response) {
      return response.success('Hello World');
    });
    	
    app.js is the main entry point for extensions. Hence, it is mandatory to have this file in the 'server' folder.
  • To upload the 'server' and 'client' folders to Built.io Backend, you need to zip them together into a single file. Since this is a simple “Hello World" example, keep the client folder empty.
  • Now, let us upload the zipped file to Built.io Backend. In the management console, go to the 'Extensions' section. Select a name for your application's primary domain. For example, if you choose ' helloworld', then your primary domain will be http://helloworld.builtapp.io. Below this, upload your zipped file.
    Extension
    With your code uploaded, it will take a moment before it is deployed. The deployment status is shown in the dashboard. In case of any error, the specifics of the error (syntax error, file placement errors, etc.) would be displayed as well.
  • Once deployed, Built.io Backend provides custom API calls to execute this function. The API call for our 'hello' function is https://api.built.io/v1/functions/hello
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltExtension *extensionObject = [builtApplication extensionWithName:@"hello"];
[extensionObject executeWithData:nil completion:^(BuiltResponseType responseType, id responseObject, NSError *error) {
    if (error == nil) {
        // response will contain the response of the extension method
    }else {
        // error in case of any error
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var extensionObject:BuiltExtension = builtApplication.extensionWithName("hello")
extensionObject.executeWithData(nil, completion: { (responseType, responseObject, error) -> Void in
    if (error == nil) {
        // response will contain the response of the extension method
    }else {
        // error in case of any error
    }
})
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication   = Built.application(context,"blt5d4sample2633b");
BuiltExtension extensionObject      = builtApplication.extension();
 
extensionObject.execute("hello", new BuiltExtensionCallback() {
 
    @Override
    public void onCompletion(BuiltResponseType resType, Object object, BuiltError error) {
 
        if(error == null){
            Log.i("BuiltExtension", "finish-response|"+response);
        }else{
            // there was an error in executing extentation.
            // refer to the 'error' object for more details
        }
    }
});
// SDK internal makes and API to https://api.built.io/v1/functions/hello
// 'blt5d4sample2633b' is a dummy Application API key
var app = Built.App('blt5d4sample2633b');

app
.Extension.execute('hello')
.then(function(res) {
  // do somethings
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication= Built.App("blt5d4sample2633b");
BuiltExtension extensionObject   = builtApplication.Extension();

extensionObject.Execute("hello").ContinueWith(extensionTask=>
{
        if(extensionTask.IsFaulted)
        {
                // there was an error in executing extentation.
                // refer to the extensionTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // extensionTask.Result will contain the response of the extension method
        }
});
curl -i -X -d {} POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d {}\
https://api.built.io/v1/functions/hello
RESPONSE:
{
  "result": "Hello World"
}
  • As you can see, the same function name appears in the url. This is always the case. If, for instance, you create another function with a different name, say 'greetings', the custom API call to execute that function would be https://api.built.io/v1/functions/greetings

    The function is executed just like any other API on Built.io Backend, and its result, 'Hello World', is obtained as a response to the request.
    You can also handle an exceptional situation by issuing an error in the response. The following code demonstrates sending an error inresponse.error():
    // This line informs Extensions to use the latest version of SDK
    Built.Extension.setVersion(2)
    
    Built.Extension.define('hello', function(request, response) {
      // the errors are a key-value pair
      return response.error({
        error: 'world is not enough'
      });
    });
    
    For every error response, an error code can be set. This code can be used to identify the error. By default, the error code for every error is 259. You can change this code as per your preference. You can specify the error code in the first argument of ' response.error( )', and the error message in the second augment. The code below demonstrates this:
  • // This line informs Extensions to use the latest version of SDK
    Built.Extension.setVersion(2)
    
    Built.Extension.define('hello', function(request, response) {
      // the errors are a key-value pair
      return response.error(260, {
        error: 'world is not enough'
      });
    });    
  • You can also send an HTTP status code in response. Here's how you can do it:
    // This line informs Extensions to use the latest version of SDK
    Built.Extension.setVersion(2)
    
    Built.Extension.define('hello', function(request, response) {
      // the errors are a key-value pair
      return response.status(400).error(260, {
        error: 'world is not enough'
      });
    });    

  • response.error() takes a plain JavaScript object, in which you can specify your custom error message. This will help you identify the error. You can then execute the function in the same way as before:
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltExtension *extensionObject = [builtApplication extensionWithName:@"hello"];
[extensionObject executeWithData:nil completion:^(BuiltResponseType responseType, id responseObject, NSError *error) {
    if (error == nil) {
        // response will contain the response of the extension method
    }else {
        // error in case of any error
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var extensionObject:BuiltExtension = builtApplication.extensionWithName("hello")
extensionObject.executeWithData(nil, completion: { (responseType, responseObject, error) -> Void in
    if (error == nil) {
        // response will contain the response of the extension method
    }else {
        // error in case of any error
    }
})
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication  = Built.application(context,"blt5d4sample2633b");
BuiltExtension extensionObject     = builtApplication.extension();
 
extensionObject.execute("hello", new BuiltExtensionCallback() {
    
    @Override
    public void onCompletion(BuiltResponseType resType, Object object, BuiltError error) {
 
        if(error == null){
            Log.i("BuiltExtension", "finish-response|"+response);
        }else{
            // there was an error in executing extentation.
            // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var app = Built.App('blt5d4sample2633b');

app.Extension.execute('hello')
.then(function(res) {
  // do something
}, function(error) {
  // the error object will contain your custom error
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication= Built.App("blt5d4sample2633b");
BuiltExtension extensionObject   = builtApplication.Extension();

extensionObject.Execute("hello").ContinueWith(extensionTask=>
{
        if(extensionTask.IsFaulted)
        {
                // there was an error in executing extentation.
                // refer to the extensionTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // extensionTask.Result will contain the response of the extension method
        }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
https://api.built.io/v1/functions/hello
RESPONSE:
{
    "error_message": "Bummer. There was a problem executing that function",
    "error_code": 259,
    "errors": {
        "world": [
            "is not enough"
        ]
    }
}

Each function has a request and response object. The ‘request object’ contains all the parameters that are sent while making an API call. The ‘response object’ is used to send the response in either the success or error variant.

Any parameters passed in the API call will be received in the ‘request.params’ property. In addition, there are two other properties that allow you to access parameters. First, the ‘request.query’ property contains any query parameters passed while making an API call. Next, the body property contains only those parameters passed in the body of the POST call.

  • In the following example, we will pass parameters to the "hello" function, such that it accepts a name:
Built.Extension.define('hello', function(request, response) {
    return response.success('Hello ' + request.params.name);
});

Here's how you execute it with a name:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltExtension *extensionObject = [builtApplication extensionWithName:@"hello"];
[extensionObject executeWithData:@{@"name": @"Richard"} completion:^(BuiltResponseType responseType, id responseObject, NSError *error) {
    if (error == nil) {
        // response will contain the response of the extension method
    }else {
        // error in case of any error
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var extensionObject:BuiltExtension = builtApplication.extensionWithName("hello")
extensionObject.executeWithData(["name": "Richard"], completion: { (responseType, responseObject, error) -> Void in
    if (error == nil) {
        // response will contain the response of the extension method
    }else {
        // error in case of any error
    }
})
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltExtension extensionObject    = builtApplication.extension();
 
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("name", "Richard");
 
 
extensionObject.execute("hello", hashMap, new BuiltExtensionCallback() {
    @Override
    public void onCompletion(BuiltResponseType resType, Object object, BuiltError error) {
 
        if(error == null){
            Log.i("BuiltExtension", "finish-response|"+response);
        }else{
            // there was an error in executing extentation.
            // refer to the 'error' object for more details
        }
    }
});
// 'blt5d4sample2633b' is a dummy Application API key
var app = Built.App('blt5d4sample2633b');

app.Extension.execute('hello', {
  name: 'Richard'
})
.then(function(res) {
  // executed successfully
}, function(error) {
  // the error object will contain your custom error
});
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication= Built.App("blt5d4sample2633b");
BuiltExtension extensionObject   = builtApplication.Extension();

extensionObject["name"] = "Richard";

extensionObject.Execute("hello").ContinueWith(extensionTask=>
{
        if(extensionTask.IsFaulted)
        {
                // there was an error in executing extentation.
                // refer to the extensionTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // extensionTask.Result will contain the response of the extension method
        }
});
curl -i -X POST \
-H "application_api_key: blt5d4sample2633b" \
-H "Content-Type: application/json" \
-d '{
      "name": "Richard"
    }' \
https://api.built.io/v1/functions/hello
RESPONSE:
{
  "result": "Hello Richard"
}

Congratulations! You now know how to run a code in the cloud using Built.io Backend extension. Try to play around with this example, by trying to replace “Hello World" with something else. Once you know how to use this, you can do a lot with your app.

BuiltSDK

JavaScript SDK can be used in extensions as well. To inform the Built.io Backend extension to use the latest version of SDK, set the SDK version to 2:

// This line informs Extensions to use the latest version of SDK
Built.Extension.setVersion(2)

Built.Extension.beforeSave('bugs', function(request, response) {
    console.log("Code to be executed before the object is saved goes here...");
});

It is also necessary to initialize the SDK with the application's API key before using it. While creating your own functions, avoid using special characters in function name.

Let us understand how to use the SDK with the help of an example, in which, it returns ten most recent bugs. 

// This line informs Extensions to use the latest version of SDK
Built.Extension.setVersion(2)
// 'blt5d4sample2633b' is a dummy Application API key
var API_KEY = 'blt5d4sample2633b'
var BuiltSDK = require('built.io');
var App = BuiltSDK(API_KEY)
Built.Extension.define('recentbugs', function(request, response) {
  var query = App.Class('bugs').Query()
  query
    .toJSON()
    .descending('created_at')
    .limit(10)
    .exec()
    .then(function(bugs) {
      return response.success(bugs);
    });
});

Hooks

Hooks enable you to insert your own business logic at certain points, i.e., when users perform some common actions in your application. You can write a piece of custom code that you would like to get executed when these actions are performed.

When users use your application, a pre-defined set of events take place. Whenever Built.io Backend encounters any of these defined events, it checks if you have written custom code that must be executed before or after these events happen.

Built.io Backend provides two hooks: 'beforeSave' and 'afterSave'. Using these hooks, you can run a particular code before or after a object is saved.

beforeSave

The 'beforeSave' hook is executed before an object is saved, i.e., before it is created or updated. This hook is commonly used to specify custom validations or transformations for objects.

As beforeSave hook can be called when the object is created or updated, it is important to identify whether it is being called while creating or updating the object. There is a simple way to do this. The beforeSave hook is called with a request and a response object. The 'event' property in the request object is set to 'create', if the beforeSave hook is called for creation. Similarly, it is set to 'update', if it is called for update.

The following example demonstrates this:

// This line informs Extensions to use the latest version of SDK
Built.Extension.setVersion(2)

Built.Extension.beforeSave('bugs', function(request, response) {
    if (request.event === 'create') {
        console.log('Create call')
        else if (request.event === 'update')
            console.log('Update call')
    }
    return response.success();
});

Suppose you want to perform certain validations before an object is created, you can identify that it is a create call using the above snippet, and subsequently perform the required validations.

In the following example, we will use a 'beforeSave' hook on the 'bugs' class to validate whether the due_date is a date in future:

// This line informs Extensions to use the latest version of SDK
Built.Extension.setVersion(2)

Built.Extension.beforeSave('bugs', function(request, response) {
  // get the date specified in the request
  if (request.event === 'create') {
    var due_date = new Date(request.object.get('due_date'));
    var today = new Date();
    if (due_date < today)
      return response.error({
        'error': 'due_date should not be a past date'
      });
    else
      return response.success();
  }
  return response.success();
});

Note that in the above snippet, request.object contains the Built.io Backend object that needs to be saved. response.success() should be used to send a success response, and it accepts no arguments in a hook (if given any, it will be ignored). On the other hand, we can specify the error message in response.error().

To perform validations before an object is updated, you have access to both, the existing object on Built.io Backend in request.object as well as the modifications you wish to make in request.params. Subsequently, you can perform validations on these and decide what modifications are to be made.

To understand this better, let's walk through an example:

Let's say you want to modify the 'due_date' of an already existing bug in our 'bugs' class. To do this, we need to first validate whether the bug's status is still open. At the same time, we also need to check whether the new due_date that needs to be set is a day in future. If both the conditions are satisfied, we will merge the objects, and send a success response. Else, an appropriate error response will be sent. Here's the code to do this:

// This line informs Extensions to use the latest version of SDK
Built.Extension.setVersion(2)

Built.Extension.beforeSave('bugs', function(request, response) {
  // We check whether its an update call
  if (request.event === 'update') {
    // previousObject contains the details of the existing object on built.io
    var previousObject = request.object;
    // modifications contain the changes that need to be done
    var modifications = request.params;
    if (previousObject.get('status') === 'open') {
      if (modifications.due_date >= new Date()) {
        // We update the object
        request.object = previousObject.assign(modifications);
        response.success();
      } else {
        response.error({
          'error': 'Due date should not be a past date'
        });
      }
    } else {
      response.error({
        'error': 'Bug is already closed'
      });
    }
  }
  // It was a create call so we sent a success directly
  return response.success();
});

afterSave

The 'afterSave' hook executes after an object is saved, i.e., after it is created or updated. This hook is async in nature, and is commonly used to execute lifecycle logic or analytics. Here's an example of 'afterSave', where we add an analytics call after a bug is created:

// This line informs Extensions to use the latest version of SDK
Built.Extension.setVersion(2)

Built.Extension.afterSave('bugs', function(request, response) {
  var event = new Built.Analytics.Event('bug_saved');
  event.trigger({
    onSuccess: function() {
      // successfully triggered
      return response.success();
    }
  });
});

Current user

Accessing current user details

In 'beforeSave' and 'afterSave' hooks, you have access to the details of the user (current user) who has made the request. You can find the details of the current user in request.current_user. The details that are sent in request.current_user are as follows:

  • type (SystemUser/AppUser/anonymous)
  • authtoken
  • uid
  • email

Timeouts

Built.Extension has hard time limits on execution of the functions. A standalone function is granted 20 seconds of runtime. A 'before' or 'after' hook is granted 2 seconds of runtime. After this limit, the request is cancelled and the client will receive a timeout error. Any network calls made in the request will also be cancelled after the time limit.

After response.success or response.error is called, no additional callbacks are executed. This means any simultaneous network calls will be cancelled.

Modules

Any JavaScript file created by you apart from app.js in the server folder can be required as a module. This allows you to organize code more effectively. The code in modules follows the CommonJS exports system. Here's a sample module file saved as 'mymodule.js' in the 'server' folder:

// mymodule.js
exports.process = function() {
    return 'A lot of processing!';
}

Note how the process function defined in 'mymodule' exports is used in this context. Similarly, complex code can be broken down into multiple files and also placed into folders. You can then 'require' the module in app.js. When requiring a file from inside a folder, simply require it along with the relative folder path:

// here "mymodule" is inside the "interface" folder
var mymodule = require('./interface/mymodule');

A function should not be assigned to the exports module object. Instead, a variable can be assigned to the exports object. To illustrate:

// DON'T DO THIS!: 
exports = function() {
        return 'A lot of processing!';
    }
    // do this:
exports.process = function() {
    return 'A lot of processing!';
}

JavaScript for Built.Extensions is run in a strict context ('use strict'). The various ramifications this might have for your code is described here.

Webhosting

Built.Extension provides full-featured webhosting. Its now very easy to host your own website and use custom domains.

Zip the folders (client and server together) and upload it to Built.io Backend in the 'Extension' tab from the management console. Provide a suitable name for your app.

Webhosting

The app name should be unique. If the app name is not available, Built.io Backend will prompt you to select another name.

Next, click on 'Deploy app' link to deploy your app.

That's it. You have successfully deployed your app to Built.io Backend. You can now access your application or website by clicking on the link of your very own domain.

Deployed App

There may be times when you would require to stop or restart your extension application. You can do this easily by using the 'stop' and 'restart' icons given on the page.

You can also view the logs of your application. To do this, select 'Logs' under the 'Extensions' tab on the left panel of the management console. If you wish to see logs in real-time, select the 'Enable real time' option on the page. You can also clear your app's logs from here.

Hitting the root / will serve the index.html file, if present.

Overall, the structure for your extension files will be as follows:

        |-- client
        |   `-- index.html
        |   `-- anyotherhtmlfile.html
        `-- server
        `-- app.js
        `-- anyotherjsfile.js

The size limit for webhosting is 25 MB, considering all the assets you have uploaded (both the server and client directories).

Point a custom domain

Just below the 'Deploy app' option, you can find another header called 'Domain'. Here, you can set up a custom domain that points to your website.

Domain

Next, configure your DNS with a CNAME record pointing the subdomain to extension.built.io:

Record Name Target
CNAME www extension.built.io
It will take some time before the domain setting is reflected. Reducing the TTL (Time To Live) will reduce, but not eliminate the wait.

Root domains

To point root domains (also called bare or naked domains) like domain.com, first register it via the management interface:

Root domain

Next, you need to configure your DNS. Many new DNS providers offer CNAME-like functionality for root domains. Such records include:

  • ALIAS
  • ANAME

Simply use these to point to extension.built.io.

If your DNS provider does not provide such records, you can take advantage of domain redirection. Most DNS providers offer domain redirection where the root level domain is redirected to a subdomain (such as domain.com to www.domain.com). This results in a 301 permanent redirect to the subdomain. The subdomain can then be registered at extension.built.io<code> in the regular way.

Platform-as-a-Service

What is PaaS?

PaaS provides a computing platform over the web and automates the configuration, deployment, and management of your applications in the cloud. So, developers can start writing applications directly without having to worry about the system architecture, servers and configuration.

Why use PaaS?

So that you can focus on writing the code, testing your app and launching it successfully, without having to spend on buying and managing the required hardware/software.

While Built.io Backend provides backend services for your apps, its PaaS extension allows you to run complete node.js applications, taking care of all the requirements of your project lifecycle.

This guide will walk you through the process of deploying a vanilla node.js app on Built.io Backend extension.

Getting started

To start with, create a folder named server on your machine. Within the same directory, create a file named app.js, which will serve as an entry point for your node application.

If the application has any npm dependencies, list them in package.json, just like you do in a regular node.js app. However, manually running npm install before deploying your application is not required. Built.io Backend will automatically install the all the dependencies listed in package.json.

HTTP Server

For a node app that uses the http server, you need to define a port to bind, to make it accessible to the users. You will find this port by accessing the variable process.env.PORT.

Deployment

Once all the above steps are done, proceed to uploading your code to Built.io Backend, in the same way.

Click here to download a sample node app that you can readily deploy.

Setup

It is important to note that, in Extensions, the words 'Built' and 'built' are keywords, and hence, should not be used as variables. The global variable 'Built' is used to define custom functions as well as register 'beforeSave' and 'afterSave' hooks. The global variable 'built' is the JavaScript SDK's entry point.

Another point to remember is that 'Extensions' supports both the SDKs, the previous SDK (version 1) as well as the latest one (version 2). To inform extensions to use the latest version, you need to set the SDk version to 2 as shown in the snippet below.

Built.Extension.setVersion(2)

Push Notifications

Push notification allows you to notify your app users about a particular event or message, even when the users are not using your app. It is delivery of a message or information without any specific request from the client. This is usually initiated by you (from the server), unlike pull notifications where the client requests for information. 

Since you can send notifications to all or a defined set of users, you can target users based on certain criteria, such as location, device type, etc. You can also define when you want the app users to receive the notifications. Many apps today use push notifications as it keeps the users engaged as well as informed. You can, for instance, announce to a few users about a flash sale taking place near their location. Or you can inform a particular user that it is his turn in the game that he has been playing with a friend. It is a brilliant way to interact with the app's users instantly and effectively.  

In order to start using push notification, you will need to configure your app. Our Android and iOS push notification tutorials will help you do this.

Installation Data

'Installations' is the central concept that allows push notifications with Built.io Backend and is the representation of your device in Built.io Backend. 'Installation Data' is a 'System Class'. System classes are readymade, pre-defined classes with specialized behavior and functionality.

Every Built.io Backend app installed on a particular device, which is registered for receiving push notifications, should have a corresponding Installation object in the Installation Data class. In other words, each device is an installation object.

From your application, you can create an installation object with a unique device token. For iOS, this device token is the one provided by the operating system itself, when registering for notifications (See Step 9 in iOS Push Tutorial). For Android, this device token is the registration id that you obtain by registering your device on GCM (See Step 6 in Android Push Tutorial). 

The steps involved in receiving device tokens and creating installation using these tokens are given in detail in the push Notification Tutorials given below. You can create installations using the JavaScript SDK too. This is helpful when building a hybrid application. 

Let us have a quick look at how to create a simple installation.

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltInstallation *installation = [builtApplication installation];
//converting NSData deviceToken to NString
installation.deviceToken = [[NSString alloc] initWithData:deviceToken encoding:NSUTF8StringEncoding];
[installation createInstallationWithSubscriptionChannels:nil completion:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
        //creation done
    }else {
        //error while creating
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var installation:BuiltInstallation = builtApplication.installation()
//converting NSData deviceToken to NString
installation.deviceToken = NSString(data: deviceToken, encoding: NSUTF8StringEncoding)
installation.createInstallationWithSubscriptionChannels(nil, completion: { (responseType, error) -> Void in
    if (error == nil) {
        //creation done
    }else {
        //error while creating
    }
})
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication = Built.application(context, "blt5d4sample2633b");
BuiltInstallation installation = builtApplication.installation();

installation.createInstallation("registrationId", null, new BuiltResultCallBack() {@
     @Override
     public void onCompletion(BuiltResponseType responseType, BuiltError error) {
            if (error == null) {
                 // installation is created successfully.
            } else {
                 // there was an error in creating installation.
                 // refer to the 'error' object for more details
            }
     }
});
// 'blt5d4sample2633b' is a dummy Application API key
// app.Installation returns a instance of 'built_io_installation_data' class.
var installation = Built.App('blt5d4sample2633b').Installation();

// this can be 'ios' too
installation = installtion.setDeviceType('android');

installation
.save()
.then(function(installation) {
  console.log(installation.toJSON())
});
// 'blt5d4sample2633b' is a dummy Application API key
// app.Installation returns a instance of 'built_io_installation_data' class.
BuiltInstallation installation = Built.App("blt5d4sample2633b").Installation();
installation.SetHeader("authtoken", "blt1dc2639741245481e7b48eca");
installation.CreateInstallation("deviceToken", null).ContinueWith(installationTask=>
{
        if(installationTask.IsFaulted)
        {
                // there was an error in creating installation.
                // refer to the installationTask.Exception.Flattern().InnerException for more details
        }
        else
        {
                // installation is created successfully.
        }
});

Once the installation is created, you may always retrieve the installation to update it with more values. The currentInstallation method allows you to get the current installation for the device. You can then set an owner for the installation, as well as update any other fields.

In the following snippet, we retrieve the current installation and update the owner for the installation, so that we can have a targeted push to the specific users:

// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication *builtApplication = [Built applicationWithAPIKey:@"blt5d4sample2633b"];
BuiltInstallation *installation = [builtApplication currentInstallation];
[installation updateInstallation:^(BuiltResponseType responseType, NSError *error) {
    if (error == nil) {
        //creation done
    }else {
        //error while creating
    }
}];
// 'blt5d4sample2633b' is a dummy Application API key
var builtApplication:BuiltApplication = Built.applicationWithAPIKey("blt5d4sample2633b")
var installation:BuiltInstallation = builtApplication.currentInstallation()
installation.updateInstallation{ (responseType, error) -> Void in
    if (error == nil) {
        //creation done
    }else {
        //error while creating
    }
}
// 'blt5d4sample2633b' is a dummy Application API key
BuiltApplication builtApplication = Built.application(context,"blt5d4sample2633b");
BuiltInstallation installation = builtApplication.currentInstallation();

installation.updateInstallation("registrationId", new BuiltResultCallBack() {
     @Override
     public void onCompletion(BuiltResponseType responseType, BuiltError error) {
         if(error == null){
           // installation is updated successfully.
         }else{
           // there was an error in creating installation.
           // refer to the 'error' object for more details
         }
     }
});
// 'blt5d4sample2633b' is a dummy Application API key
// app.Installation returns a instance of 'built_io_installation_data' class.

var installation = Built.App('blt5d4sample2633b').Installation('blt111sample2423f')

installation
.setDeviceToken(deviceToken)
.save()
.then(function(installation) {
  console.log(installation.toJSON())
});
// 'blt5d4sample2633b' is a dummy Application API key
// app.Installation returns a instance of 'built_io_installation_data' class.

BuiltInstallation installation = Built.App("blt5d4sample2633b").Installation("blt111sample2423f");
installation.SetCurrentTimeZone();
installation.SetHeader("authtoken", "blt1dc2639741245481e7b48eca");
installation.UpdateInstallation().ContinueWith(installationTask =>
{
        if(installationTask.IsFaulted)
        {
                // there was an error in updating installation.
                // refer to the installationTask.Exception.Flattern().InnerException for more details                
        }
        else
        {
                // installation is updated successfully.
        }
});

iOS

iOS Push notifications tutorial

Generating certificates 

     1.  Create an App ID
     2.  Generate a Certificate Request
     3.  Configure App ID
     4.  Create APNs Certificate 

Saving credentials 

     5.  Convert .p12 into .pem
     6.  Saving credentials in Built.io Backend

Setting up project

     7.  Create Provision Profile
     8.  Requesting for device token
     9.  Receiving device token

Installations

    10. Creating installations 


Introduction

Push notification allows you to notify your app users about a particular event or message, even when the users are not using your app. 

In this tutorial, we will learn how to enable push notifications in your iOS app. However, before we begin, developers need to note that you will require an iOS and an Apple Developer license. Push notifications are not available in iOS Simulator.

In iOS, push notifications are provided by the APN (Apple Push Notifications) Service. APN is a service that allows you to display messages from your application, regardless of whether it is running. Built.io Backend uses APNS to provide push notifications for iOS.

To get started with APNS, please follow this guide. There are two environments provided for push notifications by Apple: development and production. For each of these environments, you will have to generate a certificate file, which we will be uploading to Built.io Backend in Credentials. While we can definitely use the production environment directly, and you may only provide the production certificate if you desire, in practice it is highly recommended to use the development environment for testing before going live.

Let us walk through the steps involved in creating these certificates.


Generating certificates for credentials

Step 1. Create an App ID

Since push notifications are sent to a specific destination (application), each app needs a unique identifier, i.e. an App ID. Here's how you can create one.

  • Sign in to the iPhone Developer Connection Portal
  • Click on 'Certificates, Identifiers & Profiles' on the right top corner of the page.
    iPhone Developer Connection Portal
  • On the welcome page, click on 'Identifiers' to open the list of identifiers.
  • Under 'Identifiers', click on 'App ID', and then on the '+' on the top right corner of the page to create a new App ID.
    New App ID
  • Enter a suitable name for your App ID, and select an App ID suffix. In most cases, the default suffix would be correct.
  • Enter Bundle ID. Before going to the next step, make sure that you haven't created an App ID with a wildcard, since generic wildcard App Id doesn't work with push notifications.
    App ID Suffix
  • Once you are done filling all the details, click on 'Continue'.
  • The next page will help you verify the details of your App ID. Check the details and click on 'Submit' to register a new App ID.

Step 2. Generate a Certificate Request

You will have to generate a certificate request, which will be later used for development of SSL certificate. This can be done in a few simple steps mentioned below.

  • Launch Keychain Access on your Mac. You can find this in Applications/Utilities. 
  • Go to Keychain Access -> Certificate Assistant -> Request a Certificate From a Certificate Authority...
    Generate a Certificate Request
  • A 'Certificate Assistant' window will open up. Enter the required details and check 'Saved to disk' before clicking on 'Continue'.
    Certificate Assistant Window
  • Click 'Save' and then 'Done'.

Step 3. Configure App ID

In Step 1, we had created an App ID. Now, it's time to configure this App ID for push notifications. Here's how to do it.

  • Click on the App in the App ID list and click on the 'Settings' button.
  • You will see a configuration page. Scroll the page till the end and check 'Enable for Apple Push Notification Service'.
  • Under Development SSL Certificate, click 'Create Certificate'.
    Configure App ID
  • You will see the 'Add iOS Certificate' wizard. Click 'Continue'.
  • On the next page ('Generate your certificate'), click 'Choose File' to locate the certificate request that we had generated in Step 2. Then click 'Generate'.
  • Your app's SSL certificate in now ready. Click 'Done' to continue.

You need to follow the same process to generate the production certificate. 

Step 4. Create APNs Certificate

  • Download the SSL Certificate you created in the above step. Double click this .cer file to install it in Keychain Access. You provider applic