16 ms·
REST vs GraphQL vs gRPC
- hashkb 6y agoToo concise. This wouldn't be helpful for making a choice; or will mislead. Right off the top, it's not necessary to write REST endpoints for each use case. Many REST apis have filtering and joining, just like gql. Edit: claiming gql solves over/underfetch without mentioning that you're usually still responsible for implementing it (and it can be complex) in resolvers is borderline dishonest.
- parhamn 6y agoI'd call it completely lacking, not concise. E.g. its already conflating transport & serialization. But HN loves a good serializer debate so this will be an active thread.
- majkinetor 6y agoMust be a bad student homework ...
- sneak 6y agoOne thing that people seem to gloss over when comparing these is that you also need to compare the serialization. gRPC using protobuf means you get actual typed data, whereas typing in JSON (used by the other two) is a mess (usually worked around by jamming anything ambiguous-in-javascript like floats, dates, times, et c into strings). If you're using typed languages on either the client or the server, having a serialization system that preserves those types is a very nice thing indeed.
- dboreham 6y ago> usually worked around by jamming anything ambiguous like floats, dates, times, et c into strings because nobody has ever done this with protobuf... btw what is the protobuf standard type for "date"?
- sneak 6y agoint64 representing unix epoch millis (in UTC) is what I usually use. You need to jump through an additional hoop to store timezone or offset. You can, of course, do the thing that JS requires you always do and put an ISO8601 date in a string. This has the benefit of storing the offset data in the same field/var. Javascript needs int64s as strings, I believe, because the JS int type maxes out at 53 bits.
- deleted 6y ago[deleted]
- teeray 6y agoThat would be a Timestamp, found in the "well-known types" [0]. You can use your own encoding (milliseconds since epoch, RFC3339 string, etc), but using Timestamp gets you some auto-generated encoding / decoding functions in the supported languages. [0] https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/timestamp https://developers.google.com/protocol-buffers/docs/referenc...
- jeffbee 6y agoTimestamp is fundamentally flawed and should only be used in applications without any kind of performance/efficiency concerns, or for people who really need a range of ten thousand years. The problem with Timestamp is it should not have used variable-length integers for its fields. The fractional part of a point in time is uniformly distributed, so most timestamps are going to have either 4 or 5 bytes in their representation, meaning int32 is worse than fixed32 on average. The whole part of an epoch offset in seconds is also pretty large, it takes 5 bytes to represent the present time. Since you also have two field tags, Timestamp requires 11-12 bytes to represent the current time, and it's expensive to decode because it takes the slowest-possible path through the varint decoder. Reasonable people can used a fixed64 field representing nanoseconds since the unix epoch, which will be very fast, takes 9 bytes including the field tag, and yields a range of 584 years which isn't bad at all.
- jayd16 6y agoA timestamp is not quite the same thing as a calendar date.
- chrismorgan 6y agoNot loading for me (PR_CONNECT_RESET_ERROR on Firefox, ERR_CONNECTION_RESET on Chrome). https://web.archive.org/web/20210315144620/https://www.danhacks.com/software/grpc-rest-graphql.html https://web.archive.org/web/20210315144620/https://www.danha...
- deleted 6y ago[deleted]
- throwaway4good 6y agoAm I the only who simply does remote procedure calling over http(s) via JSON? Not REST as in resource modelling but simply sending a request serialized as a JSON object and getting a response back as a JSON object.
- deleted 6y ago[deleted]
- sneak 6y agoI've done JSON-RPC at scale before and the one downside to it is that you have to write a custom caching proxy for readonly calls that understands your API. With REST you can just use a normal HTTP caching proxy for all the GETs under certain paths, off the shelf. Using a hybrid (JSON-RPC for writes and authenticated reads, REST for global reads) would have saved me a lot of time spent building and maintaining a JSON-RPC caching layer. There is benefit to a GET/POST split, and JSON-RPC forces even simple unauthenticated reads into a POST. The other issue with JSON-RPC is, well, json. It's not the worst, but it's also not the best. json has no great canonicalization so if you want to do signed requests or responses you're going to end up putting a string of json (inner) into an key's value at some point. Doing that in protobuf seems less gross to me.
- hashkb 6y agoIf I'm going to neuter HTTP like that, I at least do RPC over websockets for realtime feel. And I still usually run it through the whole Rails controller stack so I don't drive myself insane.
- throwaway4good 6y agoPersonally I prefer to have explicit control over the caching mechanism rather than leaving it to network elements or browser caching. That is explicity cache the information in your JavaScript frontend or have your backend explicitly cache. In that way it is easy to understand and your can also control what circumstances a cache is invalidated.
- 6y ago
- sshb 6y agoI've recently stumbled upon WebRPC https://github.com/webrpc/webrpc https://github.com/webrpc/webrpc It solves gRPC's inability to work nicely with web browsers.
- alexhutcheson 6y agoAre you familiar with gRPC-web? https://github.com/grpc/grpc-web https://github.com/grpc/grpc-web
- sshb 6y agoYes, it bloats js bundle size quite a lot due to protobuf.
- Sean-Der 6y agohttps://github.com/jsmouret/grpc-over-webrtc https://github.com/jsmouret/grpc-over-webrtc is another way to get into the browser. It's nice that you don't have to do any translation. Just gRPC in/out of the browser.
- TeeWEE 6y agoI think for people who didnt try GRPC yet, this is for me the winner feature: "Generates client and server code in your programming language. This can save engineering time from writing service calling code" It saves around 30% development time on features with lots of API calls. And it grows better since there is a strict contract. Human readability is over-rated for API's.
- omginternets 6y agoThe flip side (IMHO, at least), is that simple build-chains are underrated. As much as I love a well-designed IDL (I'm a Cap'n Proto user, myself), the first thing I reach for is ReST. It most cases, it's sufficient, and in all cases it keeps builds simple and dependencies few.
- sagichmal 6y ago> The flip side (IMHO, at least), is that simple build-chains are underrated. Wow, yes! Yes! IDLs represent substantial complexity, and complexity always needs to be justified. Plain, "optimistically-schema'd" ;) REST, or even just JSON-over-HTTP, should be your default choice.
- mattwad 6y agoNot for me. I tried this with Javascript a couple years ago, and it was painful mapping to and from gRPC types everywhere. There's no "undefined" for example if you have a union type. You have to come up with a "EMPTY" value. On top of that, we had all kinds of weird networking issues that we just weren't ready to tackle the same way we could with good ol' HTTP.
- codegladiator 6y agoHave you seen OpenAPI ? Generating client and server code in your programming language for rest/graphql/grpc is not new.
- dtech 6y agoThere's solutions like that for GraphQL [1] and REST too. For REST OpenAPI/Swagger has a very large ecosystem, but does depend on the API author making one. [1] https://graphql-code-generator.com/ https://graphql-code-generator.com/
- mixxit 6y agoI wish gRPC was bidirectional For now I will stick to SignalR
- malkia 6y agoIt supports bidi, and also single request, multiple responses, or multiple requests, single response - https://grpc.io/docs/what-is-grpc/core-concepts/#bidirectional-streaming-rpc https://grpc.io/docs/what-is-grpc/core-concepts/#bidirection...
- mixxit 6y ago'Client- and server-side stream processing is application specific' Sounds like write it yourself using two streams
- hankchinaski 6y agoi don't know about you but in my experience, unless you have Google's size microservices and infrastructure gRPC (with protocol buffers) is just tedious. - need an extra step when doing protoc compilation of your models - cannot easily inspect and debug your messages across your infrastructure without a proper protobuf decoder/encoder If you only have Go microservices talking via RPC there is GOB encoding which is a slimmed down version of protocol buffer, it's self describing, cpu efficient and natively supported by the Go standard library and therefore probably a better option - although not as space efficient. If you talk with other non-Go services then a JSON or XML transport encoding will do the job too (JSON rpc). The graphQL one is great as what is commonly known as 'backend for frontend' - but inside the backend. it makes the life of designing an easy to use (and supposedly more efficient) API easier (for the FE) but much less so for the backend, which warrants increased implementation complexity and maintenance. the good old rest is admittedly not as flexible as rpc or graphql but does the job for simpler and smaller apis albeit I admit i see, anecdotally, it being used less and less
- deleted 6y ago[deleted]
- lokar 6y agoI wish gRPC has the same ability as stubby (what google uses internally): logging rpc (calls and replies, full msg or just the hdr) to a binary file and a nice set of tools to decode and analyze them.
- jeffbee 6y agohttps://github.com/grpc/proposal/blob/master/A16-binary-logging.md https://github.com/grpc/proposal/blob/master/A16-binary-logg...
- jayd16 6y ago> unless you have Google's size microservices and infrastructure The protobuf stuff can start to pay off as early as when you have two or more languages in the project.
- bigmattystyles 6y agoMaybe it’s because I’m in the .net world, but why is there never any love for odata? If you have SQL in the back, it’s great!
- littlecranky67 6y agoOData had its momentum but since a couple of years at least, there is no maintained JS odata library that is not buggy and fully usable in modern environments.
- bigmattystyles 6y agoI can't disagree there, and for all the work MS is putting into it right now for it in dotnetcore - I don't understand how they can have this big a blind spot.
- pietromenna 6y agoI agree with you that there is support for oData v2 and v4. But they are not exactly mainstream out there. I like oData v4 and I try to use it when it is opossible.
- lokar 6y agoThis is really just a comparison of the basic wire format. Full RPC systems like gRPC are much more.
- sbayeta 6y agoCould you please elaborate briefly? Thanks!
- swyx 6y agoi think they are talking about how it is very standard for gRPC systems to generate server and client code that make it very easy to use. see this comment for more https://news.ycombinator.com/item?id=26466902 https://news.ycombinator.com/item?id=26466902
- lokar 6y agoAlso, many others: - Standard Authentication and identity (client and server) - Authorization support - Overload protection and flow control - Tracing - Standard logging - Request prioritization - Load balancing - Health checks and server status
- _ZeD_ 6y ago... vs soap?
- bluejekyll 6y agovs corba? Between soap and grpc, grpc is the better choice at this point. It’s simpler to implement, and has decent multi-language support.
- sillyquiet 6y agoIn my opinion, it makes very little sense to compare GraphQL to REST from a client perspective - if you are only going to be hitting a single API endpoint, use REST (or gRPC I guess). The overhead of GraphQL doesn't make it worth using at that scale. The strength and real benefit of GraphQL comes in when you have to assemble a UI from multiple data sources and reconcile that into a negotiable schema between the server and the client.
- fastball 6y agoThough there are also solutions like Hasura where GraphQL makes sense at approximately any scale because it allows you to create an API from nothing in about 10 minutes.
- meowzero 6y agoAnother con of GraphQL (and probably GRPC) is caching. You basically get it for free with REST. REST can also return protobufs, with content type application/x-protobuf. Heck, it can return any Content-Type. It doesn't have to be confined to JSON. GRPC needs to support the language you're using. It does support a lot of the popular languages now. But most languages have some sort of http server or client to handle REST.
- ec109685 6y agoWe solve the cacheability part by supporting aliases for queries by extended the GraphQL console to support saving a query with an alias. Also, with gzip, the size of json is not a big deal given redundant fields compress well.
- pavel_lishin 6y agoCacheability isn't just about the transfer, it's also about decreasing server load in a lot of applications. An expensive query might return a few bytes of JSON, but may be something you want to avoid hitting repeatedly.
- ec109685 6y agoSorry, they were addressing the two points from the comment above. I agree cacheability and transfer size are two separate aspects.
- cogman10 6y agoWhat popular languages aren't supported by GRPC?
- meowzero 6y agoScala, Swift, Rust, C, etc. I guess with Scala you can probably use the Java one. But they have one for Kotlin...
- ledauphin 6y agoa big thing not called out here that both gRPC and GraphQL natively do, but that REST does not natively do, is schema definition for the payloads. It's massively useful to know exactly what 'type' a received payload is, as well as to get built-in, zero-boilerplate feedback if the payload you construct is invalid.
- sagichmal 6y agoSure, but that utility also carries massive costs: the infrastructure and tooling required to work with those schema definitions, especially as they change over time. It's certainly not the case that the benefits always, or even usually, outweigh those costs.
- ledauphin 6y agoI disagree that tooling is required to work with them in the GraphQL case - you still end up getting and sending JSON in the vast majority of cases. With gRPC you're absolutely correct. Then again, I wasn't trying to make an argument for or against any of these technologies per se - just pointing out that this is a major part of the value provided that wasn't really called out in the article.
- bluejekyll 6y agoAdditional GraphQL con: it requires some thought and planning in order to ensure data is cacheable in CDNs and other reverse proxies. This is generally simpler in REST because the APIs tend to be more single use. In GraphQL you have to essentially predefine all the queries in order to achieve the same cache-ability of responses. Then identify those, essentially, over REST.
- robin21 6y agoSolved: https://www.apollographql.com/docs/apollo-server/performance https://www.apollographql.com/docs/apollo-server/performance... 2-stage request. 1. Hashes queries and uses GET requests. 2. If missing, sends a standard graphql as POST
- thdxr 6y agoHighly recommend taking a look at the JSONAPI spec - https://jsonapi.org/ https://jsonapi.org/ It directly addresses the cons mentioned in the article while retaining all the pros
- sagichmal 6y agoTried it. Definitely not ready yet, and the scope may be large enough that it won't ever get there. Also, many of its design choices are fundamentally in tension with statically typed languages. I think you can probably formalize JSON API schemas in a useful way, but JSON API ain't it.
- thinkingkong 6y agoAll these patterns are helpful because theyre consistent. The graphql and grpc systems are “good” because theyre schema driven so that makes automated tooling easier. That being said, the problem at smaller scales doesnt really exist too much. Saving bytes on the wire is such a weird optimization at early to mid stages that - unless latency is your actual problem ends up being an optimization with very little business value.
- sudowing 6y agoThe `versus` nature of this question was the driving force behind a project I built last year. I've been in multiple shops where REST was the standard -- and while folks had interest in exploring GraphQL or gRPC, we could not justify pivoting away from REST to the larger team. Repeatedly faced with this `either-or`, I set out to build a generic app that would auto provision all 3 (specifically for data-access). I posted in verbose detail about that project a few months ago, so here I'll just provide a summary: The project auto provisions REST, GraphQL & gRPC services that support CRUD operations to tables, views and materialized views of several popular databases (postgres, postgis, mysql, sqlite). The services support full CRUD (with validation), geoquery (bbox, radius, custom wkt polygon), complex_resources (aggregate & sub queries), middleware (access the query before db execution), permissions (table/view level CRUD configs), field redaction (enable query support -- without publication), schema migrations, auto generated openapi3/swagger docs, auto generated proto file. I hope this helps anyone in a spot where this `versus` conversation pops up. original promotional piece: https://news.ycombinator.com/item?id=25600934 https://news.ycombinator.com/item?id=25600934 docker implementation: https://github.com/sudowing/service-engine-template https://github.com/sudowing/service-engine-template youtube playlist: https://www.youtube.com/playlist?list=PLxiODQNSQfKOVmNZ1ZPXbPh6LeVDWtDRc https://www.youtube.com/playlist?list=PLxiODQNSQfKOVmNZ1ZPXb...
- ctvo 6y agoBananas vs. Apples vs. Oranges
- codegladiator 6y agoCon: Bananas have thickest skin so harder to peal
- giantrobot 6y agoCon: They taste gross.
- phaedryx 6y agoPro: eating the skin of an apple is easier
- speedgoose 6y ago> JSON objects are large and field names are repetitive I used to write protocol buffer stuff for this reason. But I realized after some time that compressed json is almost as good if not better depending on the data, and a lot simpler and nicer to use. You can consider to pre-share a dictionary if you want to compress always the same tiny messages. Of course json + compression is a bit more cpu intensive than protocol buffers but it's not having an impact on anything in most use cases.
- ericbarrett 6y agoI think your instinct to reach for the straightforward solution is good. gRPC has advantages, but it also comes with complexity since you have to bring all the tooling along. And the CPU burden of (de-)serializing JSON is a very different story than when Protobufs were developed in 2001.
- zedr 6y ago> Easily discoverable data, e.g. user ID 3 would be at /users/3. All of the CRUD (Create Read Update Delete) operations below can be applied to this path Strictly speaking, that's not what REST considers "easily discoverable data". That endpoint would need to have been discovered by navigating the resource tree, starting from the root resource. Roy Fielding (author of the original REST dissertation): "A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). (...) Instead, allow servers to instruct clients on how to construct appropriate URIs, such as is done in HTML forms and URI templates, by defining those instructions within media types and link relations. [Failure here implies that clients are assuming a resource structure due to out-of band information, such as a domain-specific standard, which is the data-oriented equivalent to RPC’s functional coupling]. A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API). "[1] 1. https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypert...
- arethuza 6y agoYou are quite correct, but by this stage the original definition of REST to include HATEOAS has pretty much been abandoned by most people. Edit: Pretty much every REST API I see these days explains how to construct your URLs to do different things - rather than treating all URLs as opaque. Mind you having tried to create 'pure' HATEOAS REST API I think I prefer the contemporary approach!
- stickfigure 6y agoNo mention of what I see as the biggest con of GraphQL: You must build a lot of rate limiting and security logic, or your APIs are easily abused. A naive GraphQL implementation makes it trivial to fetch giant swaths of your database. That's fine with a 100% trusted client, but if you're using this for a public API or web clients, you can easily be DOSed. Even accidentally! Shopify's API is a pretty good example of the lengths you have to go to in order to harden a GraphQL API. It's ugly: https://shopify.dev/concepts/about-apis/rate-limits https://shopify.dev/concepts/about-apis/rate-limits You have to limit not just number of calls, but quantity of data fetched. And pagination is gross, with `edges` and `node`. This is is straight from their examples: { shop { id name } products(first: 3) { edges { node { handle } } } } Once you fetch a few layers of edges and nodes, queries become practically unreadable. The more rigid fetching behavior of REST & gRPC provides more predictable performance and security behavior.
- stevebmark 6y agoedges and node come from Relay, not from the core GraphQL spec. They're just one way to do pagination. I like edges and node, it gives you a place to encode information about the relationship between the two objects, if you want to. And if all your endpoints standardize on this Relay pagination, you get standard cursor/offset fetching, along with the option to add relationship metadata in the future if you want, without breaking your schema or clients. edit: the page you linked to has similar rate limiting behavior for both REST and GraphQL lol
- wyattjoh 6y agoSeconded. I feel that the pagination style that Relay offers is typically better than 99% of the custom pagination implementations out there. There's no reason why the cursor impl can just do limit/skip under the hood (if that's what you want to do), but it unlocks you to change that to cursor based _easily_. { products(first: 3) { pageInfo { hasNextPage endCursor } edges { cursor node { handle } } } }
- mdavidn 6y agoThere are a variety of tricks to solve the over/under-fetching problems of REST. My default approach is JSON:API, which defines standard query parameters for clients to ask the server to return just a subset of fields or to return complete copies of referenced resources. https://jsonapi.org/ https://jsonapi.org/
- mumblemumble 6y agoI feel like this is rather shallow, and, by focusing so heavily on just the transport protocol, misses a lot of more important details. For starters, REST and "JSON over HTTP/1.1" are not necessarily synonyms. This description conflates them, when really there are three distinct ways to use JSON over HTTP/1.1: Actual REST (including HATEOAS), the "openAPI style" (still resource-oriented, but without HATEOAS), and JSON-RPC. For most users, the relative merits of these three considerations are going to be a much bigger deal than the question of whether or not to use JSON as the serialization format. Similarly, for gRPC, you have a few questions: Do you want to do a resource-oriented API that can easily be reverse proxied into a JSON-over-HTTP1.1 API? If so then you gain the ability to access it from Web clients, but may have to limit your use of some of gRPC's most distinctive features. How much do you want to lean toward resource-orientation compared to RPC? gRPC has good support for mixing and matching the two, and making an intentional decision about how you do or do not want to mix them is again probably a much bigger deal in the long run than the simple fact of using protocol buffers over HTTP/2. GraphQL gives clients a lot of flexibility, and that's great, but it also puts a lot of responsibility on the server. With GraphQL, clients get a lot of latitude to construct queries however they want, and the people constructing them won't have any knowledge about which kinds of querying patterns the server is prepared to handle efficiently. So there's a certain art to making sure you don't accidentally DOS attack yourself. Guarding against this with the other two API styles can be a bit more straightforward, because you can simply not create endpoints that translate into inefficient queries.
- stevebmark 6y agoThis post is just a brief summary of each protocol, I don't understand how it made it to the front page.
- applecrazy 6y agoI think it’s because of the robust discussion in these comments.
- ZephyrBlu 6y ago
- claytongulick 6y agoSurprised no one has mentioned what (to me) is the killer feature of REST, JSON-patch [1] Completely solves the PUT verb mutation issue and even allows event-sourced like distributed architectures with readability (if your patch is idempotent) I married it to mongoose [2] and added an extension called json-patch-rules to whitelist/blacklist operations [3] and my API life became a very happy place. I've replaced hundreds of endpoints with json-patch APIs and some trivial middleware. When you couple that stack with fast-json-patch [4] on the client you just do a simple deep compare between a modified object and a cloned one to construct a patch doc . This is the easiest and most elegant stack I've ever worked with. [1] http://jsonpatch.com/ http://jsonpatch.com/ [2] https://www.npmjs.com/package/mongoose-patcher https://www.npmjs.com/package/mongoose-patcher [3] https://github.com/claytongulick/json-patch-rules https://github.com/claytongulick/json-patch-rules [4] https://www.npmjs.com/package/fast-json-patch https://www.npmjs.com/package/fast-json-patch
- ryandvm 6y agoI am totally expecting the next fad in web development to be just exposing a raw SQL interface to the front-end...
- js8 6y agoSimplify things? No way! The next fad will be SQL over GraphQL.
- fragile_frogs 6y agoand those queries well be send through gRPC.
- robin21 6y agoJokes aside, isn’t this ultimately what we are all looking for? We have added so many layers and translations between our frontend and database. Graphql brought us closer and it starts to run into some of the security concerns already. What if someone just made this direct sql interface safe/restricted?
- nym3r0s 6y agoApache Thrift is another great way of server-server & client-server communication. Pretty similar to protobuf but feels a bit more mature to me. https://thrift.apache.org/ https://thrift.apache.org/
- jrsj 6y agoBig missing con for GraphQL here — optimization. Doing the right thing in simple cases is easy; in more complex cases you’re looking at having to do custom operations based on query introspection which is an even bigger pain in the ass than using REST in the first place UNLESS all of your data is in one database OR if you’re using it as a middleman between your clients and other backend services, you have a single read-through cache like Facebook which allows you to basically act as if everything were in a single database.