Appcelerator Blog

The Leading Resource for All Things Mobile

File Uploads with Appcelerator Arrow and ArrowDB

31 Flares 31 Flares ×

Storing data in the cloud has never been easier thanks to Appcelerator Arrow. Sometimes though you need to be able to do more than just store user input, you need the ability to upload files of varying types and sizes to support the needs of your app.

Today we’re going to look at how to solve that problem using Appcelerator ArrowBuilder, ArrowDB and ArrowWeb. Arrow is a new product offering by Appcelerator that is built on top of nodejs, and expands upon the previous Appcelerator Cloud Services (ACS) and service tier (Node.ACS).

A quick overview of Arrow

Arrow Builder is a graphical tool for connecting and integrating with data sources such as ArrowDB, SalesForce, MSSQL and many more. Through an easy to use wizard, you can create, mashup and transform data for easy consumption by any web, mobile or client application.

Arrow Web leverages Express for nodejs and incorporates several templating mechanisms for the web (EJS, Handlebars, Markdown, etc) to allow our developers to standup web interfaces fast!

If you’re not familiar with Appcelerator’s new Arrow product, I recommend you check out some of the documentation and videos to better understand this new mobile middleware for connecting applications to data and services.

Prerequisites

Before starting out, make sure that you have:

  1. An Appcelerator Account that has access rights to use ArrowBuilder. (Don’t have one? You get full access during the free trial. Sign-up here)

  2. The latest Appcelerator software -> http://web.appcelerator.com. This link provides installation packages for Mac and Windows.

Note: Arrow access requires that you have an Appcelerator Team or higher level account once you are ready to push to a production environment.

Create your Arrow Project

Now that your all set to work with Appcelerator Arrow, let start by creating a new Arrow project.

From Appcelerator Studio
  1. Open Appcelerator Studio and select your workspace.

Select Workspace

Note: If you haven’t logged into Appcelerator Studio, you will first be prompted for your Username and Password

  1. After Studio loads, from the menu bar, you can create a new Arrow project by click on File -> New -> Arrow Project

New Arrow Project

  1. In the Arrow Project Dialog, give your project a name and click Finish. In my case, I named it MyApp.

That’s all it takes to create a new Arrow project—pretty easy right?

From the Appcelerator CLI

Creating a new project from the Appcelerator CLI is easy as well. Just use the following command from your terminal / command prompt and follow the instructions:

$>appc new
	Appcelerator Command-Line Interface, version 4.1.0
	Copyright (c) 2014-2015, Appcelerator, Inc.  All Rights Reserved.

	? What type of project are you creating? Arrow App
	? What’s the project name? MyApp

	* new completed. *

Now comes the fun part. Creating an API to handle File Uploads.

Adding a new API

ArrowBuilder combined with ArrowDB allows you to quickly and easily create new APIs to help your apps connect to data sources, or leverage our cloud-based database and file storage for your mobile and web apps.

In this example we’re going to leverage Arrow to create a new API that will allow us to upload files to our app and store them using the Appcelerator ArrowDB File Object. Files stored in ArrowDB are kept securely on Amazon AWS S3 file storage, making it a great way to easily store your files.

For more about ArrowDB File storage, review our documentation here

Build the API

By default your new project will have a generate API called testapi which can be found in the MyApp/apis/testapi.js file. Since this is a tutorial we’ll just go ahead and use this stub API.

Let’s start by opening the file MyApp/apis/testapi.js and looking at the sample code.

var Arrow = require(‘arrow’);

	var TestAPI = Arrow.API.extend({
	    group: ‘testapi’,
	    path: ‘/api/testapi/:id’,
	    method: ‘GET’,
	    description: ‘this is an api that shows how to implement an API’,
	    model: ‘testuser’,
	    before: ‘preexample’,
	    after: ‘postexample’,
	    parameters: {
	        id: {description:’the test user id’}
	    },
	    action: function (req, resp, next) {
	        // invoke the model find method passing the id parameter
	        // stream the result back as response
	        resp.stream(req.model.find, req.params.id, next);
	    }
	});

	module.exports = TestAPI;

In the above code example you can see that to create your API, you’re really creating a new javascript module that is based off of the extended API object that can be found on the Arrow module. An API has several parameters associated with it, the required ones are:

  • group – The group name to associate with this API. This is used for the generated documentation.
  • description – A short description of what your API does.
  • path – The relative path used by the Express engine built into Arrow to execute the API.
  • method – The HTTP method type for the API. All HTTP verbs are supported (GET, POST, PUT, PATCH, DELETE).
  • action – The action is assigned a function that is to be called when the API is triggered.

There are additional parameters as you can see above that allow you to provide greater detail and validation to your API. For a full list of parameters see our documentation on APIs here.

For our API, we’re going to modify the default API so that it aligns with our tutorial. We’ll change the group, description, path, method, and parameters properties as well as removed some unnecessary properties (model, before, after). The before and after properties allow you to execute node JS blocks as part of your API. These can be really useful to perform validation checks or data transformation for example, but we don’t have a need for them here.

var Arrow = require(‘arrow’);

