Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Write Your Mobile App With a Graph Database Backend

DZone's Guide to

Write Your Mobile App With a Graph Database Backend

The size and complexity of mobile apps is growing fast. Learn how to use OrientDB, a database solution with an HTTP REST API available out-of-the-box, with iOS.

· Mobile Zone
Free Resource

Download this comprehensive Mobile Testing Reference Guide to help prioritize which mobile devices and OSs to test against, brought to you in partnership with Sauce Labs.

Out-of-the-Box Database HTTP REST API and E-Commerce App

Mobile apps are growing, literally. Our apps and devices add more functionality, components, and sensors with each generation, which also drives up the size and complexity of our applications.

This complexity influences the amount of data we must persist and store in our apps. That means our databases are getting bigger and our data models are getting more complicated.

For storage on iOS, simple key-value plists don’t cut it for most applications. CoreData is known to be finicky and resorting to SQLite is usually necessary.

And then what about server side? There are many options out there and solutions are constantly evolving. Parse was a go-to platform for a while until Facebook discontinued and open-sourced it, while Google acquired Firebase.

If you’re working on an enterprise mobile application, this volatile database environment remains questionable. How will you plan to support your app in a year or two from now? Often, this is why it can be risky to choose a new technology to use in your stack.

OrientDB

I’m continuing to implement and test OrientDB in my applications, and I have been happy with its performance. OrientDB is an established platform that has been around since 2010, yet is a leading database solution in terms of modern features and performance.

OrientDB is an enterprise multi-model database solution with many advantages over traditional relational databases.

Plus, it has an HTTP REST API available out-of-the-box that our mobile apps can immediately start interacting with.

If you want to learn more about OrientDB and its REST API before we dive into iOS implementation, visit my earlier tutorial here.

ComputerStore Mobile App

Here, we’ll simulate developing an e-commerce mobile app for our “ComputerStore,” continued from our first tutorial. If you haven’t already, I suggest reviewing the use cases and data model in that tutorial. We’ll be writing this in Swift using XCode 8 on iOS 10.

As a quick refresher, our store will be selling six different products:

  1. Apple MacBook Pro
  2. Samsung Galaxy Phone
  3. Dell Inspiron Desktop
  4. 8 GB Memory
  5. 16 GB Memory
  6. Accelerometer

These Products have relationships of their Components and other Products that they are CompatibleWith, using graph Edges.

In the last tutorial, we analyzed each request and response pair that our ComputerStore would need to interact with our database via the HTTP REST API. Our mobile app will leverage the same HTTP REST API from the first tutorial, and we will walk through implementing that API on iOS.

We outlined a series of user stories that any e-commerce store would need to implement to create a successful user journey. If a customer downloads our app, we want to allow them to sign-in, see our products, make a purchase, and view their orders.

Those user stories are:

  • A user opens our store app and wants to sign-in (Connect).
  • A user views our catalog of products (Products).
  • A user drills down to view the components of a product (Components).
  • A user decides to make a purchase (CreateOrder).
  • A user wants to see their orders (Orders).

Visually, the user journey would look like this:

Translating that user journey into a storyboard for our app. We’ll need the following view controllers.

Storyboard & ViewControllers

  1. A user opens our store app and wants to sign-in: LoginViewController.
  2. A user enters the store and views options: MainViewController.
  3. A user views our catalog of products: ProductsTableViewController.
  4. A user drills down to view the components of a product: ProductDetailViewController.
  5. A user decides to make a purchase: ProductDetailViewController.
  6. A user wants to see their orders: OrdersTableViewController.

We’ll also create Swift classes to represent the objects in our Products and Orders tables:

  • Product
  • Order

Finally, our views and view controllers will share information stored in Globals.swift, which we’ll use for simplicity. If we were building an enterprise application, we would like want to implement a more robust StoreManager class.

Users

We won’t implement a registration process here, so to start, create a couple customer users in your OrientDB database with full permissions. In a production application, you’d want to limit the access control to only what is necessary.

We’ll use these users to log in and associate with their orders.

OrientDB Studio.

Project Setup

Now, let’s head over to XCode to start building our app. Create a new project. We can start with a Single View Application. Set the language to Swift and we’ll set our device to iPhone.

If you’re new to iOS development, it may be useful to follow along with the code in our GitHub repository.

When downloading the project, you will likely need to use Cocoapods or download the associated libraries as well.

