Over the last year or so I consulted for a Canadian startup called Spoke Technologies. We built the free SPOKEnPHOTO service which includes native iOS apps SPOKEnPHOTO for iPhone and SPOKEnPHOTO Album for iPad that allow you to ask friends and family to talk about your photos, and for you to then share those photos and the commentary with others in various ways.
I was originally asked to help out with the server development, with an initial prototype already developed in Grails. The product was functional but very much in its initial stages at this point. We started with a small team with few processes or tools.
Over the course of the coming year I formalised the REST API with the team (of which I was the only truly remote member), and we made several refinements to the product. We introduced better processes, moved code to Github, went through Pivotal tracker to JIRA, used TestFlight for ad-hoc iOS build distribution and used Basecamp to communicate. Not all of these tools were universally popular choices, but I think in the end everyone was happy enough.
A professional design agency was taken on to develop the UI and user interactions in the client and web. At the time these skills were simply not available in-house, and if you are making mobile applications you cannot overstate the value of high quality design. The non-mobile web UI remained important to the project because of the nature of the application. If you invite people to talk about photos, they invariably do not have your application yet and may not even have an iOS device on which to install it. I also used iOS 6's neat new app banner mechanism to show direct links into the app store if you view photos on an iOS device in Safari. You can install and open the app right at that photo... although I don't believe the latter part of the URL scheme implementation is complete in the public builds of the apps in the app store.
My work on the implementation of the API was interesting because developing APIs for mobile clients is quite challenging. The biggest issue of concern is that you cannot force customers to update their installed application. You may ship a fix for a critical bug, but they do not have to or may not be able to install it. This means that you have to strictly version your API and ensure that you continue to support older API clients for those older mobile app installs out there, and you have to make sure that your new API changes do not leak through to old API client response payloads. Yet you also want to reuse your code rather than cloning the logic for each API revision and tweaking it.
The implementation of REST style protocols themselves in Grails is simple. You don't need any plugins to do this, and you don't even need built-in REST support features. The versioning is the tricky part. The solution that I arrived at consisted of:
- Having a filter extract the requested API version from /api/1.1/ style URIs and putting this into the request attributes as e.g.
- Making controllers pass this API version information to service calls that implement the API request, so that they can tailor their activity and response accordingly
- Having a
UrlMappings.groovyfor the current API URL mappings, and moving older mappings over to a
LegacyUrlMappings.groovyfor hygiene purposes
- Having per-API-version functional tests for all the API requests. This means tests ensure that all versions that the server should support concurrently continue to be tested
This provides for changes over time in request and response formats supported by each API version, changes to binding from requests, changes to response payload formats, changes to URL mappings, and even changes to HTTP headers and status codes used. Build robust versioning infrastructure in from the start.
It isn't foolproof, and in some ways not even that elegant, but it gets the job done well. We had several client and API revisions and no problems that I am aware of with API incompatibility. I always maintained during development that having a full suite of functional tests for the API was absolutely critical to prevent the iOS client and Grails server developers chasing round in circles trying to isolate whether the client or server was at fault. This actually necessitated me making some improvements to the Functional Test plugin 2.0 RCs to support API testing better - something for which I have not found any better solution.
Good logging at the server end was also very helpful on this front. If a client seems to misbehave and you see some dodgy data in the staging server logs, you have just saved yourself a lot of debugging pain. So add lots of DEBUG logging that includes all headers and payloads where possible, and run your staging environment with DEBUG logging all the time.
As far as REST goes, I would prefer a high level API definition DSL as I mentioned recently on the Grails mailing list, but that is something somebody else will have to work on I expect.
On the user-facing side of the website, we had to be able to show photos and albums and allow playback of the audio associated with these. We also had to allow recording of audio directly in the browser. If you've never done that before, all I can say is don't. The state of current browsers is such that the only way to do this in 2013 is still to use a Flash app to record the audio and stream it up to a media server which converts from FLV format to something like MPEG-4 audio. Our app then gets the audio file saved from by the media server and post-processes it to hook it up to the relevant database data.
User signup is handled via the REST API although there is web UI for the password change screen and admin logins. For these we use Grails Platform UI and my Fresh Security plugin which together put a friendly skin over Spring Security for the basic signup, log in and log out requirements of most sites.
Using a custom UI Set and Theme for Platform UI and GSP template overrides for forms provided by Fresh Security, we have a nicely skinned UI with minimal fuss. Fresh Security's UI elements are rendered in a manner and using CSS/JS libraries defined by our application, without us having to explicitly code this or hack styling into the Fresh Security plugin. Platform UI demonstrating its flexibility.
This was a fun project and the Spoke Technologies team are continuing to add new features and services to the product. It was a great experience to work with iOS developers and have some input on the direction of the application and service.
They are now expanding their in-house development teams and I am looking for new clients to help out.