Designing APIs vs Consuming APIs
Most APIs are described as being RESTful but many really aren’t. Fortunately understanding about what RESTful really means is becoming more common. The one area that seems to still hold debate is HATEOAS. Should an API be described to its consumers with documentation or should they discover it through links, the relationships between the requested resource representations. HATEOAS is the final level of the Richardson Maturity Model and one that some APIs ignore completely. HATEOAS or something very similar is the future of APIs but we’re not ready to fully embrace it yet.
When consuming an API, Roy Fielding’s dissertation tells us that a truly RESTful API should be discovered but details on how that should actually work are thin on the ground. A discoverable API isn’t too hard to create but consuming it is a very different story and until the semantic gap between API and client is closed there should still be human consumable documentation to aid writing the clients. The semantic gap will exist until a client can understand the application level semantics of an API without having it hard coded in. The gap is slowly closing. Hypermedia formats such as HAL and Siren are becoming more common which help with the underlying protocol semantics. Lists of universal media and link types such as the ones maintained by IANA allow greater interoperability of application semantics. These still fall back to human understandable descriptions though.
An API should be designed in terms of the relationships between resources and how they can change, similar to a state machine. If an API is designed around its endpoints the quality of the API will suffer, it’ll be designed backwards. For this reason Swagger and other similar efforts to document APIs should be avoided. They’re solving the symptoms of a problem and not the problem itself. Tools such as Spring Rest Docs can help here, especially as documenting larger APIs can be difficult. Spring Rest Docs ties the documentation to the API, not the other way round, tests will fail if the docs don’t match the API. It also ties in the human readable docs that are still needed when writing a client.
Equally a client shouldn’t be written to consume a set of known endpoints either. Once it is coded to understand the specific media types, resources and relationships of an API it can be discovered. This also reducers the coupling between client and API, letting the API evolve without breaking the client. Like many areas of technology this is one that is changing. It important to understand where it is heading, while the future can’t be predicted, Roy Fielding’s dissertation describes a future most people are working towards. It’s equally important to understand what is actually possible today. An API should be designed for the future but also easy to consume today.