Here at Detroit Labs, we primarily develop apps for mobile devices using Java, Objective-C, and, more recently, Swift. However, we do have a handful of Haskell enthusiasts among our developers, and we thoroughly enjoy using Haskell on the side for our hobby projects.
Recently, the Haskell fans here at Labs have been particularly excited by the Servant framework for building RESTful services in Haskell. While there are more than a few Haskell libraries out there for developing web-based technologies – some of them quite extensive in scope – Servant stands out for a few key reasons:
- It’s primarily focused on the development of RESTful APIs.
- It’s concise, elegant, and lightweight. There is very little boilerplate.
- It allows you to declaratively define your API endpoints in terms of the Haskell data types they accept and return. Your web services will fully leverage the type safety that Haskell is famous for.
- With the help of a little extra code, Servant will generate API documentation for you (which you can then serve to clients). Servant also goes out of its way to make it exceptionally easy to write code that interacts with your endpoints, from the standpoint of a client. This is a big win because, at the very least, it makes it trivial to test your APIs as you develop them. Servant can even generate JavaScript code!
- Although lack of sufficient library documentation is, sadly, a frequent complaint of Haskell programmers, the developers of Servant have prepared an excellent tutorial. After devoting a few hours to the tutorial, an intermediate Haskell programmer ought to find they know more than enough to get started.
So, we wanted to try using Servant somehow. But what to do with it? After much deliberation, we decided to utilize Servant to mock an automotive backend similar to those we regularly work with, and to present our findings in a series of blog posts.
You may very well be wondering what it means to mock a backend, and why one would do such a thing. So, before we delve further into the technical details of Servant, I’d like to explain our rationale for using it in this manner.
At Detroit Labs, a good number of our clients are large automotive companies for which we have developed mobile apps. These apps are the sort that enable you to use your smartphone to interact with your vehicle (locking/unlocking doors, starting/stopping climate, locating your vehicle, etc.).
As you might imagine, there does not exist a direct link between your smartphone and your car… Instead, when you tell the app to start your vehicle, there are a number of servers that must successfully communicate with each other before the vehicle is finally notified. At the very least, there will be a “web API layer.” This is the layer with which our app directly communicates, via RESTful protocols (it is also the layer we are primarily concerned with in this blog series). To start the vehicle, for example, we know that our app needs to send a JSON-formatted message to a certain URL. We know this because the client provides us with the specifications.
Typically, the development and maintenance of these backend layers are the responsibility of the auto company itself, and/or third parties. We often have little or no visibility into what happens beyond the web API layer, but we do know that it’s not trivial. Quite likely, there are database layers and other technologies designed to interface more closely with the vehicle. Further complicating matters, there may be customer web portals and other user-facing applications that play a role in the bigger picture.
Changes are often made to the various backend actors in parallel with our development of the mobile app. Since a variety of teams are involved in a variety of ways, things can change very quickly. Unforeseen bugs may originate on the web API layer. Or, a bug somewhere else on the backend can have a nasty effect that trickles down to the web API, creating problems for our app.
In the worst case scenario, we may suddenly discover that we can no longer log into our app at all, due to some change or defect that is very much out of our hands. This is a big deal; if we can’t log in, then without a means of testing our app independent of the backend, development nearly grinds to a halt. Our focus changes from writing code to assisting the client in troubleshooting the issue. But due to our limited visibility, there is often little we can do beyond asserting that the problem did not originate in our app.
There are other compelling use cases for mock backends as well. On one occasion, we found ourselves in a situation where we were building an app for a client who had not yet completed their backend, and our app development outpaced that of the backend. How could we develop those app-side features that relied on as-of-yet nonexistent services? Mock the backend! The client was able to provide us with all the API documentation we needed, so we built our own backend to those specs, for the services in question. When the client finished the backend, we just “flipped the switch” to point the app at the real server.
So, here we have the concept of mocking a backend. The idea is to develop your own server that mimics the real web API layer, as accurately and (ideally) as thoroughly as possible. When our app sends the signal to start the engine, for example, the mock server will reply with a canned response (“OK, car started!”). When the real server goes down, we just point our app to the mock server, and development can continue unhindered. Creating and maintaining the mock server incurs a significant effort, but if the client’s backend continues to create headaches time and time again (as is often the case), then it’s worth it in the end.
There already exist tools such as Apiary, which can greatly aid in the process of getting a mock server up and running. So why would we do it from scratch, using Servant?
Well, as previously mentioned, when we took a look at Servant, we were excited by its features and keen to try it out. Servant seemed to be a very developer-friendly library. Going through the tutorial, it was refreshingly simple and straightforward. How practical (or complex) would it actually be to roll out the sort of automotive API we were already familiar with? This was an intriguing question.
As we hoped and expected, Servant turned out to be a joy to use. It delivers on its promises. Whether or not coding a mock backend from scratch using Servant is actually a viable alternative to using an existing tool such as Apiary… well, unsurprisingly, that’s debatable. In any case, an intermediate Haskell developer who is already familiar with Servant can certainly roll out a working RESTful API very quickly, and with little hassle. And that’s exciting!
In the following posts, we’ll show you exactly how we used Servant to develop our auto API, step by step. Read on for the all the details!