It’s an exciting time at Ticketmaster. The company is growing and innovating faster than ever. We’re rolling out new products, most recently our client-facing Ticketmaster ONE, as well as experimenting with new concepts at a very high cadence.
A big part of that agility is attributed to our API (what’s an API?).
To meet the high demand for growth and innovation, and given the sheer size of our company, API development at Ticketmaster is distributed across many teams in various international locations. That makes it all the more important, albeit difficult, for us to speak the same language as we develop this critical capability. We’re at a point where we need principles and guidelines for developing a world-class API that delights both internal and external developers.
Yes, we will be opening up our APIs to the larger developer community soon. I know, I’m stoked too! More on that in a later post 🙂
API Design Principles
So in order to get our decentralized engineering team to build APIs that look and feel like they came out of the same company, we need to establish certain API design principles. If you dig deep into APIs with strong and loyal developer following (i.e. Amazon, Stripe, Flickr, Edmunds, etc), you’ll notice that they follow what I like to call the PIE principle: Predictable, Intuitive and Efficient APIs.
They behave in a way that’s expected and do it in a consistent manner. No surprises. No Gotchas. Software is a repeatable process and a predictable API makes it easy to build software. Developers love that.
They have a simple and easy interface and deliver data that’s easy to understand. They are “as simple as possible, but not simpler,” to quote Einstein. This is critical for onboarding developers. If the API isn’t easy to use, they’ll move on to the competitor’s.
They ask for the required input and deliver the expected output as fast as possible. Nothing more, nothing less.
These are APIs that make sense. That’s why they delight and engage developers. Documentation, code samples and SDKs are important, especially to external developers, but the real battle here is ensuring the API itself is as easy as PIE.
2. URI Path
Agreeing on a URI path pattern is going to be one of the most critical decisions our team will have to make. This will heavily impact how predictable, intuitive and efficient our API is. For Ticketmaster, I think the following pattern makes sense:
localization: The market whose data we’re handling (i.e. us, eu, au, etc)
resource: The domain whose data we’re handling (i.e. artists, leagues, teams, venues, events, commerce, search, etc)
version: The version of the resource NOT the API.
identifiers: The required parameters needed to get a valid response from this API call
optional params: The optional parameters needed to filter or transform the response.
I believe this pattern could help us create endpoints that make sense and are PIE-compliant. Here’s some examples:
// sample endpoints /us/commerce/v1/cart/create /us/commerce/v1/ticket/22355050403 /us/artists/v1/taylor+swift /au/artists/v1/all /ae/events/v1/all /us/leagues/v1/nfl/all
What matters here is not the URI pattern itself, but rather sticking to one pattern across all endpoints, which helps make the API predictable and intuitive for developers.
3. HTTP Status Codes
The most important guideline for HTTP header usage in an API context is ensuring the API response status code is a) accurate, and b) matches the response body. This is key in making the API predictable to developers since status codes are the standard in communicating the status of the API response and whether or not a problem has occurred. The main status codes that need to be implemented are:
/ 200 OK / 201 CREATED / 204 NO CONTENT / 400 INVALID REQUEST / 401 UNAUTHORIZED / 404 NOT FOUND / 500 INTERNAL SERVER ERROR
We might also want to define some custom status codes around API quota limits, etc. Whatever we end up deciding, we’ll make sure it’s consistent across all our endpoints.
- The API version will be defined in the URI path using prefix ‘v’ with simple ordinal numbers e.g v1, v2.
- Dot notations will not be used i.e v1.1, v1.2.
- First deployment will be released as version v1 in the URI path.
- Versions will be defined at the resource level, not at the API level.
Versioning eliminates the guessing game, making a developer’s life much easier.
5. Payload Spec
Another key area affecting PIE compliance is using a payload that developers can easily understand and parse. Luckily, JSON API offers a standard specification for building APIs in JSON:
If you’ve ever argued with your team about the way your JSON responses should be formatted, JSON API is your anti-bikeshedding weapon.
By following shared conventions, you can increase productivity, take advantage of generalized tooling, and focus on what matters: your application.
Clients built around JSON API are able to take advantage of its features around efficiently caching responses, sometimes eliminating network requests entirely.
So what about XML? Are we going to support it? I personally think it’s time to say goodbye to XML. It’s verbose and hard to read, which makes it a major buzz kill for any developer. Also, XML is losing market share to JSON. It’s time. Goodbye, XML.
I’d like to call out a few things in the JSON API spec that we should pay close attention to:
5.1 Links and Pagination
A hypermedia API is discoverable and easy to program against, which in turn gets it closer to being PIE-compliant. The links spec in JSON API helps with that. For data collections, providing a standard mechanism to paginate through the result set is very important, and that’s also done via links.
A server MAY choose to limit the number of resources returned in a response to a subset (“page”) of the whole set available.
A server MAY provide links to traverse a paginated data set (“pagination links”).
Pagination links MUST appear in the links object that corresponds to a collection. To paginate the primary data, supply pagination links in the top-level
linksobject. To paginate an included collection returned in a compound document, supply pagination links in the corresponding links object.
The following keys MUST be used for pagination links:
first: the first page of data
last: the last page of data
prev: the previous page of data
next: the next page of data
Keys MUST either be omitted or have a
nullvalue to indicate that a particular link is unavailable.
Concepts of order, as expressed in the naming of pagination links, MUST remain consistent with JSON API’s sorting rules.
pagequery parameter is reserved for pagination. Servers and clients SHOULD use this key for pagination operations.
The spec on sorting is as follows: use sort query parameters with fields separated by commas. All sorts are by default ascending unless prefixed by “-“, in which case it’s descending.
// Examples of sort /us/events/v1/all?sort=artist,-date /us/artists/v1/323232/reviews?sort=-rating,date
Using filters to control the result set of the API response is a great way for us to deliver an efficient API to our developers. We’ll need to discuss our filtering strategy as a team before deciding on how to do it.
5.4 Error Handling
Eventually, things will go wrong. A timeout, a server error, data issues, you name it. Part of being a predictable API is communicating errors back to the developer with some actionable next steps. The error object spec in JSON API helps with that:
Error objects provide additional information about problems encountered while performing an operation. Error objects MUST be returned as an array keyed by
errorsin the top level of a JSON API document.
An error object MAY have the following members:
id: a unique identifier for this particular occurrence of the problem.
links: a links object containing the following members:
about: a link that leads to further details about this particular occurrence of the problem.
status: the HTTP status code applicable to this problem, expressed as a string value.
code: an application-specific error code, expressed as a string value.
title: a short, human-readable summary of the problem that SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization.
detail: a human-readable explanation specific to this occurrence of the problem.
source: an object containing references to the source of the error, optionally including any of the following members:
pointer: a JSON Pointer [RFC6901] to the associated entity in the request document [e.g.
"/data"for a primary data object, or
"/data/attributes/title"for a specific attribute].
parameter: a string indicating which query parameter caused the error.
meta: a meta object containing non-standard meta-information about the error.
In our business, we’d always want to know exactly who is making API calls and getting our data. Therefore, solid and secure authentication is required to give anyone access to that data. The authorization standard in the market place today is OAuth 2.0. The trick here is making it dead simple for developers to get their access token so they can make API calls as quickly as possible.
I believe those six API design guidelines will help us develop Predictable, Intuitive and Efficient API capabilities for us and our developer community. I told you this was an exciting time at Ticketmaster 🙂
We want you to get involved to help guide this process. Do you think we’re missing something? What are some of the APIs you love? Why do you love them? What are some of the APIs you’d expect us to deliver?