Appstax REST API Guide

No SDK for you? Don't worry, our REST-api got you covered.

Getting started

The Appstax REST API lets you use the Appstax data storage through regular HTTPS calls. To use the API you will need to have an Appstax account, and an AppKey that is valid for an app. To get started, follow these simple steps:

A quick note before we start

As we work through the examples in this guide we demonstrate the API using the curl tool. This is standard on Mac OS X and Unix-related platforms. If you are on Windows you can download a Windows copy of curl. We use the following command line options :

 
    curl -X "http verb" "url" 
    -H "http header"
    -H "another http header"
    -d "request body contents"
    

Note also that the urls will always be anchored at /api/latest.

Application keys

We need to tell Appstax which app we are acting on. We do this by sending an HTTP header named x-appstax-appkey. The value should be the same value as the AppKey we retrieved in step 2 under Getting Started. To make our life easier throughout the examples we will store the appkey in a shell environment variable, like so on Unix-like systems:

     
    export APPSTAX_APPKEY="yourAppstaxappkeygoeshere"
    

Now let's get to work!


Working with objects

Create an object

Assume we have created our app and that we have created a collection named Notes. We now wish to create new notes objects and store them in our collection.

     
    curl -X POST https://www.appstax.com/api/latest/objects/Notes \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H 'Content-Type:application/json' \
    -d '{"title":"This is my first note", "contents":"The note is short."}' 
    

Before you can create objects from code you must define your collection using the Appstax admin web interface.

So, for example, if you want to start saving Notes objects to Appstax you must first log on to appstax.com and create a collection named Notes.

Remember that collection names are case sensitive, so a collection named Notes won't match https://www.appstax.com/api/latest/objects/notes

The above command results in the following response from Appstax::

     
    {
        "sysObjectId":"QZXRpyhazyJm", 
        "sysCreated":"2014-08-04 14:18:22.767631811",
        "sysUpdated":"2014-08-04 14:18:22.767631811"
    }

As you can see, Appstax adds three properties to your object automatically. Note that any properties added by Appstax - for whatever reason - will start with sys as prefix, for example, sysObjectId or sysCreated.

The most important of these is the sysObjectId property, which is the system-generated ID of the object that you use to reference the object in subsequent calls to Appstax.

Retrieve an object

To retrieve an existing object you add the object's sysObjectId to the URL path, as shown below:

     
    curl -X GET https://www.appstax.com/api/latest/objects/Notes/QZXRpyhazyJm \
    -H "x-appstax-appkey:$APPSTAX_APPKEY"

This results in the following response from Appstax:

     
    {   
        "title": "This is my first note", 
        "contents": "The note is short.", 
        "sysCreated": "2014-08-04T14:18:22.767631811", 
        "sysUpdated": "2014-08-04T14:18:22.767631811", 
        "sysObjectId": "QZXRpyhazyJm"
    }

Retrieve multiple objects simultanously

To retrieve several objects in one request send a request to the object's base URL path, and add the URL parameter objects with a comma-separated list of the objects you wish to retrieve.

     
    curl -X GET https://www.appstax.com/api/latest/objects/Notes?objects=QZXRpyhazyJm,B6ZmZ6UenoeJ \
    -H "x-appstax-appkey:$APPSTAX_APPKEY"

This results in the following response from Appstax:

     
    { 
        "objects" : [
            {
                "title": "This is my first note", 
                "contents": "The note is short.", 
                "sysCreated": "2014-08-04T14:18:22.767631811", 
                "sysUpdated": "2014-08-04T14:18:22.767631811", 
                "sysObjectId": "QZXRpyhazyJm"
            },
            {
                ... second object 
            }

        ]  
    }

Update an object

To update an existing object you add the object's sysObjectId to the URL path, in the same fashion as above when retrieving. In addition you supply the full JSON document describing the updated object. Only those object properties that are part of the request body JSON will be assigned new values.

     
    curl -X PUT https://www.appstax.com/api/latest/objects/Notes/QZXRpyhazyJm \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H 'Content-Type:application/json' \
    -d '{"title":"An updated tite"}' 
    

