(For more resources related to this topic, see here.)
Using an external API
APIs are provided as a service from many different companies. This is not an entirely altruistic move on the part of the company. The expectation is that by providing the information and access to the company’s data, the company gets more usage for their service and more customers.
With this in mind, most (if not all) companies will require you to have an account on their system in order to access their API. This allows you to access their systems and information from within your application, but more importantly from the company’s perspective, it allows them to maintain control over how their data can be used. If you violate the company’s usage policies, they can shut off your application’s access to the data, so play nice.
The API key
Most APIs require a key in order to use them. An API key is a long string of text that gets sent as an extra parameter on any request you send to the API. The key is often composed of two separate pieces and it uniquely identifies your application to the system much like a username and a password would for a regular user account. As such it’s also a good idea to keep this key hidden in your application so that your users can’t easily get it.
While each company is different, an API key is typically a matter of filling out a web form and getting the key. Most companies do not charge for this service. However, some do limit the usage available to outside applications, so it’s a good idea to look at any restrictions the company sets on their service.
Once you have an API key you should take a look at the available functions for the API.
API functions typically come in two types – public and protected:
The public functions can simply be requested with the API key
The protected functions will also require that a user be logged into the system in order to make the request
If the API function is protected, your application will also need to know how to log in correctly with the remote system. The login functions will usually be a part of the API or a web standard such as Facebook and Google’s OAuth.
It should be noted that while OAuth is a standard, its implementation will vary depending on the service. You will need to consult the documentation for the service you are using to make sure that the features and functions you need are supported.
Be sure to read through the service’s API documentation to understand which functions you will need and if they require a login.
Another thing to understand about APIs is that they don’t always do exactly what you need them to do. You may find that you need to do a little more work than you expect to get the data you need. In this case, it’s always good to do a little bit of testing.
Many APIs offer a console interface where you can type commands directly into the system and examine the results:
This can be really helpful for digging into the data, but consoles are not always available for every API service. Another option is to send the commands in your application (along with your API credentials) and examine the data returned in the Safari console.
The drawback of this method is that the data is often returned as a single-line string that is very difficult to read as shown in the screenshot:
This is where a tool like JSONLint comes in handy. You can copy and paste the single-line string from your Safari console into the page at http://jsonlint.com and have the string formatted so that it is much easier to read and validate the string as JSON at the same time:
Once you get a hold of what data is being sent and received, you will need to set it all up in Sencha Touch.
External APIs and Sencha Touch
As we have talked about earlier in the book, you cannot use a standard AJAX request to get data from another domain. You will need to use a JSONP proxy and store to request data from an external API.
Using the API or the Safari console, you can get a good idea of the data that is coming back to you and use it to set up your model. For this example, let’s use a simple model called Category.
We can then set up a store to load data from the API:
This will set up a store with our Category model and call the url property for our external API. Remember that we have to send our credentials along with the request so we set these as extraParams on the proxy section.
The apiKey and appSecret properties shown here are examples. You will need your own API key information to use an API.
We also need to set a property called rootProperty in the reader section. Most API’s send back a ton of detailed information along with the request and the store needs some idea of where to start loading in the category records.
We can also add additional parameters later by calling the setExtraParam() function on our store proxy. This will let us add additional parameters to be sent to our external API URL.
Please note that setExtraParam() will add an additional parameter but setExtraParams() will replace all of our extraParams with the new values.
The basic application
The Decider application is designed to use a combination of local storage, Google’s Map API, and the Foursquare API. The application will take a list of people and their food preferences, and then use Foursquare and Google Maps to find nearby places to eat that will match everyone’s food preferences.
This screenshot provides a pictorial representation of the preceding explanation:
Our contacts and categories will be stored using local storage. External APIs from Google and Foursquare will generate our maps and restaurant listings respectively. We will start with a quick overview of the basic application structure and forms, before diving into the store setup and API integration.
Our main container is a simple card layout:
In this viewport we will add two cards: a navigation view and a form panel. Our navigationvew will serve as our main window for display. We will add additional containers to it via our controller:
This mainView contains our navigationBar and our homeScreen container with the big Get Started button. This button will add new containers to the navigation view (we will look at this later in the controller).
A DataStage project stores jobs and define their environment, such as their security and execution resources. Your project, as well as your user account, is typically created by your DataStage administrator.
The second item that is added to our viewport is our form panel. This will contain text fields for first and last name, as well as a selectable list for our different food categories:
We close out the form with a segmentedbutton property, which has options for Save and Cancel. We will add the handler functions for these buttons later on in our controller.
We also include a title bar at the top of the form to give the user some idea of what they are doing.
One of the key pieces of this form is the categories list, so let’s take a closer look at how it works.
Creating the categories list
Since we will be getting our list of potential restaurants from the Foursquare API, we need to use their categories as well so that we can match things up with some degree of accuracy.
The Foursquare API can be found at https://developer.foursquare.com/. As mentioned before, you will need a Foursquare account to access the API. You will also need an API key in order to integrate Foursquare with your application.
We can use the Foursquare’s API to get a list of categories, however the API returns a list of a few hundred categories including Airports, Trains, Taxis, Museums, and Restaurants. Additionally, each of these has its own subcategories. All we really want is the subcategories for Restaurants.
To make things more complicated, Foursquare’s API also returns the data like this:
This means we can only get at a specific category by its order in the array of categories. For example, if Restaurants is the twenty-third category in the array, we can get to it as: categories, but we cannot get to it by calling categories[‘Restaurants’]. Unfortunately, if we use categories and Foursquare adds a new category or changes the order, our application will break.
This is a situation where it pays to be adaptable. Foursquare’s API includes a console where we can try out our API requests. We can use this console to request the data for all of our categories and then pull the data we need into a flat file for our application. Check this URL to see the output:
We can copy just the Restaurant information that we need from categories and save this as a file called categories.json and call it from our store.
A better solution to this conundrum would be to write some server code that would request the full category list from Foursquare and then pull out just the information we are interested in. But for the sake of brevity, we will just use a flat json file.
Each of our categories are laid out like this:
The main pieces we care about are the id, name, shortname and icon values. This gives us a data model that looks like this:
Notice that we also add a function to create an image URL for the icons we need. We do this with the convert configuration, which lets us assemble the data for image URL based on the other data in the record:
The convert function is automatically passed both the data value (v), which we ignore in this case, and the record (rec), which lets us create a valid Foursquare URL by combining the icon.prefix value, a number, and the icon.suffix value in our record. If you take a look at our previous category data example, this would yield a URL of:
By changing the number we can control the size of the icon (this is part of the Foursquare API as well).
We combine this with our XTemplate:
This gives us a very attractive list for choosing our categories:
Next we need to take a look at the controller for the contact form.
Creating the contact controller
The contact controller handles saving the contact and canceling the action. We start out the controller by declaring our references and controls:
Remember that our refs (references) provide a handy shortcut we can use anywhere in the controller to get to the pieces we need. Our control section attaches tap listeners to our cancel and save buttons.
Next we need to add our two functions after the controls section. The doCancel function is really simple:
We just use our references to clear the contact editor, deselect all the items in our category list, and switch back to our main view.
The save function is a little more complex, but similar to the functions we have covered elsewhere in this book:
As with our previous save functions, we create a new MyApp.model.Contact and add the values from our form. However, since our list isn’t really a standard form component we need to grab its selections separately and add them to the contact data as a comma-separated list.
We do this by creating an empty array and using Ext.each() to loop through and run a function on all our categories. We then use join to implode the array into a comma-separated list.
Finally, we save the contact and run our doCancel function to clean up and return to our main view.
Now that we can add contacts we need to create a controller to handle our requests to the Foursquare and Google APIs, and get the data back to our users.
Integrating with Google Maps and Foursquare
Our application still has a couple of tasks to accomplish. It needs to:
Handle the click of the Get Started button
Add our maps panel and offer to adjust the current location via Google Maps API
Display a list of friends to include in our search
Display the search results in a list
Display the details for a selected result
We will start out with the basic skeleton of the controller, create the views and stores, and then finish up the controller to complete the application.
Starting the mainView.js controller
We will start the mainView.js controller file with some placeholders for the stores. We will add views later on and some references for those components.
Keep in mind that when working with placeholders in this fashion the application will not be testable until all the files are actually in place.
We create the mainView.js file in our controllers folder:
At the top of this configuration we require Ext.DateExtras. This file provides us with formatting options for date objects. If this file is not included, only the now() method for date objects will be available in your application.
In our views section we have added placeholders for confirmLocation, restaurantList, friendChooser,and restaurantDetails. We will add these files later on, along with the RestaurantStore file listed in our stores section.
We also have a number of references for these views, stores, and some of their sub-components. We will need to create these views before getting to the rest of our controller. We will take these views in the order the user will see them, starting with the confirmLocation view.
Creating the confirmLocation view
The confirmLocation view first appears when the user clicks on the Get Started button. This view will present the user with a map showing their current location and offer an option to switch to a different location if the user desires.
The following screenshot gives a pictorial representation of the preceding code:
In order to give ourselves a bit more flexibility, we will be using the Google Maps Tracker plugin as part of this view. You can find this plugin in your Sencha Touch 2 folder in examples/map/lib/plugin/google/Tracker.js. Copy the file into a lib/google folder in your main application folder and be sure to add it into the requires section of your app.js file:
This plugin will let us easily drop markers on the map.
Once the Google Tracker plugin file is included in the application, we can set up our confirmLocation.js view like so:
The view itself is a simple container with some HTML at the top asking the user to confirm their location. Next we have a map container that uses our Google Tracker plugin to configure the map and animate the location marker to drop from the top of the screen to the current location of the user. The position configuration is a default location, which is used when the user denies the application access to their current location. This one is set to the Sencha Headquarters.
Next we need a few options for the user to choose from: Cancel, New Location, and Next. We will add these as a segmented button under our map container. We add the code to the end of our items container (after the map container):
Each of our buttons has an associated action. This allows us to assign functions to each button within the mainView.js controller. By creating buttons in this fashion, we maintain separation between the display of the application and the functionality of the application. This is really helpful when you want to re-use a view component.
The next view the user encounters is the Friends Chooser.
Creating the Friends Chooser view
The friendsChooser.js file uses a similar list to our previous category chooser. This lets our users select multiple people to include in the restaurant search:
Our friendChooser extends the Ext.Container component and allows the user to select from a list of friends:
As with our previous panel, we have a container with HTML at the top to provide some instructions to the user. Below that is our list container, which, like our category list, allows for selection of multiple items via the mode: ‘MULTI’ configuration. We also set grouped to true. This allows our store to group the contacts together by last name.
If you take a look at the ContactStore.js file, you can see where we do:
This configuration returns the first letter of the last name for grouping.
The last thing we need to do with our friendChooser.js file is add the buttons at the bottom to Cancel or Finish the search. The buttons go out in the items section, just below the list:
As in our previous view, we use a segmentedbutton property with actions assigned to each of our individual buttons.
Once the user clicks on Finish, we will need to return a list of restaurants they can select from.
Creating the restaurant list, store, and details
Our restaurant list will use a store and the Foursquare API to return a list of restaurants based on the shared preferences of everyone the user selected.
The following screenshot exemplifies the preceding explanation:
This component is pretty basic:
This component uses a simple list with a configuration option for onItemDisclosure:true. This places an arrow next to the restaurant name in the list. The user will be able to click on the arrow and see the details for that restaurant (which we will create after the store).
We also set grouped to true, only this time our store will use a function to calculate and sort by distance.
Creating the restaurant store and model
The restaurant store is where we set up our request to the Foursquare API:
The RestaurantStore.js file sets a model and storeId field for our store and then defines our proxy. The proxy section is where we set up our request to Foursquare.
As we mentioned at the start of the article, this needs to be a jsonp request since it is going to another domain. We make our request to https://api.foursquare. com/v2/venues/search and we are looking for the responses.venues section of the JSON array that gets returned.
You will note that this store currently has no other parameters to send to Foursquare. We will add these later on in the controller before we load the store.
For the model, we can consult the Foursquare API documentation to see the information that is returned for a restaurant (called a venue in Foursquare terms) at https://developer.foursquare.com/docs/responses/venue
You can include any of the fields listed on the page. For this app, we have chosen to include the following code in our model:
You can add more fields if you want to display more information in the details view.
Creating the details view
The details view is a simple panel and XTemplate combination. Using our controller, the panel will receive the data record when a user clicks on a restaurant in the list:
Since the tpl tag is basically HTML, you can use any CSS styling you like here. Keep in mind that certain fields such as contact, location, and categories can have more than one entry. You will need to use
Now that the views are complete, we need to head back to our controller and add the functions to put everything together.
Finishing the main view controller
When we started out with our main controller, we added all of our views, stores, and references. Now it’s time to add the functionality for the application. We start by adding a control section to the end of our config:
The controls are based on the references in the controller and they add functions to specific listeners on the component. These are each in the format of:
Once these controls are in place, we can add our functions after the config section of our controller.
Our first function is doStart. This function loads our Contacts store and checks to see if we have any existing contacts. If not, we alert the user and offer to let them add some. If they have contacts we create a new instance of our confirmLocation container and push it onto the main navigation view:
Remember that since the mainView is a navigation view, a Back button will automatically be created in the top toolbar. This function will show the user our initial map panel with the users current location.
This panel needs four functions: one to cancel the request, one to pop up a new location window, one to set the new location, and one to move on to the next step:
We actually want to be able to use the doCancel function from anywhere in the process. As we add new panels to our mainView navigation, these panels simply pile up in a stack. This means we need to get the number of panels currently on the mainView stack. We use length-1 to always leave the initial panel (the one with our big Get Started button) on the stack. We use pop to remove all but the first panel from the stack. This way the Cancel button will take us all the way back to the beginning of our stack, while the Back button will take us back just to the previous step.
The next function is doNewLocation(), which uses Ext.Msg.prompt to ask the user to enter a new location:
If the user enters a new location, we call setNewLocation to process the text the user entered in the prompt textbox:
This code gets our map and encodes the text the user passed us as a geocode location. If Google returns a valid address, we center the map on the location and drop a marker to show the exact location. We also set the latitude and longitude so that we can reference them later.
If we fail to get a valid address, we alert the user so they can fix it and try again.
Once the user is happy with the location they can click on the Next button, which fires our doChooseFriends function:
This function pushes our friendchooser view onto the stack for display. The friendchooser view allows the user to select multiple friends and click on Cancel or Finish.
Since we have already taken care of our Cancel button with our doCancel function, we just need to write the doShowRestaurants function.
This function starts by looping through the selected friends. For the first one in the list, we grab the restaurant categories we have stored for the friend and convert it from a comma-separated list (which is how we stored it) into an array.
This lets us grab every subsequent selection and run Ext.Array.intersect() to find the common categories between all of the selected friends:
Next, we load the store based on the common categories by categoryID, the location data we have stored in our map, client_id, and client_secret that comprise our API key for Foursquare and a radius value (in meters).
We also send a required field called v that is set to the current date.
Finally, we push our restaurant list component onto the stack of containers. This will display our list of results and allow the user to click on for details.
This brings us to our doShowRestaurantDetails function:
When the user taps one of the disclosure icons in our list of restaurants, we push a restaurantdetails view onto the stack of containers and set its data to the record that was tapped. This displays the details for the restaurant in our details XTemplate
There are a number of additional features that can be added to this type of application, including:
Editing for contacts (or automatically pulling friends from Facebook)
Setting up a live feed for the categories menu
Adding additional venues other than restaurants
Combining the application with additional APIs such as Yelp for reviews
Just remember the key requirements of using additional APIs: the API key(s), studying the API documentation, and using the JSONP store for grabbing the data.
In this article we talked about using external APIs to enhance your Sencha Touch applications. This included:
An overview of API basics
Putting together the basic application
Interaction with Google Maps and Foursquare
Building the views, models, and stores
Building the application controller
Resources for Article :
- How to Use jQuery Mobile Grid and Columns Layout [Article]
- An Introduction to Rhomobile [Article]