GraphQL is a performance nightmare, and while it might have nice and flashy dev tooling, it's fundamentally unoptimizable without extensive development investment - something that isn't an issue with REST.
That feels really true. I worked on a really large gql api, and it was a performance nightmare, lots of 10+ second queries that thrashed our database.
Fine grained security was a nightmare. We found no existing solutions, and rolled a few different solutions for this that were all awful and leaky. Eventually we threw a bunch of money at h1 to tease it all out.
Having written large code bases in graphql I really disagree with this statement. It is just a different mindset and I like it. It does make you think way more in terms of data and their relations instead of endpoints. Sure you might get N+1 problems but its easy to mitigate and I prefer doing that on the backend instead of the frontend doing those calls.
But I feel like REST and OpenAPI are fine especially if you start from the backend. I think with .NET Web APIs, the story is particularly good since it has out-of-the-box tooling for OpenAPI spec generation based on your exposed endpoints and models and then the option to customize that as needed.
I've recently been working with it trying to get hot reload working on the frontend client generation and it's a fantastic DX with minimal wiring: https://chrlschn.dev/blog/2023/10/end-to-end-type-safety-wit...
Openapi is not human readable IMO and the point is you design the API waaaay before you write any line of code. The api should express the business needs and be a two way discussion with the frontend people.
I don't get the stubbornness here. OpenAPI is not hard??? It's just JSON schema + some routes and effectively conveys the same information as a GraphQL schema, possibly more if you're not using custom directives and such.
> Then each side takes the contract and go implement the frontend and the backend and it just works
This is not unique to GraphQL. There's almost zero difference between programming to an OpenAPI spec vs a GraphQL schema - they're both API interface definitions.
Code should not inform design.
Design informs code.
The problem that killed SOAP, to my mind, was growing complexity that eventually started to outweigh the benefits of the protocol. Not every implementation supported every new complication that, say, MS kept inventing, it hurt interoperability.
I think a modern sort-of-replacement for the SOAP's use case is GRPC. It eschews the heavyweight XML and tries to keep things simple, while staying reasonably typesafe, declarative, discoverable, and extendable.
The key here is overall speed, but you can't trade the time spent learning/understanding the API contract for these crazy complicated tools. The developer still has to look at the operations and data models exposed by the API, understand them, amd plan for how to integrate them into the larger application.
The big bonus of the human documentation approaches today is that time is somewhat combined with building the client. The downside of course is that it's a human doing it. My point here is that you can't take the time a human is going to spend understanding the API concepts and then tack on a bunch of time learning, configuring, and running the client gen code and associated infrastructure as well and expext that your solution is going to win.
The more complicated these codegen setups get, the less comicated just reading some docs and spinning up a few lines of client code is. And guess which I'm going to choose as a dev? Whatever is overall fastest and gets me on to the problems I'm really trying to solve.
1. Design your API in yaml 2. Run a mock API 3. Develop the App, iterate mock API 4. Implement backend and ship
No code generation needed. Generate types if you want.
Most apps nowadays have a mobile app, so you need the API anyways...
The barrier you presume is that OpenAPI specs are hard to write. Raw oAPI in yaml is indeed a pain, but there are good DSL's out there.
I personally love Zod->OpenAPI, via https://ts-rest.com which uses https://www.npmjs.com/package/@anatine/zod-openapi. https://github.com/asteasolutions/zod-to-openapi is another alternative for Zod.
> The big bonus of the human documentation approaches today is that time is somewhat combined with building the client.
This is wild to me; human documentation is absurdly error-prone and it's almost always and immediately out of date. (Zod or other DSL) -> OpenAPI -> generated docs (and types! and clients! and mocks!) are always going to be better; always accurate, and faster. The upfront cost is slightly higher, but the ROI is _significant_.
OpenAPI specs lend themselves to excellent docs, ala Mintify or Docusaurus. Even interactive ones, like Swagger UI. The vast majority of API browsers & tooling understands OAPI, so why re-create (an often incomplete) version of the truth when using those tools?
> Whatever is overall fastest and gets me on to the problems I'm really trying to solve.
You may start (slightly) faster, but you'll incur significant cost when you move past the "trivial implementation" stage.
For instance:
- Do you do request & response validation on the server? That'll often need duplication on the client (e.g, error messages, and once out of sync, client-side validation mismatches server-side response)
- Typescript on client & server? Then you're already doing the manual work (often more than once) that oAPI->types would get you for free.
- Implementing client-side XHR calls manually, and getting typing right, is a pretty significant undertaking. Multiply that by the number of client-side stacks the API will be consumed by. Or, just generate them via OAPI (or real-time infer via something like ts-rest)
- TS on client, but another BE stack? OpenAPI, when used right, ensures the "contract" is 1:1. When BE changes, client needs changing -- or it breaks. You want this safety.
- Manually mocking API responses is wasteful; write good oAPI specs and auto-generate mocks (e.g, MSW).
- Do you test the real API implementation? OpenAPI specs can help you do that automatically.
At this stage of my career, I would turn down a job offer from a company/team that wasn't willing to use OpenAPI or equivalent single-source-of-truth (*unless I'm in a truly desperate situation)
It's first non-draft release was 5 years ago. [2]
It's first release under community governance was 2 years ago. [3]
[1] https://github.com/graphql/graphql-spec/releases/tag/July201...
[2] https://github.com/graphql/graphql-spec/releases/tag/June201...
[3] https://github.com/graphql/graphql-spec/releases/tag/October...
I'm a huge fan of this general concept, so you're definitely on the right path imo. That said, two things are jumping out at me:
- Users would still be writing OpenAPI specs/JSON Schema by hand, an incredibly annoying and tedious process (unless using a nicer DSL)
- Generation/build steps are annoying (but likely unavoidable here)
As pointed out by many other comments, an unfortunate amount of teams aren't writing OAPI specs. I personally feel this is a major mistake for anyone building an API, but that's a discussion for another day.
I've been using https://www.ts-rest.com, a similar project, for a few months now. Instead of relying on OpenAPI specs as the source, you define the "contracts" using Zod. These contracts are essentially OpenAPI specs, but Zod makes for a MUCH better DSL. I really like that...
- Real-time type checking without generator steps, both server & client-side. XHR clients like `fetch`, `react-query`, etc clients are inferred from the contract.
- The Zod contracts _can_ generate/output OpenAPI specs and Mock Service Worker mocks for testing (as needed, not required)
- (Optional) Automatic request & response validation based on Zod contract definitions, no additional code needed.
- (Node) Backend agnostic (partially, anyway: NextJS, Express, Nest and Fastify supported atm)
- Works very well with `react-hook-form` & `ZodResolver`, so e.g an invalid value on client-side shows the same error as the API would have if request were fired.
- Zod types can be used as typescript (z.infer), a wonderful way to re-use e.g model types in client-side components.
This ts-rest experience has fundamentally solidified a belief in me: One single source of truth, propagating through the system, is _the_ best way to build safely and efficiently.
I am almost ashamed to look back on the many, many projects I've worked on where APIs and client-side did not share truth. Duplication of (hand-rolled) types, error messages, etc is horrific in retrospect.
I don't want to think about the amount of bugs I've come across due to this dual (at best) truth approach.
There are indeed popular DSLs and code to openapi solutions out there. Many of which are easy to plug in to the openapi-stack libraries btw!
I guess I personally always found it frustrating to try to control the generated OpenAPI output using additional tooling and ended up preferring yaml + a visualisation tool as the api design workflow. (e.g. swagger editor)
But something like https://buildwithfern.com, or using zod as substitute for json schema may indeed be worth a try as a step before emitting openapi.
The great thing about OAPI is there's _so much tooling_ available, but it can be daunting and very frustrating to find the "right one". I spent more hours than I'd care to count wading through the ecosystem,
Perhaps it'd be a good idea to promote a few tools via your project? I suspect many potential users would fall off early because they (imo wrongly) believe the upfront cost of writing the OAPI spec is too much to ask. I do understand the reaction if they don't know of good DSLs, though.
IMO, https://openapistack.co/docs/examples/building-apis/#writing... would be a good place to add that.
PS: ts-rest's video on the front page is what immediately convinced me to try it out. Your current interactive example is nice, _but_ it doesn't product type errors for me so the value isn't as immediately obvious (I'm assuming watch doesn't work in the sandbox?).
My big foot gun for this is that you can manually write jsonschema that doesn't have a nicely serializable java representation, making it hard to use cross-language, and you don't find out that that's the case until you try
REST is more secure, cacheable, and more performant on the server side as field resolution doesn't need to happen like it does with GraphQL. I'm told it is easier to develop against on the client side, and this is a trade-off, but I favor REST applications over GraphQL ones as a DevOps engineer. They are much easier to administer infrastructure-wise. I can cache the requests, I don't need to stand up an Apollo router, and WAF support for GraphQL is still pretty nacent. My coworker found a GraphQL query only about five layers deep that could tip over a service. Please don't put cycles in your graphs.
Data at our company suggests that several small requests actually do better performance-wise than one large one. We switched to GraphQL a year and a half ago or so, but this piece of data seems to suggest that we might have been better off (performance wise on the client side) just sticking with REST. My suggestion to that effect was not met with optimism either on the client or server side. Apparently there are server-side benefits as well, allowing for more modular development or something like that.
I have used OpenAPI using connexion[1]. It was hard to understand at first, but I really liked that the single source of truth was one schema. It also made it really easy to develop against the API because it came with a UI that showed the documentation for all the REST end points and even had test buttons.
I find arguments like this a bit odd. That's a pretty deep query in REST as well.
I don't have extensive experience with GraphQL, but the complaints I see about it often seem like things you just shouldn't be doing anyways - or, if you do, they're going to be rough in REST as well.
Supporting nested queries isn’t really a common thing in REST, and it’s simpler to rate limit clients by resource than query complexity.
Let me explain: standards are great, type safety is great, API contracts are great. Locked into a particular language is not great. In fact it's bad for the author. tRPC and now this assume my team has the desire and time to move to another language. The best frameworks assume none of that.
I'm not asking for implementations for every possible language given a framework. I'm asking for a framework for which any possible language can be built upon because the constructs are simple and easy to follow: graphql does this pretty well despite some of the nuances. Bonus points if the author provides examples out of the box in a variety of languages.
This seems like a nice set of tools for doing so in Node/Typescript but the general pattern of using OpenAPI contracts is language agnostic.
Rest is tied to HTTP forever - GraphQL can be separated, easily.
Rest communicates inputs and outputs in too many ways for my liking any more: headers, paths, bodies, query params, and dare I say method.
One complaint for GQL is that potentially they had a chance to standardize paging, filtering, etc... instead every schema is customized.
I guess we'll have to create a new standard at some point. We'll never get this shit right.
It’s not like HTTP is going to go away in a while.
I find that AsyncAPI is a nice extension of OpenAPI/REST ideas if you need to go beyond request / response.
We now follow a kind of hybrid approach in which the routes and types are created in code first, without actual implementation (just return 404). This auto generates the spec.yaml as well as any vendor code we might need (via client generator). I think this is quite a productive workflow as well because the type generation in code is more convenient than typing yaml by hand and everything is always in sync
I strongly disagree with this. REST APIs are usually a complete mess and follow no conventions at all. Even if OpenAPI is being used, the majority of OAS documents have errors or are entirely broken. I'm Working on tooling to automatically parse OAS and transform it to GraphQL schemas. There's not a single day where we don't find another broken OAS. Compare that to GraphQL where we now have powerful linters for schemas etc... But even without, the average GraphQL API is definitely in better shape than the average REST API, and that's simply because the tooling enforces better boundaries. You might have a correct OAS vs every GraphQL server actually follows the GraphQL spec.
Totally agree.
GraphQL tooling is generally just better. It enforces a Schema first workflow and thus more emphasis on conventions and design.
OpenAPI tends to be an after thought with teams building REST APIs. Swagger started out as a way to add docs and generate SDKs.
That was exactly my motivation for building openapi-stack. GraphQL-like tooling, but for teams using REST.
Love that it makes the client somewhat backend agnostic, but the tools for the OpenAPI backend also look great.
Thank you for this, I hope it is successful in achieving some adoption!
The nice thing is you already have an openapi spec, so it’s pretty trivial to eject from fastify swagger and switch to openapi-backend if you want!
Here’s an example of openapi-backend running on Fastify
https://github.com/openapistack/openapi-backend/tree/main/ex...
This might be the best OpenAPI Typescript-based project I've seen so far. The ones I've used often tie you into a specific framework and do not perform any validation on the parameters at all.
How does this compare to other solutions, like https://openapi-ts.pages.dev/?
The openapi-typescript package is a library for generating types from openapi spec, similar to the openapicmd typegen command provided by openapi-stack.
The new openapi-typescript-fetch seems similar to openapi-client-axios, but using fetch instead of axios for a more lightweight approach.
Both libraries are great and well aligned with goals of openapi-stack!
In addition to type generation and consuming APIs, https://openapistack.co provides tools for building and mocking API backends with the openapi-backend library, as well as a general cli tool to work with openapi files and invoke APIs via the command line.
The core mission of https://openapistack.co is to bring together tools for an end to end full stack toolkit for building and consuming typesafe REST APIs.
Its all about REST vs GraphQL vs gRPC vs Async API vs native SDKs. It's all about how to make it easier or faster for developers to build these APIs.
Never about, how to make this API best for the API client. That is what matters the most. Focus on clients and can they get the job done. If it does, no need to over engineer!
My opinion is more nuanced now, but still it’s super cool.
Show some code or small example on that main page. I have no idea or sense to compare it to graphql without some small toy example.
There is a full interactive sandbox example on the front/landing page https://openapistack.co
But point taken, will make sure code examples are visible on the overview page
Wish it would use undicci/fetch instead of axios though.