In the above example, only the title will be updated (the contents will not.)

When successful this results in an empty response from Appstax, with a HTTP status code = 204 No Response

Delete an object

Deleting an object is even simpler than updating. You supply the object's ID (sysObjectId) in the URL path, but you do not need to provide any data.

     
    curl -X DELETE https://www.appstax.com/api/latest/objects/Notes/QZXRpyhazyJm \
    -H "x-appstax-appkey:$APPSTAX_APPKEY"
    

When successful this results in an empty response from Appstax, with a HTTP status code = 204 No Response


Working with users

Up until now all our objects have been created anonymously. We have not specified any owners of the objects, they are accessible by any end user. We will now let users sign up and create their own objects, accessible only by them.

Security note: Make sure you review the users collection permissions in the Admin UI. If you are using email addresses as usernames or are otherwise storing sensitive information in user objects, set the "read" permissions to "owner" or "admin" level.

Signup a user

     
    curl -X POST https://www.appstax.com/api/latest/users \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H 'Content-Type:application/json' \
    -d '{"sysUsername":"iamanenduser","sysPassword":"mypassword", "organization":"An organization"}' 
    

As you can see, to create a new end user for your app you supply a JSON document with at least two properties, sysUsername and sysPassword. Appstax expects these two properties to contain the user's username and password respectively. You can also supply other properties in addition to these two, but you MUST supply these two for the operation to be successful.

This results in the following response from Appstax:

     
    {
        "sysSessionId":"MDNkNDA5NGEtZjJmZi00Y2NmLTdkMTktMTMwZWY1NDFiYTA4", 
        "user":{
            "sysCreated": "2014-08-04T14:58:00.813799687", 
            "sysUpdated": "2014-08-04T14:58:00.813799687", 
            "sysObjectId": "YevzQ1SGVP8O"
        }
    }
    

Appstax treats end users as regular objects and they therefore have sysObjectId, sysCreated and sysUpdated properties. The sysSessionId is another system-generated value on par with the Appstax-AppKey, and represents a session token for an authenticated end user. This also means that when the user is created she is also automatically signed in.

Logging a user in or out

Login and logout for end users are managed through sessions. To log a user in or out you create or delete sessions using POST or DELETE on /sessions.

Login

     
    curl -X POST https://www.appstax.com/api/latest/sessions \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H 'Content-Type:application/json' \
    -d '{"sysUsername":"iamanenduser","sysPassword":"mypassword"}' 
    

Logout

     
    curl -X DELETE https://www.appstax.com/api/latest/sessions/MDNkNDA5NGEtZjJmZi00Y2NmLTdkMTktMTMwZWY1NDFiYTA4 \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: MDNkNDA5NGEtZjJmZi00Y2NmLTdkMTktMTMwZWY1NDFiYTA4" 
    

When successful this results in an empty response from Appstax, with a HTTP status code = 204 No Response

As you can see, this is very similar to how you create end users, except you POST to the /sessions path rather than the /users path::

     
    {
        "sysSessionId":"YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2", 
        "user":{
            "sysCreated": "2014-08-04T14:58:00.813799687+02:00", 
            "sysUpdated": "2014-08-04T14:58:00.813799687+02:00", 
            "sysObjectId": "YevzQ1SGVP8O"
        }
    }
    

Whenever you are working with end users and creating, reading, updating or deleting objects you need to supply the HTTP header x-appstax-sessionid with the value that was returned in the response from the server when logging that end user in. The x-appstax-sessionid token is what identifies the end user as an authenticated user.

If you create an object without this header the object will be anonymous and not owned by the user. If you attempt to read, update or delete objects that you know are owned by a particular end user, but do not supply the header, you will receive a 401 Not Authorized message from the server, indicating that the particular end user does not have read/update/delete access to that particular object.

Because x-appstax-sessionid gives the caller access to a particular user's objects, it should be kept private and not shared or made public.

Password reset

