When you start thinking about the backend API for your mobile app, it can sometimes be tempting to just dive right in and start building something. While this can be effective to get your app out the door, having a solid plan for your API can save you time and aggravation later.
In the past, I’ve written about how to futureproof the client side of your API calls, but today, I’m going to focus more on the actual backend itself, with a few questions that you should be asking yourself before you ever open your text editor.
1. How will you handle authentication?
This is one that a lot of people end up tacking on later, but it’s important to think of upfront. What I recommend is first thinking through the different types of API calls you’ll be making. Will any of these need per-user accounts? Will you require users to actually sign up for the app, or can anyone just start using it? Are there certain calls that don’t require any authentication?
If you decide you’ll need some form of authentication, take the time to sketch out how it will work, and definitely look to existing patterns for guidance: authentication is not somewhere you want to be reinventing the wheel. In most cases for user-based authentication, I recommend some form of token authentication, where the device sends up login details and receives a token in return and then uses that token to sign each subsequent request. If you don’t need user accounts, I’d recommend at least using some form of API key/secret authentication, so that you can always shut down API access if needed.
2. What format will your responses be in? What about your requests?
The default answer to this is usually JSON, but I’d recommend taking at least a little time to think it through. Depending on your app’s needs, there might be more efficient ways to send data around. These days, JSON parsers are pretty quick, but if you’re anticipating sending back large responses that might take a lot of time to parse, it’s worth thinking about alternate ways to send it down. Take a look at the libraries you’re using to parse requests in your app—what sorts of response formats do they support best?
Picking your request format is another question that seems obvious, but is worth some consideration. Will you be shoving all of your request variables into the query string, sending them up as form data, or as a JSON blob? In general, I use query string variables for GET request, and JSON data for everything else. That way, I’m staying consistent with my response format, and it’s more flexible than just using form data. If you’re going to be handling file uploads, make sure you take that into account as well.
3. What are the core “objects” in your data model?
Ok, here’s where we start getting to some API design questions. Take a piece of paper and write down all the potential “objects” of your backend. For example, if you were building a car reservation app, this might be things like “user”, “car”, “reservation”, “invoice”, “contract”, etc. Think through them all, and then figure out how you want them represented in your API. You’ll want to be thinking about how the response for each will look, because it should be consistent across your entire API.
Now that you have a clear idea of what your objects will look like in your API, you can stick to it as you build out different endpoints. While each URL might return different slices of the data, you can make sure that the data in the response is always formatted and returned consistently, so that your app’s API wrapper can be as simple as possible. You don’t want to be writing a separate parsing method for every single API endpoint: keep your responses following the same format, and it will make your life a lot easier when you go to build your API wrapper.
4. How public will your API be?
Are you planning to open your API up to other consumers? Or is it only your app that will be using it? The answer to this question can have a big impact on how you design the API itself. If you don’t have to worry about anyone else using the backend, you can optimize it for exactly the internal use cases you need. For instance, you can have specific endpoints for specific screens, sending down exactly the data each screen needs. If your API is going to end up as public, you’ll likely want to be a lot more strict on how you return information, since you’ll be more stuck with it once it’s out in the wild, and it’s likely others will need to use it differently than you are.
That being said, unless you have good reasons to, I would mostly recommend against having the same internal API be exposed publicly, at least when you start. As you’re building your app and API, you’re going to make a lot of changes, and that’s a lot easier when you’re not also trying to maintain compatibility with 3rd party clients. If you keep your publicly available APIs separate, they can each be optimized to their purpose, and they can each evolve separately, as needed.
5. How will you handle errors?
This is one a lot of people will forget, but it’s really important. Eventually your backend will need to report an error, and if you haven’t thought through how it will be returned ahead of time, you’re going to end up with a mess. Take some time to map out exactly what an error response will look like, so that you can stay consistent.
You’ll also want to think of some common errors that you might need to return, such as “Not Found” or “Not Authorized”. Try to use the same error codes across endpoints when returning the same error type, so you can keep your client parsing code as simple as possible. I’d also recommend including some sort of user readable version of the error, in case the app needs to display the error message to your end user.
Here’s an example of what your error response might look like:
{
"error": {
"code": 1001,
"message": "User Not Found",
"description": "The user you were searching for couldn't be found."
}
}
6. How will you handle pagination?
Just like with error codes, you should think through pagination. You’re almost certainly going to have endpoints that return a list of objects, and you’ll need to paginate. Think now about how you want to handle it, so that you can be consistent across all of your lists. Keep in mind, you’ll want to consider both the response as well as the request parameters the app sends up.
For example, you might have an endpoint that takes pagination options like this:
http://api.yourapp.com/v1/restaurants.json?page=5&per_page=5
This will return page 5 of results, with 5 restaurants per page:
{
"restaurants": [
{ "id": 1, "name": "Loco Pez" },
{ "id": 2, "name": "Wm. Mulherin's Sons" },
{ "id": 3, "name": "Han Dynasty" },
{ "id": 4, "name": "Butcher & Singer" },
{ "id": 5, "name": "DiNic's Roast Pork" }
],
"meta": {
"page": 5,
"per_page": 5,
"total": 78
}
}
Once you have a solid schema for pagination, you can then use it across every endpoint where you have a list.