top | item 37833849

(no title)

t1mmen | 2 years ago

Cool to see more of these kinds of projects, nice work OP!

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.

discuss

order

anttiviljami|2 years ago

Thank you for your encouraging words and insights!

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.

t1mmen|2 years ago

Good point, and one that counts towards ts-rest atm; If you're bringing your own OpenAPI spec, there is (not yet) an OpenAPI->Zod converter available.

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?).

8note|2 years ago

> Users would still be writing OpenAPI specs/JSON Schema by hand, an incredibly annoying and tedious process (unless using a nicer DSL)

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