Endusers forget passwords, or will want to reset their passwords. How you handle resetting passwords is (almost) entirely up to you the developer. We provide two HTTP endpoints to enable the process.

First, your app must call the endpoint /users/reset/email. This sends an email to the user with an auto-generated pincode. The contents of this email is up to you, and can be modified through the AppStax Admin UI.

You may want to set the following fields:

  • From: myapp@myapp.com
  • From name: My App
  • Subject:
  • Text: Here is a pin code to reset your password: ${PINCODE}

The text is a template, and we expect it to contain the text ${PINCODE}, so we can insert the auto-generated pincode.

Send password reset email

     
    curl -X POST https://www.appstax.com/api/latest/users/reset/email \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H 'Content-Type:application/json' \
    -d '{"email":"xxx@xxx.com"}' 
    

Given the email with the pincode, the user will want to come back to your app and type in the pincode. For example, you might provide a link in the email that takes the user to a custom form where s/he can paste in the username and pincode.

Reset password with pincode

From a password reset form that you make, you can call a second HTTP endpoint /users/reset/password, to actually reset the password.

     
    curl -X POST https://www.appstax.com/api/latest/users/reset/password \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H 'Content-Type:application/json' \
    -d '{"username":"xxx@xxx.com", "password": "...", "pinCode": "6392"}' 
    

Note that the pin code will only be valid for 10 minutes.

Note also that this currently only works if users actually provide emails as their usernames.

Working with objects owned by end users

To make an object owned by a particular end user, you must supply the user session's x-appstax-sessionid along with the HTTP request.

Creating

     
    curl -X POST https://www.appstax.com/api/latest/objects/Notes \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H 'Content-Type:application/json' \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" \
    -d '{"title":"This is my first note","contents":"The note is short."}' 
    

Now, assuming that the return sysObjectId is YevzQ1SGVP8O, updating, reading and deleting the object is done as follows:

Reading

     
    curl -X GET https://www.appstax.com/api/latest/objects/Notes/YevzQ1SGVP8O \
    -H "x-appstax-appkey:$APPSTAX_APPKEY"
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" \
    

Updating

     
    curl -X PUT https://www.appstax.com/api/latest/objects/Notes/YevzQ1SGVP8O \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H 'Content-Type:application/json' \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" \
    -d '{"title":"An updated tite","contents":"The note has been updated."}' 
    

Deleting

     
    curl -X DELETE https://www.appstax.com/api/latest/objects/Notes/YevzQ1SGVP8O \
    -H "x-appstax-appkey:$APPSTAX_APPKEY"
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" \
    

Querying objects

Very often you will need to find multiple objects in a collection, based on a particular search criteria. For example, you may wish to add a feature to your app that allows the user to look for all Notes where the title starts with TODO, or perhaps where the contens contains the text Appstax.

Here is a simple example that looks for all notes in the Notes collection where the title equals the string literal TODO:

     
    curl -X GET https://www.appstax.com/api/latest/objects/Notes \
    --data-urlencode "filter=title='TODO'" \
    -H "x-appstax-appkey:$APPSTAX_APPKEY"
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" 
    

A couple of things to note. First, search criteria are specified using the filter URL query parameter. Second, the filter query parameter will usually contain characters that need to be URL encoded, in this example we need to encode the parameters using the --data-urlencode parameter to curl.

The actual URL sent over the wire is:

https://www.appstax.com/api/latest/objects/Notes?filter=title='TODO' (unencoded)

https://www.appstax.com/api/latest/objects/Notes?filter=title%3D%27TODO%27 (URL encoded)

Most http request libraries have facilities to easily encode URLs

Filtering

The filter parameter accepts a wide variety of operators, like and/or/not as well as + (addition), - (subtraction), * (multiplication) and / (division). The filter works very similar to the database quering language SQL. Here are som examples of filtering to get you going.