var TestAPI = Arrow.API.extend({
	group: ‘Files’,
	path: ‘/api/file’,
	method: ‘POST’,
	description: ‘Upload file to ArrowDB’,
	parameters: {
		file: {description:’file to publish’, type:’body’}
	},
	action: function (req, resp, next) {
		next();
	}
});

module.exports = TestAPI;

The parameters property lets you easily add validation to your API, telling it what it should expect as input, and what is required or optional. In our case we are specifying that the API is expecting a body element called file and that this property is required. In the event someone tries to access this API without the file property in the body of the request, then Arrow will reject the request with an error.

Handling the File

The basis for our API is complete, now we need to handle processing the file. Before we do this lets first understand how Arrow handles the files as it will help us better understand how we do this.

Arrow receives a file as part of the body via a HTTP POST request, and will download and store the file to a temporary location that can then be leveraged as part of the request object. Arrow expects this request to be multipart, so make sure your encoding the file appropriately. The file is placed on the request object off of the parameters property, and references an absolute location where the file can be reached.

To be able to process the file, we’ll need to add some additional code to the API.

At the top of the file, update the code as follows:

var Arrow = require(‘arrow’),
    File = Arrow.getModel(‘appc.arrowdb/file’),
    fs = require(‘fs’);

In the code above, we’re requesting a handle to the ArrowDB Files object as well as the standard nodejs filesystem module.

The ArrowDB Model reference allows us to get access to an instance of the File model which will allow us to create a new File to be stored in ArrowDB.

Now lets add the code to do the work. Inside the action function handler, add the following code

// req.params.file is your file object.
    if(req.params.file){
		/**
		 * Function to create and store a new file Object within ArrowDB
		 */
		Files.create({
			name: req.params.file.split("/").pop(),
			file: fs.createReadStream(req.params.file)
		}, function(err, result){

			/** Callback function handles the result */
			if(result){
				//Success!!
				resp.send(result, null, next);
			}
			else {

			  // uh oh, we hit a snag - i shouldn't have ended here.
			  next(err);
			}
		});
	}
	else {
		next();
	}

In the above code, we’re checking to see that the request object has the file path as we expect.

if(req.params.file){…}

If we have a file path, then we can proceeed with creating the new File Object in ArrowDB. Using the File.create funciton, we pass in a name in this case generated by getting the name of the original file passed, and then create stream of the file using the fs module.

file: fs.createReadStream(req.params.file)
          // ^^ creates a readable stream from the file path

Finally in the callback function, we check to ensure that we had a proper result, and then send back the result of the File.create. In the case of an error we simply reference the next function, passing in the err returned as part of the callback.

Running your Arrow Server

At this point its time to see if the magic is happening as you would expect.

In Appcelerator Studio, you can now click the Run button and run your Arrow application locally.

run-button

Once your local server is running, Appcelerator Studio will open the Arrow admin interface.

Arrow Admin Interface

In the console output you will see some important information including your API key and the url / port number to access your server locally.

Note: The port will change each time you run the local server from studio, take note of it for testing purposes.

Testing Your API

To test this API, open up your REST client of choice and test the api.

Testing the API in Rest Client

Here I am using Paw. Notice that I am referencing my local host (127.0.0.1) with the correct port number as defined in my console output in studio. The API path defined in my API file is also referenced with the correct method declaration. Because you can specify different behaviors based on the same path using HTTP methods its important to use the right one here.

For my file object, I am using an Appcelerator logo image, and as noted above I am encoding it as multipart/form-data.

If you have authentication enabled you’ll need to add the Authentication header for BasicAuth with your API key. Your API key can be found in your console oputput or in your PROJECT_DIR/conf/default.js file.

Example of Basic Authentication

The Result

Calling your new API returns a result response passed from the ArrowDB File.create function as part of its successful response.

{
  “id”:”5592efbf7cdfd70b76000e37”,
  “name”:”tmp-1435692992272appc-logo-mark.png”,
  “processed”:false,
  “createdat”:”2015-06-30T19:36:31.000Z”,
  “updatedat”:”2015-06-30T19:36:31.000Z”,
  “userid”:”5592e45ce014044625034281”
}

This response provides the id of the new file object along with additional meta data and user information.

You can also validate the successful upload of your file in the Appccelerator Dashboard. In the Dashboard, you find your ArrowDB associated with your new Arrow app, and click on Manage Data and then selecting Files.

Appcelerator Dashboard Files View

Conclusion

Allowing your users to upload their own file data can be a powerful and necessary feature for your mobile app or web app project. With Appcelerator Arrow and ArrowDB, you can support this feature quickly and easily.

31 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 31 Email -- 31 Flares ×

1 Comment

  1. hi there,

    Great tutorial – would you be able to post a link to the source code on github?

    Also, it looks like “Files” is a typo in the create function. Where is the code for the file model?

    Thanks
    Jake

Comments are closed.

Sign up for updates!

Become a mobile leader. Take the first step to scale mobile innovation throughout your enterprise.
Get in touch
computer and tablet showing Appcelerator software
Start free, grow from there.
31 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 31 Email -- 31 Flares ×