Reference:
- Effective Java (good for learning the mindset of developing backward-compatible APIs in any language)
- Enterprise Integration Patterns (I work on an enterprise APIs team)
- Designing Data-Intensive Applications
- Camel in Action
Good for lending out: - The Phoenix Project
- Making Work Visible
- Effective DevOps
- The Pragmatic Programmer
- REST in Practice1. https://www.amazon.com/REST-Practice-Hypermedia-Systems-Arch...
2. https://www.amazon.com/Building-Hypermedia-APIs-HTML5-Node/d...
1. HTTP methods are improperly used. The documentation states "All API calls should be sent as a GET HTTP request". GET is used to retrieve resources, and should be cacheable. It should NEVER change the state of a resource. Yet we see in that it's used to delete, create, and modify resources! Examples:
GET https://subdomain.sharefile.com/rest/folder.aspx?op=create...
GET https://subdomain.sharefile.com/rest/file.aspx?op=delete
These should be as follows:
POST https://subdomain.sharefile.com/rest/folder.aspx
DELETE https://subdomain.sharefile.com/rest/file.aspx
HTTP verbs have specific semantics that allow for intelligent, scalable architecture.
2. Individual resources are not identified by an unchangeable URI. Let's say I want a folder:
GET https://subdomain.sharefile.com/rest/folder.aspx?op=get&...
Nope. This is more RESTful:
GET https://subdomain.sharefile.com/rest/folder/123
Two things to note: 1) no 'aspx' bullshit, that's implementation and shouldn't be visible to the user, and 2) the ID is in the URI itself as opposed to the params. URIs should seldom, if ever, change. Parameter names may change, URIs shouldn't.
3. Violation of content type retrieval. Let's say I want a folder as XML:
GET https://subdomain.sharefile.com/rest/folder.aspx?op=get&...
Wrong. This is the request I should be sending as a curl:
curl https://subdomain.sharefile.com/rest/folder/123 -H 'Accept: text/xml'
Note that I'm using the Accept header. This allows for flexibility in accessing my resource. With any luck, the server will give me an XML file, and its content type should be "text/vnd.sharefile+xml" (vendor specific content types are best).
4. No link relations in the body. I'm mostly assuming this because I haven't seen sample response bodies, but almost no one does this even though is a crucial aspect of a RESTful service. RESTful services describe the relationship between resources. Suppose I have an ordered collection of files. When retrieving a file, it should describe its relationship in this ordered collection. This is done either via the LINK header, or some sort of scheme in your response body (e.g. JSON Schema describes 'link' attributes).
A pretty good RESTful API is Github's (see http://developer.github.com/). If you'd like to learn more, I highly recommend "REST in Practice" by Webber, et al (http://www.amazon.ca/REST-Practice-Hypermedia-Systems-Archit...).
The best follow-up question to ask someone is: "What level on the Richardson Maturity Model is your RESTful API?" If they can't answer that, they're probably using the term RESTful to describe something else.
Richardson Maturity Model:
Level Zero Service - URI API. Usually just POST. SOAP, XML-RPC, POX.
Level One Service - URI Tunneling via URI Templates. GET/POST.
Level Two Service - CRUD (POST, GET, PUT, DELETE). Amazon S3.
Level Three Service - "Hypermedia as the Engine of Application State" (HATEOAS).
The higher up the level, the more "RESTful" your API (you can argue about the order of level's 0 and 1), but the more complex it will be. Not everything fits perfectly in those levels either; you're free to borrow concepts and mash-up your own custom API.HATEOAS is the most complicated. Imagine you're browsing the internet. You go to a webpage, and it loads with lots of text, links, images, and videos. You can interact with it, click on links, watch videos, submit a form, and go elsewhere. You have no idea what appeared on the webpage until after you visited it, and the next time you visit it might change entirely. The link might become broken and you get 404'ed, or you need a username/password otherwise you get 401'ed. HATEOAS is similar to that, but instead of a "person" browsing a "website", it's "client software" browsing "XML/URIs/Resources" received from a server API.
REST is not easy to understand or explain, as it entails learning about many different concepts, ideas, and custom-building something based on them. This is probably why there's no single-sentence which easily describes REST. Saying that something is RESTful is like saying something is Drivable. You can drive a car, truck, motorcycle, bicycle, or boat, but they're all very different from one another. There are similar concepts between them, like accelerating, steering, breaking, but how they do each of those things is very different.
A good book I recommend is "REST in Practice" by Jim Webber, Savas Parastatidis, and Ian Robinson (http://www.amazon.com/REST-Practice-Hypermedia-Systems-Archi... or http://shop.oreilly.com/product/9780596805838.do). That helped me grasp what REST means.
Some of those APIs might be REST APIs in the strict hypermedia/ HATEOAS sense as popularized twenty years ago by some proponents of this. However, looking back that mostly did not get very popular. I actually met with Jim Webber a couple of times. He co-authored "REST in Practice", which is sort of the HATEOAS bible together with the og. HTTP spec by mr. REST Roy Fielding. Lovely guy but I think he moved on from talking a lot about that topic. He's been at neo4j for more than a decade now. They don't do a lot of HATEOAS over there. I remember having pointless debates about the virtues of using the HTTP Patch method with people. Thankfully that's not a thing anymore. Even Jim Webber was on the fence about that one.
Most people these days are less strict on this stuff and might create generic HTTP REST APIs that may or may not do silly things as making every request an HTTP POST like SOAP, Graphql, and indeed Grpc tend to do. Which is very un HATEOAS like but perfectly reasonable if you are doing some kind of RPC.
Most APIs trying to do some of notion of REST can and probably should be documented. For example using OpenAPI.
Most modern web frameworks support OpenAPI directly or indirectly and are nominally intended to support creating such REST APIs. There's very little reason not to support that if you use those. Things like Spring Boot, FastAPI, etc. all make this pretty easy. Your mileage may vary with other frameworks.
Grpc is a binary RPC protocol that gets used a lot for IMHO mostly invalid reasons and assumptions. Some of those assumptions relate to assuming applications spend a lot of time waiting for network responses and parsing to happen and that making responses smaller and easier to parse makes a significant impact. That's only true for a very narrow set of use cases.
In reality, textual responses compress pretty well and things like JSON parsers are pretty fast. Those two together mean that the amount of bytes transferred over the network does not really change significantly when you use Grpc and the time waiting for parsing relative to waiting for the network IO is typically orders of magnitudes less. Which leaves plenty of CPU time for parsing and decompressing stuff. This was a non issue 20 years ago. And it still is. I routinely added compression headers to web servers twenty years ago because there were no downsides to doing that at the time (minimal CPU overhead, meaningful network bandwidth savings). Parsers were pretty decent 20 years ago. Etc.
Using RPC style APIs (not just grpc) has two big issues:
- RPC protocols tend to be biased to specific implementations and languages and rely on code generation tools. This can make them hard to use and limited at the same time.
- They tend to leak internal implementation details because the APIs they expose are effectively internal APIs.
The two combined makes for lousy APIs. If you want an API that is still relevant in a decade or so, you might want to sit down and think a little. A decade is not a lot of time. There are lots of REST APIs that have been around for that long. Most RPC APIs from that long ago are a bit stale at this point. Even some of the RPC frameworks themselves have gone a bit stale. Good luck interfacing with DCOM or Corba services these days. Or SOAP. I'm sure there's a poor soul out there wasting time on supporting that shit in e.g. Rust or some other newish language. But don't get your hopes up.
Once you're doing REST instead of just "somewhat sane JSON responses" then the response has self-descriptive elements, including links to related resources. And importantly, URLs for older resources become static very, very quickly. Not unlike the internals of subversion or git.
The trick there is to realize that O(1) = O(2). If you're trying to show 25 items per page, you do not need a query that returns the most recent 25 items. That creates a situation where every single interaction is distinct from every other interaction.
Asking for 25 results and everything newer than that is barely more complicated than pagination already is.