Filter Explanation
title <> 'TODO' All objects where title does not equal 'TODO'
Age > 42 All objects where age is greater than 42
Age between 40 and 49 All objects where age is between 40 and 49
Gender in ('F', 'f', 'M', 'm') All objects where gender equals \n one of the four characters in the parenthesis
Contents like '%Appstax is great!%' All objects where contents contains the string 'Appstax is great!.
Contents not like '%Appstax is great!%' All objects where contents contains the string 'Appstax is great!.
Age > 42 and name like 'Alex%' All objects where age is greater than 42 and name starts with 'Alex'
Age < 42 or name like 'Alex%' All objects where age is greater than 42 or name starts with 'Alex'
[first-name] = [last-name] All objects where first-name equals last-name. Note that when the name of the collection column contains a dash (-), then you must enclose all references to the column with brackets.
Age between 30 and 39 or (gender = 'M' and country = 'NORWAY') All objects where age is between 30 and 39 or gender is male and country is NORWAY
Contents not like '%Appstax is great!%' All objects where contents contains the string 'Appstax is great!.

Just to let you see how this works, here is the last filter using curl:

     
    curl -X GET https://www.appstax.com/api/latest/objects/Notes \
    --data-urlencode "filter=Age between 30 and 39 or (gender='M' and country='NORWAY') \
    -H "x-appstax-appkey:$APPSTAX_APPKEY"
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" 
    

As the examples show, it is easy to create arbitrarily complex queries.

Compression

If your objects are large, or if you retrieve many objects (ie hundreds) you can improve performance by asking Appstax to compress the results. This will reduce the size of the HTTP response by about 90% at the cost of having to decompress the results on the client side. There are two ways to ask for compression. You can either specify an Accept-Encoding: gzip HTTP header, or you can specify an URL parameter compress=yes. They both work exactly the same.

The following call asks for gzip-compression using the "compress=yes" URL parameter method:

     
    curl -X GET https://www.appstax.com/api/latest/objects/Notes \
    --data-urlencode "filter=Age > 20" \
    --data-urlencode "compress=yes" \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" 
    

The following call asks for compression using the "Accept-Encoding: gzip" HTTP header method:

     
    curl -X GET https://www.appstax.com/api/latest/objects/Notes \
    --data-urlencode "filter=Age > 20" \
    -H "Accept-Encoding: gzip" \
    -H "x-appstax-appkey:$APPSTAX_APPKEY"
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" 
    

Note that Appstax currently supports gzip-compression only.

When to use compression

For best results you should use compression when you expect the result set to be particularly large, either because there are a large number of objects being returned, and/or the objects are large in and of themselves (ie they contain many properties with a large amount of data). The larger the size of the HTTP response, the greater the benefit of compression. You do not need to use compression when you expect only a few objects to be returned and the objects are small. In such cases, compression will usually only result in unnecessary overhead.

Controlling access to objects

By default, an object can only be accessed by the user that created it. This provides a very secure foundation for your app. But many times you want users to share data with each other, for example in social or collaboration apps.

Sharing objects between users

For two users to share an object, the user that created it must grant permissions on the object with the username of the other user:

     
    curl -X POST https://www.appstax.com/api/latest/permissions
    -H "x-appstax-appkey:$APPSTAX_APPKEY"
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" 
    -d \
    '{
        "grants":[
            { "sysObjectId": "id1", "username": "buddy", "permissions": ["read", "update"] },
            { "sysObjectId": "id2", "username": "friend", "permissions": ["read"] }
        ], 
        "revokes":[
            { "sysObjectId": "id1", "username": "badboy", "permissions": ["delete"] }
        ] 
   }'
   

The example does several things. It gives "read" and "update" permissions on the object with id1 to "buddy", but "buddy" will not be able to delete the note or give anyone else access. It also gives "read" permission on id2 to "friend". And finally, it takes away (revokes) "delete" permission from "badboy" on id1.

As you can see, you can grant and revoke different permissions to several users on several objects in one POST request. (The grants are executed before the revokes.)

The following table lists all permissions a user could have for an object:

