Swagger, the REST Kryptonite
Swagger, a tool to help design, build, document, and consume RESTful APIs is ironically kryptonite for building actual RESTful APIs. The battle over the term "REST" is lost, where "RESTful" simply means "an API over HTTP" but these days is 99% of the time referring to "RPC over HTTP".
In a post covering the problems with Swagger, the author outlines some familiar issues I've seen with it (and its progenitors such as apiary.io):
- Using YAML as the new XSD
- Does not support Hypermedia (!!!!)
- URI-centric
- YAML-generation from code
Some of these are well-known issues, but the biggest one for me is the lack of hypermedia support. Those that know REST understand that REST includes a hypertext constraint. No hypermedia - you're not REST.
And that's OK for plenty of situations. I've blogged and given talks in the past about when REST is appropriate. I've shipped actual REST APIs as well as plenty of plain Web APIs. Each has its place, and I still stick to each name simply because it's valuable to distinguish between APIs with hypermedia and APIs without.
When not to use REST
In my client applications, I rarely actually need REST. If my server has only one client, and that client is developed/deployed lockstep with the server, there's no value to the decoupling that REST brings. Instead, I embrace the client/server coupling and use HTTP as merely the transport for client/server RPC. And that's perfectly for a wide variety of scenarios:
- Single Page Applications (SPAs)
- JS-heavy applications (but not full-blown SPAs)
- Hybrid mobile applications
- Native mobile applications where you force updates based on server
When you have a client and server that you're able to upgrade at the same time, hypermedia can hold you back. When I build clients alongside the server - and with ASP.NET Core, these both live in the exact same project - you can take advantage of this coupling to embrace this knowledge of the server. I even go so far as compiling my templates/views for Angular/Ember on the server side through Razor to get super-intelligent components that know exactly the shape of my DTOs.
In those cases, you're perfectly fine using RPC-over-HTTP, and Swagger.
When to use REST
When you have a client and server that deploy independently of each other, the coupling risk of RPC greatly increases. And in those cases, I start to look at REST as a means of decoupling my client and my server. The hypermedia constraint of REST goes a long way of helping to decouple, to the point where my clients can react to the existence of links, new form elements, labels, translations and more.
REST clients are more difficult to build, but it's a coupling tradeoff. But if I have server/client deployed independent, perhaps in situations of:
- I don't control server API deployment
- I don't control client consumer deployment
- Mobile applications where I can't control upgrades
- Microservice communication
Since Swagger doesn't support REST, and in fact encourages RPC-over-HTTP APIs, I wouldn't touch it for cases where I my client and server's deployments aren't lockstep.
REST and microservices
This decoupling is especially important for (micro)services, where often you'll see HTTP APIs exposed as a means of exposing service capabilities. Whether or not it's a good idea to expose temporal coupling this way is another question altogether.
If you expose RPC HTTP APIs, you're encouraging a new level of coupling with your microservice, leading down the same monolith path as before but now with 100-10K times more latency.
So if you decide to expose an HTTP API from your microservice for other services to consume, highly consider REST as then at least you'll only have temporal coupling to worry about and not the other forms of coupling that come along with RPC.
Documenting REST APIs
One of the big issues I have with Swagger documentation as it's essentially no different than API documentation for libraries. Java/Ruby/.NET documentation of a list of classes and a list of methods and a list of parameters. When I've had to consume an API that only had Swagger documentation, I was lost. Where do I start? How do I achieve a workflow of activities when I'm only given API endpoints?
My only savior was that I knew the web app also consumed the API, so I could reverse engineer the correct sequence of API calls necessary by following the workflow the app.
The ironic part was that the web application included links and forms - providing me a guided user experience and workflow for accomplishing a task. I looked at an item, saw links to related actions, followed them, clicked buttons, submitted forms and so on. The Swagger-based "REST" API was missing all of that, and the docs didn't help.
Instead, I would have preferred a markdown document describing the overall workflows, and the responses just include links and forms that I could follow myself. I didn't need a list of API calls, I needed a user experience applied to API.
Swagger, the tool for building RPC-over-HTTP APIs
Swagger has a rich ecosystem and support for a variety of platforms. If I were building a new SPA, I'd take a look at Swagger, especially for its ability to spit out TypeScript models, clients and the like.
However, if I'm building a protocol that demands decoupling with REST, Swagger would lock me in to a highly coupled RPC-over-HTTP API that would cripple my ability to deliver down the road.