There are a few iOS libraries that we’ll be using to help us interact with the API. These are common in iOS. Either download via CocoaPods or manually install these into your project.

We’ll start by laying out the Storyboard that we’ll use for our app. XCode’s Interface Builder is a great drag-and-drop UI tool. We’ll have an initial login screen, LoginViewController. Upon login, we’ll navigate to the Welcome screen, MainViewController. From the Welcome screen, the user can view the product catalog, ProductsTableViewController and drill down and see more information about a product, ProductDetailViewController. Also from the Welcome screen, the user can navigate to viewing their orders, OrdersTableViewController.

Additionally, we’ll embed our app in a UINavigationController, which will help slide our view controllers in and out.

Storyboard of the final app.

Globals.swift

As we navigate around our app, there’s some information our views will need to share. That info is the location URL of our API, the username, password, and userRid of our customer, and finally our catalog of products.

Note that we will maintain our list of products in memory as a Dictionary<String,Product>. This will allow us to look up each product by its RID.

1. LoginViewController: A User Opens Our Store App and Wants to sign-In.

Starting with our login screen. We’ll have inputs of UITextFields to enter username and password. When the visitor signs in, we’ll make our first API call using Alamofire’s request method, where we can also define the response handler. We use the .validate() method to ensure we are receiving a valid 2XX response from the server, and not an error.

Alamofire.request(escapedUserString!).validate().responseJSON { … }

When we receive the response, we use Alamofire to determine if it was a .success or .failure.

Then we unpack the JSON response using SwiftyJSON, which allows us to use the json[“key”] accessor methods.

Make sure to import Alamofire and import SwiftyJSON at the top of the login class to use these functions.

In our Globals.swift, we set the baseURL to the location of our API. Therefore we can use baseURL()+ “<endpoint>” for our requests.

The connect call is to first make sure we can connect to our database and to verify the login credentials.

On successful login, we also need to look up the RID of our customer. This RID will be later used when we’re making a purchase and looking up our user’s orders.

We’ll store this information about our visitor’s username, password, and userRid in the Globals.swift variables for later use.

Finally, if we perform a successful login, we will then navigate to the MainViewController. We use the storyboard constructor and navigation pushViewController methods to do so.

Note that in your storyboard, you must also define the Storyboard ID for these view controllers.

MainViewController.

2. MainViewController: A User Enters the Store and Views Options

Next is the Welcome screen of our app, where we’ll present options to the user to view our catalog or view their orders.

View Products

// GET http://{{server}}:{{port}}/query/{{database}}/{{language}}/SELECT from PRODUCTS
let requestString = baseURL() + “/query/ComputerStore/sql/SELECT from PRODUCTS”
let escapedString = requestString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
Alamofire.request(escapedString!).validate().responseJSON { response in …}

Construct the API endpoint using baseURL() again. Here, we must be sure to use the convenience function requestString.addingPercentEncoding(…) since our request string has spaces in “SELECT from PRODUCTS.”

Again we will validate() our response and parse the JSON.

Now that we are receiving Product records from the database, we will want to implement our Product class on the client side. This is a simple data storage class with the same fields as the database. It is important to understand the convenience init(productJSON: JSON){…} that is written to accept the JSON response from the server and unpack it into a new object.

Keep in mind that a Product has relationships for Components and CompatibleWith. These are edges, and edges have their own RIDs. Therefore, the RIDs that the REST API returns to us are for the edges which point to those Products, not the RIDs of the Products themselves.

Additionally, we convert those Components and CompatibleWith fields from Swift JSON type to Swift Array<String> type using the following syntax: productJSON[“out_Components”].arrayValue.map({$0.stringValue})

Back in our MainViewController, we then store the product, by it’s RID, in our global product dictionary using products[rid] = productObject

Once all of the products have been unpacked and stored, we then instantiate and push our ProductsTableViewController to display those products.

View Orders

Alternatively, in this view, the user can select to view their orders.

To do this, we query and traverse the HasOrder edges which point to our User RID, which we retrieve using the expand(out(…)) modifier to receive the Order records.