With permission ... ... user is able to
read Retrieve the object and view all its properties. It will also be included in queries executed by other users.
update Change property values on the object and save it.
delete Delete the object from storage.
grant read Grant and revoke "read" access to others.
grant update Grant and revoke "update" access to others.
grant delete Grant and revoke "delete" access to others.

Public access

In some applications you will want everyone, including anonymous users, to see or interact with objects. Some use cases are wikis, blogging and public photo sharing applications. You use the special username * to indicate that a permission should be granted to or revoked from the public.

     
    curl -X POST https://www.appstax.com/api/latest/permissions
    -H "x-appstax-appkey:$APPSTAX_APPKEY"
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" 
    -d \
    '{
        "grants":[
            { "sysObjectId": "id1", "*": "buddy", "permissions": ["read", "update"] }
        ], 
        "revokes":[
            { "sysObjectId": "id1", "Username": "*", "permissions": ["delete"] }
        ] 
   }'
   

Working with files

Storing files with objects

Your objects can have properties that are files. To do this you need to follow the following steps:

  1. Create a collection column of type file in the Appstax admin web interface
  2. POST or PUT an object with the filename using the /objects endpoint
  3. PUT the actual file data using the /files endpoint

Step 1

This is standard operating procedure, just go to appstax.com and create the column in the Appstax admin. For the Notes example we've been using, let's assume we want a property Image in our Notes collection, and we want this property to be of type file.

Step 2

Before we upload the actual file, we need to make sure we have an object we can attach the file to. Let's POST a new object:

     
    curl -X POST https://www.appstax.com/api/latest/objects/Notes                \
    -H "x-appstax-appkey:$APPSTAX_APPKEY"                                       \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2"  \
    -H 'Content-Type:application/json'              \
    -d '{                                           \
            "title":"This is my first note",        \
            "description":"The note is short.",     \
            "image": {                              \
                "sysDatatype" : "file",             \
                "filename" : "myimage.png"          \
            }                                       \
        }' 
   

Note how we specified the image property. It was a little different. Instead of just passing it a string or a number (as we would if it were of type string or number), we pass it an object with two properties, SysDatatype and Filename. For the file datatype to work, you have to specify the property this way, otherwise the system will not recognize the property datatype as file in step 3, when you upload the file contents. For files the sysDatatype property must always have the value "file", but of course the filename property should have the filename you want it to have.

Step 3

Now we can upload the file data, for example:

     
   curl -X PUT https://www.appstax.com/api/latest/files/Notes/JjKZnbTA85ml/image/myimage.png \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2ID" 
    -F filedata=@myimage.png
   

Again, note that the filename specfied in the URL must correspond to the value for the "Filename" property specified in Step 2.

Multiple files per object

You can have more than one property of datatype "file" per object. For example, the following object has two properties, smallImage and largeImage:

     

    curl -X POST https://www.appstax.com/api/latest/objects/Notes \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2" 
    -H 'Content-Type:application/json' \
    -d '{ \
            "title":"This is my first note",
            "description":"The note is short.", 
            "smallImage": {
                "sysDatatype" : "file",
                "filename" : "smallimage.png"
            },
            "largeImage": {
                "sysDatatype" : "file",
                "filename" : "largeimage.png"
            }
        }' 
   

Uploading the two images requires two requests:

     
   curl -X PUT https://www.appstax.com/api/latest/files/Notes/JjKZnbTA85ml/smallImage/smallimage.png \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2ID" 
    -F filedata=@smallimage.png

   curl -X PUT https://www.appstax.com/api/latest/files/Notes/JjKZnbTA85ml/largeImage/largeimage.png \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2ID" 
    -F filedata=@largeimage.png
   

File permissions

Users always have the same permissions on files as they have on the objects that the files belong to. To be able to store a file using the PUT /files endpoint a user must have update permission on the object containing the file.

Retrieving files

To retrieve files we GET them as if they are regular resources on the Web, using the same URL as we used when uploading the file.

     
   curl -X GET https://www.appstax.com/api/latest/files/Notes/JjKZnbTA85ml/smallImage/smallimage.png \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2ID" 

   

Retrieving objects with file properties

