We’ve just launched Take5 Feedback and its mobile app. This is the fourth mobile app that The Frontier Group has launched, that I’ve worked on.
Previously, we had been using a combination of PhoneGap and SpineJS. This helped us get into the iOS market while still using tools we were familiar with as web developers. After releasing a few apps using PhoneGap and SpineJS, we found that we were consistently spending time during app development fixing things like scrolling, tap events propagating to other views and transition animations. This coupled with the less-than-fantastic debugging tools made us feel that perhaps we needed to re-evaluate our technology choices.
This time we decided to kick it up a notch by moving to RubyMotion. (Bam!).
For those who haven’t heard about RubyMotion, it’s a library that lets you write native iOS apps in Ruby which is then compiled down into Objective-C. As most of us at The Frontier Group are Ruby developers, this felt like a technology well worth exploring. After working with it for a few months, I think it’s the way to go for us moving forward. Now, let’s talk a little about RubyMotion.
Off the bat, one of the big advantages of RubyMotion is that you’re writing native apps in Ruby and not in Objective-C. I’ve found that Objective-C is not an intuitive language and certainly nowhere near as readable as Ruby (especially when method chaining looks like array declaration shudders). One thing RubyMotion has ported over from Objective-C that I do like is the named parameter which makes method declaration/invocation much more readable. For example, let’s say I have a method that generates a receipt and takes a the date of the purchase and the amount in cents as parameters.
In regular Ruby it would be declared something like this:
def generate_receipt date, amount
# Do something...
end
Now this method could conceivably be called like this:
square = generate_receipt('3/3/2013', 100)
In RubyMotion, however, using named parameters the same declaration/invocation looks like this:
def generateReceiptForDate date, andAmount: amount
# Do something...
end
As you can see, it gives the parameters passed in more meaning during the method invocation. Now most Rubyists won’t call methods with “magic numbers/strings” and you can achieve the same thing in < Ruby 2.0 by accepting a hash but I think this is a nice little addition.
Next I’d like to discuss generating and organizing views. MVC in iOS is a little different from MVC in Ruby on Rails, in that views are a little more tightly coupled to the controller. View elements are ultimately defined and positioned in the controller. Those elements will rely on methods which should be defined in the controller as they deal with event handling and navigation. Let’s take a simple example. I want a screen to have a table and when I tap a row I want to navigate to another screen.
As you can see we’ve got a mix of view level logic (positioning the table on the screen and defining what a row will look like) and controller level logic (setting the data source and the navigational behavior). This makes views and controllers coupled a little tighter than you might be used to. This can lead to extremely fat controllers when you have many elements on the screen each with its own position, look, feel and event handlers. A pattern I found that has worked for me is to have a subclass of a UIView that is responsible for drawing all the elements on a given screen. Let look at an example.
Let’s start by creating our own UIView where we define our table and its look and feel.
class ExampleView < UIView
TABLE_FRAME = CGRectMake(0,0,300,400)
TABLE_ROW_HEIGHT = 30
attr_accessible :table
def initWithFrame frame
super
setupTable
self
end
private
def setupTable
@table = UITableView.alloc.initWithFrame(TABLE_FRAME)
@table.rowHeight = TABLE_ROW_HEIGHT
self.addSubview @table
end
end
class ExampleController < UIViewController
REUSE_IDENTIFIER = 'example'
def viewDidLoad
@data = [1,2,3,4]
self.view = ExampleView.alloc.initWithFrame(view.frame)
self.view.table.delegate = self
self.view.table.dataSource = self
end
def tableView(tableView, cellForRowAtIndexPath: indexPath)
cell = tableView.dequeueReusableCellWithIdentifier(@reuseIdentifier)
cell ||= UITableCell.alloc.initWithStyle(UITableViewCellStyleDefault,
reuseIdentifier: REUSE_IDENTIFIER)
cell.textLabel.text = @data[indexPath.row]
cell
end
def tableView(tableView, didSelectRowAtIndexPath:indexPath)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
self.navigationController.pushViewController(AnotherController.new, animated: true)
end
def tableView(tableView, numberOfRowsInSection: section)
@data.count
end
end
Ok so now the responsibility for drawing the table (and any other element) is localized to the ExampleView class and the data manipulation and navigation logic is in the controller which is looking better. We can neaten this up further by making the view responsible for assigning delegates.
Let’s start by creating a new parent view that stores an object which will be the delegate for all elements within the view. In this example the delegate is the ExampleController.
class UIViewWithDelegate < UIView
attr_accessor :controllerDelegate
def initWithFrame(frame, andDelegate: delegate)
self.initWithFrame(frame)
self.controllerDelegate = delegate
self
end
end
Now that we have this class our ExampleView class can inherit from it, allowing the ExampleView to set the delegates for any elements inside it.
class ExampleView < UIViewWithDelegate
TABLE_FRAME = CGRectMake(0,0,300,400)
TABLE_ROW_HEIGHT = 30
attr_accessible :table
def initWithFrame(frame, andDelegate: delegate)
super
setupTable
self
end
private
def setupTable
table = UITableView.alloc.initWithFrame(TABLE_FRAME)
table.delegate = self.controllerDelegate
table.dataSource = self.controllerDelegate
self.addSubview table
end
end
class ExampleController < UIViewController
REUSE_IDENTIFIER = 'example'
def viewDidLoad
@data = [1,2,3,4]
self.view = ExampleView.alloc.initWithFrame(view.frame)
end
def tableView(tableView, cellForRowAtIndexPath: indexPath)
cell = tableView.dequeueReusableCellWithIdentifier(@reuseIdentifier)
cell ||= UITableCell.alloc.initWithStyle(UITableViewCellStyleDefault,
reuseIdentifier: REUSE_IDENTIFIER)
cell.textLabel.text = @data[indexPath.row]
cell
end
def tableView(tableView, didSelectRowAtIndexPath:indexPath)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
self.navigationController.pushViewController(AnotherController.new, animated: true)
end
def tableView(tableView, numberOfRowsInSection: section)
@data.count
end
end
This has separated the view and controller logic out a little more and our controller is a little thinner. This becomes more useful as the number of elements on your screen increases. The one drawback I found was that my views were ending up with walls of constants defining positions, fonts, etc. Creating subclasses for individual elements that include the position/look/feel, would solve the problem, however you’ll end up with a lot of singleton classes.
Now a little on automated testing. Automated testing is generally a big part of any of the applications we develop. This time however, I found the experience to be so much more costly than testing in a Rails world. When I started developing the app I was aiming for the level of automated coverage we have in our Rails environments. As I attempted to achieve this, I kept hitting road blocks with either the testing framework not behaving as expected, or the mocking libraries placing a significant impact on the code being tested. After some discussion, we decided that due to the simplicity of this app we could achieve an acceptable level of quality and coverage by manual user testing. From this experience though we now know areas that can be improved and are currently developing our skills and tools to ensure that as our apps increase in complexity, we are able to ensure our code quality.
I could write so much more about RubyMotion and the different technical challenges I faced during the development process, but I really just wanted to give my overall impressions. I think it’s a good choice for any Rubyist wanting to venture in iOS development. In combination with the Apple developer docs, which are fantastic, it lets you learn the iOS framework while programming in a language that you’re comfortable with. It’s a well maintained library with the RubyMotion team making constant improvements. My only real criticisms are with the testing and debugging tools not feeling as flexible and as powerful as I’m used to in the Rails environment, but like I’ve said, these tools are being continually developed and improved, and have no doubt these tools will get better with time.
Frequently rails applications need to process data that will not be stored in a database. How does one handle this sort of data?
An example of this might be a user filling out a search form, doing some sort of query. This quickly gets complicated to handle once you start searching by dates (which have to be casted from strings) or have complicated rules about which parameters are required.
This sort of data doesn’t really fit into Ruby on Rails models (which are usually concerned with persisting data). Additionally this data is often subject to business logic and doesn’t really seem to belong in the controller layer either.
The Rails answer to such things is ActiveModel, which provides some tools to get you started on building models that aren’t based off ActiveRecord::Base. Unfortunately, however, there are a number of great features, such as typecasting, that you can’t easily get this way.
Enter active_attr, a fantastic gem by Chris Griego, that helps you bootstrap your new non-persisted models and get into the good stuff. Chris’s gem provides validation, mass-assignment, and security features among others.
My favourite feature is typecasting. In a regular active-record model Rails can infer the appropriate types of your attributes from the database – not a possibility in a non-persisted model. With active_attr you can define the types of your attributes with ease, and get some of that Ruby magic going.
Here’s an example of a PersonQuery:
class PersonQuery
include ActiveAttr::BasicModel
include ActiveAttr::TypecastedAttributes
include ActiveAttr::MassAssignment
include ActiveModel::Validations
attribute :full_name, type: String
attribute :born_after, type: Date
validates :full_name, presence: true, :length => { :minimum => 5 }
validates :born_after, presence: true
def execute
Person.where(full_name: full_name).where("date_of_birth > ?", born_after) if valid?
end
end
These days there’s a lot of money in mobile applications – and where there’s money and new technologies there’s web developers primed and ready to argue about how best to implement these new technologies.
As one of this dedicated crowd I’ve found myself recently working with a lot of Rails RESTful APIs that talk to my mobile applications. This has given me the opportunity to both create my own RESTful APIs and use RESTful APIs written by other developers.
As a result, I’ve gained a much better understanding of the HTTP Status Codes and how they can help you write both better APIs and client applications.
For clarity, I use the term ‘client’ to refer to the mobile application that is communicating with the Rails RESTful API backend.
When I say API I’m referring to a Rails RESTful API.
Before I begin, here are some good sites for reading up on the HTTP Status Codes:
Here’s a good article by Alex Rogriguez over at IBM from 2008 on REST APIs. If you aren’t clear on what a RESTful API actually is give Alex’s article a read.
The status code works hand-in-hand with the response body to help the client application process the request.
Status codes tell the client application what it needs to do with the response in general terms.
For example, if your API returns a 401 you know you need a logged in user. If the API returns a 403 you know the user you’re working with doesn’t have sufficient authorization. If the API returns a 418 you know that the API is telling you it’s a teapot and was probably written by knobs.
The response body will tell your client application in specifics what it needs to do with the response. If the client is trying to update a record and the API responds with a 400, the response body will inform the client why the request failed. On the other hand, if the API responds with a 200 the response body will provide the client with the updated entity.
That seems pretty straight forward, right? The difficulty lies in when the API returns a status code and a response body that don’t match up.
I worked with an API that returned a 200 status code but the response body had an errors array in it. That was an absolute trip – I had to parse the response body and look for the presence of content in an errors array first. Then I called an error handler from within the success callback of a jQuery ajax function. This is an example of a bad RESTful API. I hope by reading the remainder of this article you can avoid doing that.
Which status codes should I be using?
As long as you’re not too pedantic status codes are easy to work with when writing an API.
Here’s a rough guide to how I handle mine:
(For the purpose of all of the examples below, any response content I refer to will be as JSON.)
(2xx) Success Codes
200 OK
The 200 OK status code can be your go-to for any successful response. There are many success codes but for a very basic API I’ve found the 200 *can* be expressive enough. The distinction between 200 and the other success codes hasn’t proved valuable in my APIs so far.
However, some other Success Codes you might be interested in:
201 Created for when you’re creating a new resource.
202 Accepted for when you’ve successfully set the request to be performed in a background task. Useful if your client is requesting something on the API that is time-consuming and you don’t want the client to have to wait.
What should I return in the 200 response content?
The content of the response is dependent on the HTTP Method used in the request.
This JSON should allow the client to update all the records they have that match the records provided in the response. Possibly, it will also allow the client to determine which records have been deleted and can prune its local storage accordingly.
Now, consider an example where you are updating a resource with a request like:
PUT api.example.com/1/users/1
Your response JSON will look like:
{id: 1, name: 'Jordan'}
This allows the client to update its data for the record.
(4xx) Client Error Codes
Here I’ll cover the 3 client error codes I find myself using most in my APIs:
400 Bad Request
The 400 Bad Request status indicates that the request ‘could not be understood by the server due to malformed syntax’. See the IETF docs
There is also the 422 Unprocessable Entity status code that appears to be popular for roughly the same purpose. I’ve read from a couple of sources that since the 422 is part of the WebDAV extension that 400 is preferable over 422. I don’t have the knowledge to weigh in on this argument. Perhaps someone can enlighten us in the comments section.
Some examples scenarios I’ve used an API to return a 400 for:
The client is trying to create a resource with data that fails validation rules on the API
The client is requesting resources using invalid params (e.g.: the date is malformed)
The client request is missing fields the API requires as indicated in the thoroughly written docs! (e.g.: a search might require an end date is a start date is passed through)
What should I return in the 400 response content?
The response of a 400 will depend on why the request failed.
Likely, you’ll want to keep a consistent format across all API end-points. I nest my failure reasons in an errors attribute in the JSON.
As an example, let’s say the client request failed because the name provided was too long. The API will respond with:
{errors: {name: "must be fewer than 18 characters"}}
In fact, given this is being returned with a 400 status code, you can probably do away with the errors wrapper entirely and only return:
{name: "must be fewer than 18 characters"}
The only important thing is to be consistent across your API in how you represent these errors.
401 Unauthorized
The 401 Unauthorized status indicates that the request had missing/invalid authentication credentials. See the IETF docs.
To demonstrate the use of the 401 in an API, I’ll use one of my apps as an example.
In the client application we have a login screen for entering email/password to log in. On all other pages in the application we use token-based authentication (each request must have an token passed through that is checked by the API before performing any request). When the client successfully logs in the API passes a token back that can be persisted on the client device.
In this scenario, the API will return a 401 if:
The client app attempts to authenticate a user by passing invalid username or password
The client app makes a request to an action that requires authentication without providing the token (To be honest, I think this has only ever happened to me in development)
The client app makes a request to an action that requires authentication providing an invalid token (For example: the user tries to log in to the client app after their user has been disabled on the API)
What should I return in the 401 response content?
I’ve found that so far I’ll just return one of:
{errors: {invalid_credentials: 'Authentication credentials provided were invalid'}}
or
{errors: {no_token: 'No authentication token was provided in request'}}
or
{errors: {invalid_token: 'Token provided was invalid'}}
403 Forbidden
The 403 Forbidden status indicates that although the request was valid the action requested failed authorization constraints. See the IETF docs.
Pretty straight forward scenario: user x tries to update resource y. User x is not authorized to update resource y.
As a note, if you are making a client where you strictly control the interactions with the API I feel that your client ever getting an authorization error is at best a code smell but more likely it’s actually just a bug.
Consider an interface that has a button that the user can interact with which returns a message like ‘You are not authorized to perform this action’. Ideally, in a mobile interface the user should never see an authorization error message since it’s not something the user can do anything to fix.
What should I return in the 401 response content?
The API will return a string with a simple error message like:
{errors: {authorization: 'You are not authorized to perform this action'}}
What about the rest of the client error status codes?
So I’ve given you the top 3 error status codes I use in a bit more detail but that’s not an exhaustive guide to the error codes. Here’s a whirlwind summary of the remaining error codes that I’ve used in my APIs:
404 Not Found for when the URL is wrong or the requested resource does not exist.
410 Gone for when the resource has been permanently (and intentionally) deleted. This informs the client application that it should remove any references to the resource in question.
Summary
I hope I’ve provided some insight into the various status codes you can leverage to create an accurate, informative API. I also hope I’ve illustrated the strong relationship between the status code and the response body and the importance of providing a descriptive response body.
If you have any thoughts or disagree with me on this let me know in the comments and we can discuss!
I love the RSpec let syntax. I especially love using let blocks to declare everything on the planet. However, I was noticing a lot of duplication in my code so I knocked up the below pattern to deal with the issue:
The pattern I’m referring to above is declaring and using the vehicle_attributes object to set attributes on an object. The benefits of this pattern is that I’m able to set specific attributes on an object on a per-context basis without having to re-write my call to the factory. The issue that caused me to start using this pattern was having a declaration at the top of the file that was getting overloaded with ‘common’ attributes. My vehicle declaration started to look like:
Which worked well enough until I had 4 common attributes on vehicle and 3 other objects that were being created with multiple common attributes as well. My spec file was starting to get ugly.
Even worse, I was declaring vehicle multiple times within describe blocks for other methods.
So, by using the above pattern you can avoid a fair bit of duplication in your specs and keep everything neat and tidy.
Plus, it’ll reduce the amount of code you have to type which gives you more time to browse r/aww
If you’re looking for an engaging and interactive way to learn Ruby, I’d recommend Ruby Koans by EdgeCase. I think that the koans are especially interesting if you’re coming from another programming language like PHP or Java, because they rely on some basic programming knowledge, but don’t presume any Ruby-specific abilities.
The Koans walk you along the path to enlightenment in order to learn Ruby. The goal is to learn the Ruby language, syntax, structure, and some common functions and libraries.
By manipulating and building upon Ruby’s TestUnit framework, the EdgeCase developers have created a step-by-step process for teaching Ruby through the practice of “Red, Green, Refactor.” They’ve added some simple game mechanics too, by showing your systematic progression through the 270+ challenges (puzzles). Reaching enlightenment results in a pretty ASCII graphic, and a legitimate sense of achievement.
Before you start with the koans though you’ll need a working Ruby installation. I recommend you take a look at the excellent rvm project, which will allow you to install multiple rubies (1.8.7 and 1.9.2 for example, alongside each other) and multiple gemsets in your home directory. Former Frontiersmen and 2011 Ruby Hero Award winner Darcy Laycock was heavily involved in this project as part of the 2010 Ruby Summer of Code, so we really like rvm at TFG.
Lastly, if you’d like to have a play with the koans before diving in too deep, they’re available online through your web browser at Ruby Koans Online. This is a no-risk way of trying out Ruby (hint: team them up with why’s Try Ruby project) in your browser.