3 ms·
While this is a nice overview (I wouldn't call it detailed), I feel it misses the points of REST, gRPC, and GraphQL. I think it's a more useful engineering deci
by danpalmer 4y ago
While this is a nice overview (I wouldn't call it detailed), I feel it misses the points of REST, gRPC, and GraphQL. I think it's a more useful engineering decision to first filter based on how you want an API to be used, and then to filter based on the implementation details such as these.
The whole point of REST is that it's discoverable. Now web standards didn't quite manage to standardise HATEOAS, so sadly full machine discovery is unlikely via an API, but you can build quite adaptable clients that can respond to changing APIs well, going as far as optimising client usage by changing API responses without redeploying clients. That may or may not be something you want in an API, but it's worth considering, because it's not going to happen with gRPC.
GraphQL, like REST, is about the objects and relationships, and lends itself well to building highly capable client-side caching layers when you introduce the Relay patterns to it – particularly globally unique IDs. Given GraphQL's well defined schema it's relatively easy to build generic caching mechanisms. Again, this may or may not be something you want in an API.
gRPC doesn't really allow for any of this, if you want it you've got to invent it all yourself. But that might be ok! Server to server calls rarely need a big cache to work around poor networking. gRPC does however offer considerably more control over streaming behaviour, more standardised error handling than GraphQL, and more.
There are quite a few factual errors in this post, like REST not being schema based (that's up to the implementer), no streaming in REST (not necessarily true).
When deciding on an API technology the first questions must be "who is the consumer", and "what are their constraints". These will often lead to just one or two of the options here, then you can drill down into the details like tooling, API design, and so on.
- jrsj 4y agoTypesafety is another big part of this imo. GraphQL and gRPC give you this out of the box, but with REST you have to cobble together some sort of solution for providing a schema & client libraries.
- BerislavLopac 4y agoThat is true, but it has been very well solved and standardised by OpenAPI and JSON Schema.
- g_delgado14 4y agoThis isn't 100% true - unless you're using a json-schema --> types package then there's a risk of your documentation not aligning with your types.
- BerislavLopac 4y agoA common mistake I have noticed is that people identify API models with their business logic models. They may look similar, but they are very rarely identical, just as is the case with business logic models vs ORM models. Unless your models are very simple, the best approach is to use three separate layers of model definitions: * API models for serde and conversion of external requests * business logic models that carry the actual internal functionality * (optionally) ORM models to convert the data for persistence to a RDBMS
- jeffdn 4y agoAn even worse mistake is treating all three of those model layers as one and the same, which tools like Django REST Framework make it so easy to do. It all seems well and good for a while, as developers build up a big codebase with ease, but then are confronted with an almost insurmountable amount of work when the need to refactor arises. The thing I’ve noticed when stepping into a codebase where this problem has been allowed to occur is the lack of layers of abstraction. Having those different models built up from the start allows for an application to shift along with the needs of the product. Having a single layer, with the endpoints talking literally directly to the ORM models, almost inevitably leads to calcification, spaghettification, and disastrous performance.
- jrsj 4y agoIt really depends on the language and framework you're using how convenient OpenAPI actually is to implement. In many cases there's a lot of additional manual effort involved if you can't auto generate a schema, or at least generate one that is good enough to then generate client libs from.
- 4y ago
- danpalmer 4y agoTrue, but again this is a technical detail that should be secondary to who the client is and what they need. Is the client always going to use a library to interact, is connecting without any code/schema published by the API provider a core requirement? Are clients going to be in languages with good protobuf/GraphQL support? Some don't have this. Is the code that talks to the API also owned by the API provider? Public vs private. Support lifecycles. These factors all play into whether the type safety could even be utilised by clients. And it's not like REST doesn't have this – OpenAPI and Swagger can get a lot of the benefit with fairly minimal work. Both are very common.
- jrsj 4y agoI do agree that client requirements come first of course, but after that DX is at the top of my list. They do differ fundamentally in that type safety is an afterthought with REST but is built in with some of the alternatives. That can have it's benefits too of course, it's easier to integrate with and more broadly supported in part because it doesn't concern itself with that. OpenAPI can help but keeping your schema in sync with reality can be a pain depending on what libraries you have available. In the best case it really is minimal work, but if you don't have good tooling for whatever web framework you're using it can be a bit of a pain. In my experience it often requires more manual effort to maintain & more risk of mistakes causing the schema to be inaccurate.
- rswail 4y agoIs the image/jpeg media type "typesafe"? How is using, for example, JSON Schema to define your types any better or worse than a "proto" file that requires a compiler, a parser, and a client and server library?
- jrsj 4y agoThe difference is really that with something like protobuf type safety is built in & with JSON it's an afterthought. With JSON Schema or OpenAPI it's on you to keep things in sync with your API & there's often a significant amount of work that comes along with that too. There's many tradeoffs of course, it's not like dealing with proto files is painless either.
- rswail 4y agoWhat you're actually saying is that when you use the standard language bindings for a protobuf parser, the type safety is as built in as your language. JSON has a limited set of types. There is object, array, string, number, boolean, and null. That's it. JSON Schema adds to that by providing definitions of types that build on those basic JSON types.
- jeffbee 4y agogRPC does not give you any form of type safety. Even if you assume protobuf entities over gRPC, protobuf also does not give you any form of type safety.
- cle 4y ago> There are quite a few factual errors in this post, like [...] no streaming in REST (not necessarily true). Where did it say that? I got the opposite impression: > Handling large data sizes with REST APIs, such as file uploads, is rather straight forward. The received file can be treated as a stream, using very little memory. Re: streams, I've found that an opaque binary stream in REST is okay, but the moment I want to stream messages, my life is hell. I keep running into this, and it's such a pain. If I have to stick with REST, I end up inventing a bespoke RPC protocol to allow for sending errors as part of the stream, either as part of the message or as a trailer header (and trailers have their own issues like no browser support). And then the semantics of HTTP status codes have to change. The reason I often stick with REST is that infrastructure supports HTTP/1 much better than h2/gRPC (such as L7 load balancers, caching, etc.). JSON RPC is not always a good answer either as caching POSTs is typically not well-supported and using GET with JSON RPC is discouraged and fraught with issues. I would definitely prefer to just use gRPC but the poor middlebox support sometimes makes it cost-prohibitive. What a mess.
- danpalmer 4y agoFrom the article: "This is a very nice advantage of gRPC in comparison to REST, which only supports unary requests." You're right that files can be streamed and it does say that, but additionally there's no reason why messages can't be streamed down an open connection. Out of interest, as I hadn't considered middlebox support, what sort of things do you find becomes problematic? Doesn't TLS mitigate that? Or are you thinking of niche environments like companies that require intercepting all traffic on their networks? I realise those use-cases do exist, but they're pretty uncommon now as more people realise they're terrible security practice.
- cle 4y agoI'm talking about L7 middleboxes like HTTP load balancers, API gateways, caches/CDNs, etc.
- danpalmer 4y agoOh fair enough. I guess that's true, although I'm not sure I'd see too much of a problem there. For load balancers there are options that work fine with gRPC, similarly API gateways. Caches and CDNs no (at least I haven't seen any), but then again, I'm skeptical about putting CDNs in front of business logic, and would only ever use them for actual content (where the serving logic doesn't matter). Even logged out usage of APIs still often has analytics and other stuff that means you want to hit the backend every time.
- magicalhippo 4y ago> but you can build quite adaptable clients that can respond to changing APIs well Any good examples on how to do this for non-trivial API changes?