When you retrieve an object which has a file property, the response will include the URL to retrieve that object in a special url property:

     
   curl -X GET https://www.appstax.com/api/latest/files/Notes/JjKZnbTA85ml \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2ID" 
   

returns:

     
    { 
        "title":"This is my first note",
        "description":"The note is short.", 
        "smallImage": {
            "sysDatatype" : "file",
            "filename" : "smallimage.png",
            "url": "files/Notes/JjKZnbTA85ml/smallImage/smallimage.png"
        },
        "largeImage": {
            "sysDatatype" : "file",
            "filename" : "largeimage.png",
            "url": "files/Notes/JjKZnbTA85ml/largeImage/largeimage.png"
        }
    } 
   

Creating objects and files simultanously

(This section is for advanced users.)

It is possible to create an object and in the same request save a file (or several files) associated with the object. This is useful for scenarios where you want users to be able to create objects (and attach files), but not update the objects later.

To create an object and save a file simultanously we use a HTTP multipart request. One part must include the object data, and the other parts must include the file data. Read more about multipart requests here: The Multipart Content-Type and A Complex Multipart Example.

An example of an acceptable multipart request header that creates an object and saves a file with the same request is:

     
        --9a3862a514cb4bb39369d4d03f1abd27
        Content-Disposition: form-data; name="Contents"; filename="mycontents.docx"

        <... binary data ...>

        --9a3862a514cb4bb39369d4d03f1abd27
        Content-Disposition: form-data; name="sysObjectData"; filename="0"
        Content-Type: application/json

        {
            "Title": "42", 
            "Description": "a description", 
            "Contents": {"filename": "mycontents.docx", "sysDatatype": "file"}, 
            "Tarball": {"filename": "mytarball.docx", "sysDatatype": "file"}}
        --9a3862a514cb4bb39369d4d03f1abd27--
    

For Appstax, there are two special rules to follow:

First, the part of the HTTP request that contains the JSON data for our object must have a Content-Disposition header of the following form.

     
    Content-Disposition: form-data; name="sysObjectData"; 
    Content-Type: application/json

    { ... json data ... }
    
    }

The important element is name="sysObjectData", this tells Appstax which part contains the object data. The Content-Type must be application/json.

Second, for the part(s) that contains the binary data, the Content-Disposition header must be of the following form:

     
    Content-Disposition: form-data; name="Contents"; filename="mycontents.docx"

    ... binary data ...
    
    }

The name="Contents" indicates which property this binary data belongs to, and the filename="mycontents.docx" indicates the filename the file will be associated with.

Note also that in the example above the object also has a second property Tarball, but the request did not include the binary data for this.

Relations

You can create relations between objects. A relation between one object and the other means that the first object holds a reference to the other, but the other object lives completely independent of the first object. The benefit of using relations comes from the ability to easily expand the first object and retrieve all objects that participate in relation to the first object.

An example should make this clear. Let's say we are building a social app and we want to manage users' timelines. A user can post messages to his or her timeline, which other users can read. So we can create a timelines collection to hold timelines, and a messages collection to hold messages.

For a particular user's timeline, we can now create a relation from the collection timelines to the collection messages. This then let's us create relations between objects of these two collections. Relations can be singular, ie one objects holds a reference to exactly one other object (one-to-one), or it can be an array (one-to-many), meaning one object can hold a reference to many other objects.

To setup relations, go to the Appstax admin interface and click the tab relations. For this example, all relations are of type "array" (one-to-many)

Creating relations between two objects

Assuming the existence of a relation between two collections, we can make two objects participate in a relation, by updating the object:

     
   curl -X PUT https://www.appstax.com/api/latest/objects/timelines/JjKZnbTA85ml \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2ID" 
    -d '{ \
            " ... other properties to update here ...",
            "messages": {
                "sysRelationChanges" : {
                    "additions" : ["id1", "id2"],
                    "removals" : ["id3"]
                }
            },
            "comments": {
                "sysRelationChanges" : {
                    "additions" : ["id4"],
                    "removals" : ["id8"]
                }

            }
        }' 
   