//GET http://localhost:2480/query/ComputerStore/sql/SELECT expand(out(“HasOrder”)) from 5:0
let userRidTrim = userRid?.trimmingCharacters(in: [“#”])
let requestString = baseURL() + “/query/ComputerStore/sql/SELECT expand(out(\”HasOrder\”)) from “ + userRidTrim!
let escapedString = requestString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
Alamofire.request(escapedString!).validate().responseJSON { response in … }

We will display our list of products in a UITableViewController. Each row will display a product’s name and price. In the storyboard, set the prototype cell Identifier to ProductCell, which allows us to reference it in programmatically, and set Style to Subtitle, which enables a detail text label for us to use.

UITableViewController configuration.

When the customer selects a row from our list of products, we’ll look up that product by the row selected and pass it onto the ProductDetailViewController using its product input to display more information.

4. ProductDetailViewController: A User Drills Down to View the Components of a Product

The product detail view displays all of the product information using several user interface elements, including a UIImageView, UITextView, UILabel, and an embedded UITableView.

XCode’s Interface Builder has a handy Assistant Editor view and ability to drag and connect UI elements to code snippets. Make sure your UI elements are correctly referenced in their associated Swift files, and that the Buy button invokes a buy function.

XCode Assistant Editor.

In our viewDidLoad() method, we’ll set all of our UI elements to display our product’s information. Most of these are text labels.

We must also load the image for the productImageURL that we have. This is where we will use AlamofireImage’s handy asynchronous af_setImage(withURL: URL) method.

To display the components, we embed a UITableView inside of our UIViewController (which is not a UITableViewController), we therefore also need to adopt the UITableViewDelegate and UITableViewDatasource protocols on the top class definition line. That’s how we define what the table should display and what should happen when our visitor selects a row.

Remember that our Product object has a componentEdgeRids field, which holds the RIDs of the edge that points to our components, but does not have the RIDs of the components themselves. Therefore, we will need to make another request to the OrientDB API to traverse this edge.

We do that with the following request:

// GET http://{{server}}:{{port}}/query/{{database}}/{{language}}/SELECT expand(out(‘Components’)) from <<@rid>>
let requestString = "http://admin:admin@localhost:2480/query/ComputerStore/sql/select expand(out(‘Components’)) from " + productRidTrim!
let escapedString = requestString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
Alamofire.request(escapedString!).validate().responseJSON { response in … }

ProductDetailViewController.

5. ProductDetailViewController: A User Decides to Make a Purchase

Alternatively, in this view, a customer may decide to purchase a product by pressing the Buy button.

This button invokes our clickBuy() function and prompts the user to confirm their purchase with a UIAlertController. This alert view has two actions, where Cancel simply dismisses the popup, and Confirm invokes our createOrder() function.

The createOrder() function makes a request to our ComputerStore custom function, CreateOrder, and passes in the RIDs of the product and the customer. Our first tutorial explains the creation of this custom function.

let productRidTrim = product?.rid?.trimmingCharacters(in: [“#”])
let userRidTrim = userRid?.trimmingCharacters(in: [“#”])
// POST http://{{server}}:{{port}}/function/{{database}}/{{name}}/{{argument1}}/{{argument2}}
// POST http://localhost:2480/function/ComputerStore/CreateOrder/23:1/5:0
let requestString = "http://admin:admin@localhost:2480/function/ComputerStore/CreateOrder/" + productRidTrim! + “/” + userRidTrim!
let escapedString = requestString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
Alamofire.request(escapedString!, method: .post).validate().responseJSON { response in … }

6. OrdersTableViewController: A User Wants to See Their orders.

Back to the MainViewController, when a customer selects View Orders, we query the database for any HasOrder edges which point to our current user.

Here we need to also create our Order class in Order.swift, which is very similar to our Product class. This Order class also has a convenience init(orderJSON: JSON) method to unpack a JSON object into an Order object.

We append each order to an orders array and then push our OrdersTableViewController, passing in this list.

This table view simply displays a table view of our order RID and order totalPrice.

OrdersTableViewController.

And there you have it! We’ve built a (very simple) e-commerce mobile app using an OrientDB database and it’s out of the box HTTP REST API.

Hope you found this useful. Feel free to dig through the iOS code on GitHub and leave us your comments and any questions that arise.

Here are some resources for additional reading:

Analysts agree that a mix of emulators/simulators and real devices are necessary to optimize your mobile app testing - learn more in this white paper, brought to you in partnership with Sauce Labs.

Topics:
orientdb ,database ,graph database ,rest api ,ios ,http ,mobile ,mobile app development

Published at DZone with permission of Anthony Blatner. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}