Relations between objects are managed using the special property sysRelationChanges. When interacting with objects that have relations, each property that is a relation has to have the sysRelationChanges property, and this property has to have two properties: additions and removals. These are arrays that contain the sysObjectId for each object to add to or remove from the relation.

The above example creates a new relation between the object JjKZnbTA85ml of collection timelines and the objects id1 and id2 of collection messages.

As the example above shows, you can include several relations in one API request. Of course, the relations must all be defined for the timelines collection, but they can reference different collections.

As you probably saw, you don't have to specify which relation the properties participate in, Appstax figures that out for you.

If you would like to add the relations in the same request that you are creating the object, you can change the above PUT to POST. The POST then creates the object and simultanously creates the object relations.

One last thing: so far all the relations we have talked about have been one-to-many. To define one-to-one relations, define them as single in the Appstax admin interface. Then, when assigning new relations, Appstax will validate that the additions and removals arrays contain only one object id.

Expanding relation between objects

Relations are useful because it let's you more easily retrieve related objects. An example will make this clear. Let's say we have defined relations between a timelineand several messages. Imagine further that each message has a relation to several comments, in the sense that each message can have several comments. In other words, there is a relation hierarchy of two levels, one from timelinesto messages and one from messages to comments.

Now, given a timeline, we can retrieve all messages related to this timeline by adding the URL parameter expanddepth whose value is the number of levels to expand. If we want to retrieve a specific timeline object and all messages related to that timeline, and also all comments related to all those messages, we want expanddepth=2, as follows:

     
   curl -X GET https://www.appstax.com/api/latest/objects/timelines/JjKZnbTA85ml?expanddepth=2 \
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2ID" 
   

The request returns all objects participating in the relation, that the user can see. The result looks like the following:

     
   {
        "... other timeline properties ",

        "messages" : {
            "sysDatatype" : "relation",
            "sysCollection": "messages",
            "sysObjects" : [
                { 
                    "sysObjectId" : "id1",
                    "... other messages properties ...",
                    "comments" : {
                        "sysDatatype" : "relation",
                        "sysRelationType" : "array",
                        "sysCollection" : "comments",
                        "sysObjects" : [
                            "sysObjectId" : "id5",
                            "title" : "my title",
                            " ... other properties ... "
                        ]
                    },
                    { ... other comments ... }
                },
                { ... other messages ... }
            ],
            "sysRelationType" : "array"
        }

   

As you can see, expanding several layers is a powerful mechanism to easily retrieve many related objects, but it can also very quickly retrieve lots and lots of unnecessary objects.

For one-to-one (single) relations, the output is the same, but the sysObjects array will have only zero or one element.

If several relations are defined for the collection, the request above retrieves all of them.

Given the relationship hierarchy described above, if you had only specified expanddepth=1, then the comments array under each message would not be expanded and you would retrieve an array of sysObjectId instead of the actual objects.

     

           "comments" : [ "id1", "id2", "id3"]

    

The has operator

The has operator allows some very powerful queries. Imagine a relation from a books collection to an authorscollection. Each book has a number of authors. The semantics described so far make it natural and easy to think of queries that retrieve certain books and their authors.

But what if we need to go the other way around? What if we have a certain author and need to retrieve the books written by this author? So long as the relation from books to authors is defined, we can do this by adding a filter containing a special operator has. So assuming we have an author with sysObjectId xyz, we can filter like this:

  • filter = authors has ('xyz')

An example with two authors, xyz or abc:

     
   curl -X GET https://www.appstax.com/api/latest/objects/timelines?filter=authors has ('xyz', 'abc') \ # the filter string must of course be url encoded properly!
    -H "x-appstax-appkey:$APPSTAX_APPKEY" \
    -H "x-appstax-sessionid: YzA0Yzc4N2YtMDc3NS00ZjIwLTU1YjAtZjdlOWFiYWIyNTg2ID" 
   

... retrieves all books written by the author xyz or abc.