Hacker News new | past | comments | ask | show | jobs | submit login
OpenAPI v4 (aka Moonwalk) Proposal (github.com/oai)
222 points by mooreds on May 31, 2023 | hide | past | favorite | 151 comments



I've tried using OpenAPI a few times, it's been...lackluster... I probably won't use it again.

Here are my gripes:

1) For me one of the biggest selling points is client code gen (https://github.com/OpenAPITools/openapi-generator). Basically it sucks, or at least it sucks in enough languages to spoil it. The value prop here is define the API once, code gen the client for Ruby, Python and Scala (or insert your languages here). Often there are a half dozen clients for each language, often they are simply broken (the generated code just straight up doesn't compile). Of the ones that do work, you get random PRs accepted that impose a completely different ideological approach to how the client works. It really seems like any PR is accepted with no overarching guidance.

2) JSONSchema is too limited. We use it for a lot of things, but it just makes some things incredibly hard. This is compounded by the seemingly limitless number of version or drafts of the spec. If your goal is interop, which it probably is if you are using JSON, you have to go our and research what the lower common denominator draft spec JSONSchema support is for the various languages you want to use and limit yourself to that (probably draft 4, or draft 7).

On the pros side:

It does make pretty docs - kinda wish it would just focus on this and in the process not be as strict, I think it would be a better project.


I find it odd that you've struggled so much with generating API clients. I've generated C# and TypeScript (Angular's HttpClient and React Query) clients for my API and never had any issues with them. With that being said, I didn't use OpenAPI's Java-based code generators and rather used ones made by third-party developers such as NSwag[0] and openapi-codegen[1].

[0]: https://github.com/RicoSuter/NSwag

[1]: https://github.com/fabien0102/openapi-codegen


You said it yourself — the “official” generator is awful and very hard to modify or extend (well, you didn’t say that, but I’m saying it) and while there are many alternatives, they’re not always easy to find. I had some success with swagger-typescript-api[1], but eventually got tired of it and wrote my own generator. Despite looking around quite a bit at what’s available, I never heard of openapi-codegen, which looks quite good.

I think it’s a pretty big problem for many devs that so many of the options are mediocre and they’re quite difficult to evaluate unless you have a lot of experience, and even then it takes a lot of time.

[1]: https://github.com/acacode/swagger-typescript-api


Technically, there isn't an "official" OpenAPI 3.x tool of any sort. SmartBear/Swagger is no more official than any other vendor with 3.0+ (obviously it's different for the versions named "Swagger"!). I am working on an official parser/linter (oascomply) on a contract for the OpenAPI Initiative to set a baseline to help tool developers implement consistent support for the spec. However, this is more about the parts of OAS outside of the Schema Object.


Nswag leaves much to be desired. I deployed an OpenAPI server and the initial deployment partners using nswag begged us to change the API to suit an issue that was reported and nswag hadn't fixed in years. I respectfully told them to pound sand and deal with it manually or better yet be a good citizen on the ecosystem that they are using for free and contribute a patch. Last I checked they were still manually patching their codegen on each deploy. /Shrug

Nswag has important issues that are many years old still in their backlog.

1.6k issues, oldest unresolved 7 years old:

https://github.com/RicoSuter/NSwag/issues?q=is%3Aissue+is%3A...


I've been using redux toolkit's OpenAPI code generator for a side project and it's been pretty good. The documentation is a bit lacking and it could certainly use more work to make names more customizable. The generated code comes out looking very much machine generated. But I love that RTKQuery (redux toolkit query) has client side caching so that if I use a query param that was already used before, it will remember and just serve from the local cache.

But it's been nice being able to make a backend change, run the code generator, and then be able to use whatever API in react. I hope this type of stuff gets developed more!

[0] - https://github.com/reduxjs/redux-toolkit/tree/master/package...


I've had the same experience and gripes as the comment op, but RTKquery is one of the better experiences I've had with OpenApi based tooling.

But ya... JSONschema is confusing and doesn't really support type composition the way you think it would.

If your API model is simple, then you'll probably have decent experience with clients... But if you need "allOf/anyOf/oneOf" and to restrict "additionalProps", you're probably going to have a rough time...


Yup. JSON Schema is a constraint system, not a data definition system. https://modern-json-schema.com/json-schema-is-a-constraint-s...


This. I've found you can get a long way with NSwag, and the barrier to entry is low. I've got a post that walks through how to get a TypeScript and a C# client generated.

https://johnnyreilly.com/generate-typescript-and-csharp-clie...


I'm working on a company https://speakeasyapi.dev/ with the goal of helping companies in this ecosystem get great production quality client sdks, terraform providers, cli(s) and all the developer surfaces you may want supported for our API. We also manage the spec and publishing workflow for you so all you have to do is build your API and we'll do the rest.

Feel free to email me at sagar@speakeasyapi.dev or join our slack (https://join.slack.com/t/speakeasy-dev/shared_invite/zt-1cwb...) . We're in open beta and working with a few great companies already and we'd be happy for you to try out the platform for free!


Created some accounts for advertising? Accounts created some hours ago and just praising you endlessly…..


The original comment and every reply reads like it was copied straight from a marketing brief. This is everyone's reminder that Hacknernews is not immune to astroturfing, and it's often done much more subtly.


Definitely check out Speakeasy— we've been using them and the experience + team are fantastic


We at Airbyte are happy users of the speakeasy platform. The CLI generator is easy to get started with and generate nice api clients that are constantly getting better. Their api developer platform does a great job of managing new client builds and deploys to the package repositories as well. Super please with the experience so far.


What's the thought process behind the product with API Keys? Why do you build those for your end user, and what's the goal of someone using that. Unless I'm misinterpreting.


+1 to Speakeasy ~ Our end-users love to use the SDKs that are automatically generated through Speakeasy, based off our API.


I've been working with Speakeasy for a couple of month now to produce client libraries for our customers to use. They've finally made an OAS-based code generator that's great. In fact, it's getting even better with useful functionality being released on an almost biweekly basis. I would strongly recommend Sagar and the Speakeasy team to anyone looking to support high quality client libraries for your customers.


I'm one of the builders of an open source project (https://buildwithfern.com/docs) to improve API codegen. We built Fern as an alternative to OpenAPI, but of course we're fully compatible with it.

The generators are open source: https://github.com/fern-api/fern

We rewrote the code generators from scratch in the language that they generate code in (e.g., the python generator is written in python). We shied away from templating - it's easier but the generated code feels less human.

Want to talk client library codegen? Join the Fern Discord: https://discord.com/invite/JkkXumPzcG


I think it's worth pointing out that a lot (most?) of Fern's complaints against OpenAPI are really complaints against JSON Schema. There have been talks before about allowing other schema systems in OpenAPI - I wouldn't be incredibly surprised to see such things come up for Moonwalk. JSON Schema is not not a type definition system https://modern-json-schema.com/json-schema-is-a-constraint-s....

It's also worth noting that most JSON Schema replacements I've seen that prioritize code generation are far less powerful in terms of runtime validation (I have not examined Fern's proposal in detail, so I do not know if this is true for them).

The ideal system, to me (speaking as the most prolific contributor to JSON Schema drafts-07 through 2020-12), would have clearly defined code generation and runtime validation features that did not get in each other's way. Keywords like "anyOf" and "not" are very useful for runtime validation but should be excluded from type definition / code generation semantics.

This would also help balance the needs of strongly typed languages vs dynamically typed languages. Most JSON Schema replacements-for-code-generation I've seen discard tons of functionality that is immensely useful for other JSON Schema use cases (again, I have not deeply examined Fern).


Just wanted to chime in and say we are a big fan of Fern! It makes developing our APIs 10x easier as we get full end-to-end type safety and code completion, but the really great part is we get idiomatic client and server SDKs as well as OpenAPI output that we use to autogen documentation. Our small team of two engineers are able to ship multiple client facing SDKs because we are built on Fern!


Speed of development on these guys is huge, and have enjoyed using their SDKs. Community is getting involved in building things like auto-retry with backoff and other pretty helpful features in SDKs. Big fan of these guys!


I think that’s what most people are using it for, but having a single expressive (debatable) language to describe the contract an api offers has soo much potential.

GraphQL promised us apis that we can trust - since both the client and the server were implemented with the same schema, you would know for sure which requests the api would respond to and how, if it tried to do something outside of the schema, the server lib itself would through a 500 error. This allowed you to generate lean, typesafe clients.

OpenAPI kinda allows you to do that but for any other http api - I’ve written some code to use the schema as a “source of truth” for the server code as well, proving at compile time that the code will do the correct requests and responses for all the endpoints, paths and methods. So if you are reading the schema, you know for sure that the api is going to return this, and any change has to start from modifying the api.

And in turn this allows a “contract first” dev where all parties agree on the api change first, and then go to implement their changes, using the schema as an actual contract.

Combine this with languages with expressive type systems, and it allows you a style of coding thats quite nice - “if it compiles it is guaranteed to be correct”. Now of course this does not catch all bugs, but kinda confines them to mostly business logic errors, and frees you from needing to write tons of manual unit tests for every request.

Oh as a bonus it can be used for runtime request validation as well, which allows you to have types generated for those as well, for the client _and_ the server! Makes changes in the api a lot more predictable.

Client / server code generation can also be implemented as just type generation with no actual code being created, sidestepping a lot of complaints about code generators.

I did package it up as OS https://github.com/ovotech/laminar but no longer have access to maintain it as I no longer work there unfortunately.


> "contract first” dev

Just wanted say that this is very cool and I find it hard to understand why this is not already the norm in 2023. I've done something quite similar in a proprietary project (I called it "spec-driven development" in reference to "test-driven development").

I would first start by writing the OpenAPI spec and response model JSON schema. I could then write the frontend code, for example, as the API it called on the server was now defined. Only as the last step I would actually integrate the API to real data - this was especially nice as the customer in this particular project was taking their time to deliver the integration points.

All the time during development the API conformity was being verified automatically. It saved me from writing a bunch of boilerplate tests at least.


The reason why no one does “contract or spec driven development” is that in most real life cases the spec is not known in advance, and it’s very very hard to get the spec right before starting to write a single line of code.

It’s often much more practical to integrate early and then iterate on the implementation and the spec at the same time until reaching a stable point.


thing is - with this setup the spec is the code you iterate it as you would your implementation - it just makes sure that the its guaranteed to be correct.

What I’ve seen so often (and why I implemented this) was that the spec will be written, found insufficient, and the code updated, leaving the spec out of date.

Having to write the spec first allows you to actually iterate on it before implementing the code, with all the server / test client generators. So the frontend team can start working on its end before the backend even implements anything, as most of its test would be done against mocks / fake data generators.

Even better, since the spec is a source of truth for soo many things - validation, client test requests, server test responses, docs, as well as the paths / endpoints in both client and server implementation, it saves an enormous amount of time and communication energy to have it be implemented in one place.


FWIW, there are a few companies cropping up now doing better codegen for client libraries. I'm starting one of them: https://stainlessapi.com

Unfortunately we don't yet have a "try now" button, and our codegen is still closed-source, but you can see some of the libraries we've generated for companies like Modern Treasury and sign up for the waitlist on our homepage.

Always happy to chat codegen over email etc.


CTO of Modern Treasury here. We're very happy with the quality of the client libraries being generated by Stainless. It also integrates nicely into our workflow, we've got the releases almost fully automated whenever new API routes are added or changed.


I'm looking for a codegen tool for client SDKs for my product, would love to use your product. My email is in my profile, if you want to chat.


Sad to see it isn't just me. I had very real vibes of "surely I'm holding this wrong" in my building an OpenAPI file. And you didn't even mention tools to help deploy, just to help make a client.

To add my difficulty, the document generation inside Sphinx was less than up to date. Such that I didn't even get the pretty docs.


The Java generator is pretty good, many big companies are using it for generating both client and server code, I'm especially happy with the Java Spring Boot generator, I've been using it for both reactive and 'standard' code generation.


I am using the 'spring' generator and it works fine. Just fine. Could be better if it would buse more Spring features.

It saves hours and hours of development time. And the ability to regenerate the whole application on spec changes is amazing.


I'm sorry, but you have completely misunderstood the purpose of Open API.

It is not a specification to define your business logic classes and objects -- either client or server side. Its goal is to define the interface of an API, and to provide a single source of truth that requests and responses can be validated against. It contains everything you need to know to make requests to an API; code generation is nice to have (and I use it myself, but mainly on the server side, for routing and validation), but not something required or expected from OpenAPI

For what it's worth, my personal preferred workflow to build an API is as follows:

1. Build the OpenAPI spec first. A smaller spec could easily be done by hand, but I prefer using a design tool like Stoplight [0]; it has the best Web-based OpenAPI (and JSON Schema) editor I have encountered, and integrates with git nearly flawlessly.

2. Use an automated tool to generate the API code implementation. Again, a static generation tool such as datamodel-code-generator [1] (which generates Pydantic models) would suffice, but for Python I prefer the dynamic request routing and validation provided by pyapi-server [2].

3. Finally, I use automated testing tools such as schemathesis [3] to test the implementation against the specification.

[0] https://stoplight.io/

[1] https://koxudaxi.github.io/datamodel-code-generator/

[2] https://pyapi-server.readthedocs.io

[3] https://schemathesis.readthedocs.io


To your first point - you may think it detracts from perceived value, but you can just write your own code generator for openapi - it's not that hard, and you'll probably end up with a higher quality client that more fits your preferred pattern better.

This is still a win because you can still generate all your clients in sync with your API spec rather than doing all that manually.


> For me one of the biggest selling points is client code gen. Basically it sucks

I agree that the official codegen is not that great. One of my former colleagues started guardrail[0] to offer better client -- and server -- codegen in Scala for a few different http/rest frameworks. Later, I added support for Java and some Java frameworks. (I haven't worked on the project in over a year, but from what I understand, it's still moving forward.)

Obviously that's a fairly limited set of languages and frameworks compared to what the official generators offer, and there are some OpenAPI features that it doesn't support, but guardrail is a good alternative if you're a Java or Scala developer.

> JSONSchema is too limited

I've run into some of the problems you've described, which can be a big bummer. For new APIs I'd designed, I took the approach of designing the API in a way that I knew I could express in OpenAPI without too much trouble, using only the features I knew guardrail supported well (or features I knew I could add support for without too much trouble). It's not really the ideal way to design an API, but after years of that sort of work, I realized one of the worst parts of building APIs is the tedious and error-prone process of building server routes or a client for it, and I wanted to optimize away as much of that as possible.

Ultimately my view is that if you are writing API clients and servers by hand, you're doing it wrong. Even if you end up writing your own bespoke API definition format and your own code generators, that's still better than doing it manually. Obviously, if something like OpenAPI meets your needs, that's great. And even if you don't like the output of the existing code generators, you can still write your own; there are a bunch of parser libraries for the format that will make things a lot easier, and it really isn't that difficult to do, especially if you pare your feature support down to the specifics of what you need.

[0] https://guardrail.dev


I think OpenAPI needs to step up its game with its code generators, because that too has been an issue for me; I've seen a few issues pop up over time.

It's only useful for generating types; most generators' APIs are stubs at best, which means it's pretty much useless for evolving API specifications.

JSON has its limitations, in that its type system is different enough from other languages that back-end generated code often feels awkward.

I think that the foundation should take ownership of the generators and come up with a testing, validation & certification system. Have them write a standardized test suite that can validate a generated client, making sure there's a checklist of features (e.g. more advanced constructs like `oneOf` with a discriminator, enums, things like that).

And they should reduce the number of generators. Have one lead generator for types, then maybe a number of variants depending on what client the user wants to use. But those could be options / flags on the generator.

Of course, taking a step back, maybe OpenAPI and by extension REST/JSON is a flawed premise to begin with; comparing it with e.g. grpc or graphql, those two are fully integrated systems, where the spec and protocol and implementation are much more tightly bound. The lack of tight bounds (or strict standards for that matter) is an issue with REST/JSON/OpenAPI.


I agree that codegen + docs is actually where most of the value is. The problem I think is in the design. Having an intermediate spec makes all the downstream tooling for codegen + docs need to handle all the complexity. Any information lost (because the spec is in sufficient for whatever use case), you end up with a worst of both worlds situation, your code or docs gen tooling is less direct to use, and now is missing context.

Another way of handling this is getting the server your are interacting with to be able to generate the code directly based on their own internal knowledge of how the APIs are put together. This puts more onus on the library creators to support languages etc, but provides a much better experience and better chance things will 'just work' as there are just less moving parts.

ServiceStack is a .NET library that does this with 'Add ServiceStack Reference'[0] which enables a direct generation of Request and Response DTOs with the APIs for the specific server you are integrating with. IDE integration is straight forward since pulling the generated code is just another web service call. Additional language generation are integrated directly. It had trade offs but I'm yet to see a better dev experience.

[0] https://servicestack.net/add-servicestack-reference

(Disclaimer I work for ServiceStack).


I find the code gen less valuable than having a machine-readable spec that I can test against.


It's always nice to read and know I am not an opinionated asshole, and other people share the misery. I admit I've been duped using OpenAPI. Generating the schema via FastAPI and Nest.js works pretty well. But like you we have been sorely disappointment by the codegen.

Anyone care to suggest alternatives though, assuming we want to call from node to python? I actually believe that having api packages with types is one of the only things startups should take from the enterprise world. I thought about GRPC, I had good experience with it as a developer, but the previous company had a team of people dedicated just to help with the tooling around GRPC and Protobufs.

So I picked OpenAPI, figuring simple is better, and plaintext over http is simpler. and currently I do believe it's better than nothing, but not by much. I am actually in the process of trying to write my own codegen and seeing how far I can get with it.

are protobuf's with GRPC really the way to go nowadays? should a startup of 20 developers just give up and document api in some shared knowledge base and that's it?


NSwag does a wonderful job of generating TypeScript clients from OpenAPI specs. Definitely give it a shot before killing your current setup.

https://github.com/RicoSuter/NSwag (It sucks in any OpenAPI yml, not just ones from Swashbuckle/C#)


@sthuck I'm working on an alternative in this space called Fern. Like gRPC, you define your schema and use it to generate client libraries + server code. Fern integrates with FastAPI/Express/Spring and generates clients in Python, Typescript, and Java.

Checkout out this demo: https://www.loom.com/share/42de542022de4e55a1349383c7a465eb. Feel free to join our discord as well: https://discord.com/invite/JkkXumPzcG.


Yeah I had this experience too. I figured at least there'd be static checking that would at least make sure we aren't going off spec but there isn't really. So you just have a spec that slowly becomes out of sync with the code until it's basically useless. Just seems like double work for almost no benefit.


It depends on the tools you use. You can use tester proxies that validate all requests and responses to the specs, or you can do server code gen (with interfaces/Subclasses for example in Java) so you are forced to adhere to the specs.


I actually got the OpenAPI docgen magic to work 100% all the way into Azure API Management Service such that our branded portal's docs were being updated based upon code comments each time upon merge. It really is something to marvel at. It actually worked.

That said, I didn't like the amount of moving pieces, annotation soup in code, etc. I got rid of all of it. Instead of relying on a fancy developer web portal with automagically updating docs, I am maintaining demo integration projects in repositories our vendors will have access to. I feel like this will break a hell of a lot less over time and would be more flexible with regard to human factors. Troubleshooting OpenAPI tooling is not something I want myself or my team worrying about right now.


Good to know. I'd like to learn about the process you had set up and the number of moving pieces it required. Have you written about this process? Can I read about it somewhere?


1) hits home. The lack of a proper AST, "logicless" Mustache templates for code generation, lack of tests,... Also, OpenAPI seems to allow features in the language before at least a handfull of first class code generators have support for that feature, just because one generator supports it. And not that the others refuse, they just produce broken code


As for point 1) I fully agree. I'm using it a lot currently due to lack of alternatives, mainly with java. Swagger codegen is the one I've had most success with, but both openapi and swagger codegen shares the same problems.

For internal projects we use grpc which is a breeze to use in comparison.


I'm certainly not going to be the only one who, confused, read fairly far in before realizing I didn't see the P in OpenAPI.


reminds me of when Snap-On tools had a nice bump in stock price prior to Snapchat IPO


You are definitely not the only one. It happened to me too. xD


OpenAI's plugins are based on OpenAPI.


The https://github.com/OAI/ Github group name is indeed deceptive.


I wonder if it was just a matter of them getting that GitHub handle way before OpenAI was a real thing.

Update: per Wikipedia, looks like OpenAPI was founded in 2010-11 so that would make sense https://en.wikipedia.org/wiki/OpenAPI_Specification



you are not to be honest, and I work with Swagger APIs every day…


I mean, chatgpt does a decent job of working with openapi docs.


yes, I can confirm this.


I just wish they'd stop using map keys. Use arrays:

    paths:
      - name: "speakers"
        requests:
          - name: createSpeaker
            method: post
This structure would have allowed adding request name to the schema without breaking everything.

This really goes for anyone building REST/JSON APIs. Please avoid dynamic keys; whatever you think the "primary key" is today, it may be different tomorrow. Clients can easily hash an array of objects into a map if they need it.


Why not accept map keys as nullable similar to what non-required fields in protobuf do? Wouldn't arrays open you up to duplication?

More broadly, I'm interested in sparse field updates vs. full payload updates and how each of these handle nullable / emptyable fields. I haven't seen any protocol or standard handle these well.


Allow me to introduce you to RFC6902[1]. A standard of how to update without sending the whole thing. There are libraries for almost every language as well.

[1]: https://datatracker.ietf.org/doc/html/rfc6902/


One of the Moonwalk discussions is indeed about moving from objects to arrays for many structures: https://github.com/OAI/moonwalk/discussions/32

Also, I agree with the person who mentioned JSON Patch (RFC 6902), which I feel is an under-rated and underused technology. While less intuitive than JSON Merge Patch (RFC 7396), it is far more powerful. I have used both together, using JSON Merge Patch where possible to keep things more readable and intuitive, and using JSON Patch where JSON Merge Patch can't do what is needed. Although if most of your changes need JSON Patch, I find it's better to just stick with that.


Hard not to have major WSDL flashbacks in the OpenAPI project I have running right now. Between the lack of support for the latest OpenAPI to generated documentation in Sphinx, custom attributes needed for AWS API Gateway deployment, and the general grossness of adding the OPTIONS requests for CORS access, nothing has worked as easily as I would have thought it would. Especially given so much of the hype.

Worse, too many of the client generation libraries all look to be abandoned. With no real indication for me to know which would have a good future.


I consume WSDLs and produce OpenAPI very regularly and you're very right that we've reinvented the wheel. On the bright side, REST APIs are much easier to work with ad hoc and Open API (not sure if this is really because of the format or we just care more now) often has better associated docs.


The single dumbest thing we on a team did on a project I used to work on was use the AWS API Gateway. I have my problems with OpenAPI itself, but API Gateway itself is a half-assed mess. If we'd been able to wait a little longer, the lambda serving API requests could've just gotten the HTTP requests directly without that useless heap getting in the way.


This sounds surprising to me. Do you have a link that goes over the problems?


It's a shame about the tooling. It seems like maybe lack of corporate sponsorship is a problem. I know that many companies use open API internally, but of course are never willing to actually contribute or fund the tools that they depend on.


Just looking at all of the companies in this post that are chiming in to say they are helping the tooling, I think there is no lack of effort. I agree that having a big sponsor would help clarify direction.


Since there's a lot of show and tell going on, I'll jump in too I suppose.

I work on a tool in this space called TypeSpec (aka.ms/typespec) that aims to address some of the authoring concerns folks have with OpenAPI. We're a language that feels a lot like TypeScript, with support for high-level features you might be used to in a more typical PL, but compiles to high quality OpenAPI 3.0 you can feed into your existing code/docs generation pipeline. You can see this in action on our playground: https://cadlplayground.z22.web.core.windows.net. We also support protobuf and (once my PR gets merged) JSON Schema targets.

We're not yet to beta (obviously, no website even) but we're hoping to get there relatively soon. Happy to hear any thoughts, especially from folks using OpenAPI.


I looked through the docs and now I have a question! It seems like part of the advantage here is being able to represent things in the spec that OpenAPI might have a hard time with. For example, a ResultsPage<T> template represents structure that's shared across a bunch of paginated endpoints regardless of the type of the items. In OpenAPI, each of those responses has to get its own type (ResultsPageA, ResultsPageB, etc.), and presumably in the generated OpenAPI spec, the fact of that shared structure must be lost, and therefore cannot be picked up by client generators that work on the OpenAPI spec.

How do you think about the relation to OpenAPI v3 (i.e., setting aside possible improvements in v4) — is the goal of TypeSpec to avoid doing things that are too far afield from what you can represent in OpenAPI, or is the OpenAPI thing more like a bridge to adoption so people can use their existing generators, but in the future you imagine people generating clients from TypeSpec directly?


This is a great question. We think OpenAPI is great and TypeSpec is a great way to write OpenAPI, but OpenAPI has some challenges generating high quality, language ideomatic code for complex services. Generating code straight from TypeSpec can drive better codegen in some cases such as the one you mention, especially when combined with custom libraries and emitters. Incidentally, this is how we are creating many client libraries for Azure services.

That said, these are not opposing choices really, or a bridge to anything. OpenAPI works great for probably most http services, has a huge ecosystem, and enjoys wide support across the industry so I'd expect many folks to continue to leverage our OpenAPI emitter to take advantage of that.

In general we don't limit ourselves to things which can be trivially compiled to OpenAPI but try to be super general purpose. We support protobuf and intend to support more protocols going forward, and also have experimented with generating other things like JSON RPC, ORMs, db migrations, etc.


This is great. After a couple of years fighting OpenAPI in various ways, I can definitely see the case for giving the spec its own proper language that’s not JSON. Seems inspired by GraphQL’s really nice specs (IMO the only nice thing about GraphQL).


Thank you! We take most of our inspiration from TypeScript and sometimes C#, but I agree that gql demonstrates the value of terse, highly readable specs quite nicely.


Much or some OpenAPI tooling has not even moved past OpenAPI 2.0 some even refusing and saying that they will not update to Swagger 3.0 [0] and others have issues open since some 2019 and still open with no resolution in sight (because these are individuals doing out of passion and the spec is complex to implement) and yet we have Open API spec 4.0

All this is - trying to do RPC over HTTP in a fashion that was deemed virtuous in some doctoral thesis.

I wish there were better alternatives for RPC that work everywhere including browsers.

EDIT: typos

[0]https://github.com/go-swagger/go-swagger/issues/1122#issueco...

[1]https://github.com/swaggo/swag/issues/386


OAS 3.0 is pretty well-supported by now. One of the biggest lags was Swagger, and they now support 3.0 and are finally making progress on 3.1.

One factor in 3.1 support is that it came out more-or-less concurrently with JSON Schema draft 2020-12, and depends on it. 2020-12 support has recently become more common across more languages, and we're seeing 3.1 work pick up the pace a bit.

But (from years of experience working on these standards), there is _always_ a lag in adoption. You can't just sit and wait until everyone "catches up" because that won't really shorten the lag to the next major version (OAS 3.1, despite the numbering, had significant enough changes to lag like a major version).

So while I'd agree that it's slower than if there were a clear and well-funded owner of things (which is closer to the situation with AsyncAPI), it's not _unusually_ slow as these things go.


The doctoral thesis does not describe RPC at all. It is a more general description of a request/response pattern for navigation of something like a website, by an agent. I would wager that virtually nobody read the thing, and some of those that actually did drew bad conclusions, e.g. pushing for HATEOAS in their API.


Well I am more optimistic about its usefulness than you, I agree that it's a little ridiculous to announce v4, when v3 was out for over a year before it had decent support from tools like Postman and Swagger UI. There seems to be a disconnect between the people creating the standard and the people implementing it.


The big weak point I've always seen in OpenAPI is that every change in the server needs to be mirrored in the spec. This opens up a lot of surface area for mistakes.

What I really want is a way to generate clients from the server source. I realize that this would require a highly opinionated web server with strong typing on all endpoints, but that just sounds like extra value to me.

Are there any web frameworks that enable generating clients like this, whether through a generated OpenAPI spec or otherwise?


> Are there any web frameworks that enable generating clients like this, whether through a generated OpenAPI spec or otherwise?

I think perhaps you just never realized this has been common practice for a long time...

There are lots and lots of web service frameworks that do that: FastAPI in Python, Spring in Java, Play in Scala (iheartradio/play-swagger), rocket/okapi in Rust, many many more. You just need some introspection it's not a difficult thing to do.


I'm trying to go in this direction with an API I'm building at the moment in PHP: https://github.com/smolblog/smolblog-core/tree/feature/api-b... It uses a combination of definition-in-code (also used to translate the endpoint classes to the outside framework), reflection, and PHP annotations to generate the OpenAPI spec which I'm loading into Swagger to do testing.


Plenty of frameworks let you generate the spec from your server code. Nest.js is one off the top of my head. Generate the spec from your server code, version it in-repo, and write a test to run in CI that makes sure the spec is up to date with the code.


Something like:

https://ts-rest.com/

or https://github.com/sukovanej/effect-http ?

there are several others in TS world.


We're using tapir (https://tapir.softwaremill.com/en/latest/), and are pretty happy with it.


Django Rest Framework + drf-spectacular. It needs a couple tweaks here and there but it's great.

Apparently django-ninja (a different REST framework for Django) also generates an OpenAPI spec but I haven't tried it.


I've also had success with drf + drf-spectacular and then using the output OpenAPI spec to generate a typescript-react client with a third-party code generator.

It mostly just works, like you said, and almost acts as a framework guardrail: if the inferred client types are comprehensive and unsurprising then the view tends to be concise; a wonky type indicates there may be something nonstandard in the view that could be fixed by cleaner framework-abiding code.


There are various tools that will do some of this, utoipa [1] for rust and play-swagger [2] for scala + play that I've used in the past and enjoyed. They generate a significant portion of your spec for you, then a client can be generated from the spec.

[1] https://github.com/juhaku/utoipa

[2] https://github.com/iheartradio/play-swagger


I suspect OpenAPI advocates would argue you should start with the spec and use it to generate both the client and server. This is already a common pattern in other RPC definition languages such as gRPC. You _could_ write a server to match the gRPC spec, but why would you?


That works great if you're starting from scratch, but not so much if you're on a brownfield project. The way the generators are written, even generating a new endpoint can't be done after code has been written because it generates a whole file with route stubs.


Agreed, but if you’re asking for a solution that will generate a spec from your code, the more proven path is to generate code from a spec. Gives you more and costs less.

In my opinion the problem is that there’s some APIs that are impossible to represent with OpenAPI — that’s the real challenge they should be solving with this version, not reducing spec line count.


Not sure if I’m an advocate, but definitely a fan. I use frameworks (e.g., Django REST Framework, Nest.js) to build the server and generate my OpenAPI spec. I find it faster than writing YAML/JSON manually, and I end up with a half-working server at the end of it all.


It depends on your use case. Starting with the spec can unblock other implementers, so that they can work with mocks while you build the implementation. And it can help prevent re-work by describing the API first and getting feedback.

Bigger orgs also have style guides for public APIs and you can use various linters/standardization tools to enforce this. Tech writers can work on the API documentation without making changes in your code. There are tools that can tell you if your spec changes would cause breaking changes to API clients, such as adding a required query parameter.

You might not need these things on your project, but for some users it makes sense to write the spec first.


I’m familiar with all that. I worked at Stripe, where I started with a skeleton server first.

My point is, when I work with a framework that generates an OpenAPI spec, I find it faster to generate the spec from a prototype server than to write the spec by hand.


In addition to the many other solutions mentioned, Cloudflare can export an OpenAPI spec from the proxied traffic.

Optic/UseOptic does a similar traffic watch and spec export from local builds.


While I have many thoughts about OpenAPI's ease-of-use and readability, I'm going to focus my commentary on the proposal at hand.

1. "The primary goal of this proposal for a major new version of OpenAPI is to make it more approachable in order." -> This is a sound objective. I'm glad to see less nested structures that will improve readability. It'll make it easier to scroll the JSON/YAML and follow the logic.

2. "OpenAPI has become the defacto standard for API descriptions." -> With OpenAI's choice to pick OpenAPI as the standard for ChatGPT plugins, this is more true than ever. It's great to see that now giving names to responses will make it easier for AIs (i.e., ChatGPT, Copilot) to call an API more accurately.

3. No mention of improving the quality of codegen (e.g., client libs, server stubs). Surprised that Moonwalk is silent on this topic.


If you dig through enough of the discussions, you will definitely see talk around code gen. There's more discussions happening in the background that haven't really percolated out to the moonwalk repo because it's all pretty hand-wavey right now. My intention, when advocating for OpenAPI 3.1 to adopt JSON Schema 2020-12, which brings custom vocabulary support (which I led the design of for JSON Schema), was for additional vocabularies to improve code generation semantics. This has not really happened (for a variety of reasons including that vocabularies weren't quite done and I ended up unable to follow up on the whole thing for several years).

It's not entirely clear to me where things go from here, but I suspect Moonwalk will address it in some way. I'd like to focus on it some (from the OpenAPI perspective more than JSON Schema, specifically) but I haven't found anyone who would sponsor that work (I guess the dollars are flowing more to these alternatives several folks have mentioned)


Every time I try to use an OpenAPI document to generate client code, it fails, I talk to the customer and they say "oh no don't do that, it's not meant for generating code from". Not an indictment on OpenAPI but it's truly bizarre how people use it.


I’m working with a spec that used GUIDs for their operation IDs. This limits TypeScript code generation to typescript-node, which prepends an underscore on the method names. Otherwise, those starting with numbers would be invalid.


This annoys me so much. Like, just use array-style accesses in the code generator?


Yes, but also generate a spec with meaningful operationIds. “getLabels” is much more useful that “529ab782”.


I was mostly thinking about 'in' and other kinds of language keywords that get prepended with underscores and stuff.


> A side effect of giving names to requests and responses is that it makes the predictions from AIs like GitHub Copilot significantly more effective.

Hmm first time I see an api try to cator to AI tools rather than the other way around, feels like we’ve turned a corner for AI tools. Wonder what will happen when we start to design code / libraries / languages with this in mind.

I have a feeling there will be a “designed for ai” language that is going to sweep our industry, maybe turn the languages of today in the same place as assembly/forth - nice for some specific applications, but not mainstream…


I’ve thought of this as well. Maybe even inline assembly which might actually be something like JS/python/rust. It might look like inline SQL does now.


Could you give an example of how this would work with an API? Trying to understand what you mean


What API? This would be a new programming language!


I don’t think a new spec is going to make it easier for more teams to use OpenAPI. This isn’t the problem…

What we really need is better tooling to help developers maintain the spec and built generators on top of it.

I’ve been building open source API version control tools built on top of OpenAPI. It’s an easy way to keep your spec up-to-date just by looking at test traffic. If it detects a diff, it will update the OpenAPI sort of like a snapshot test. https://www.useoptic.com/cli


Maybe its just me, but I'd always pick gRPC, a lot less headaches than the community (un)maintained codegen for some random language.


Contrary to some others experience here I've had good results writing OpenAPI YAML and generating server stubs in Spring. Because it's generating strongly typed code we get a lot of guarantees that the docs match the implementation. For working with frontend devs it's a huge win over the lossy communication of word-of-mouth API docs.

It is definitely verbose to write and Moonwalk would help. Co-pilot helps a huge amount, but I do crave a DSL that's not indentation based.


Few folks in here are (rightly) frustrated with the code generation story and broader tooling support around the OpenAPI standard. I've found a few alternative approaches quite nice to work with:

- Use a DSL to describe your service and have it spit out the OpenAPI spec as well as server stubs. In other words, I wouldn't bother writing OpenAPI directly - it's an artifact that is generated at build time. As a Go user, I quite like Goa (https://goa.design/) but there are others shared in here like TypeSpec.

- There are situations where sticking a backend-for-frontend (BFF) in front of APIs can yield great productivity boosts. For example, in the past we built a thin GraphQL proxy that calls out to a poorly structured REST API. Integrating with that was much more convenient. Most recently, I've been playing with a BFF built with tRPC (https://trpc.io/) which calls out to a REST API. It seemed to provide an even better experience if you use TypeScript on the front-end and in the BFF. It does not have a codegen step and I was really pleased with how fast I could iterate with it - granted it was a toy project.


The projects I work on generate OpenAPI docs at runtime based on annotations in the server source code, so they're always guaranteed to be in sync with the actual API. We've had to add some custom logic to clean things up a bit (e.g., in places where we have custom JSON serialization logic) but luckily the library we're using has hooks for that purpose and it hasn't been a huge pain point.

But like others have said, the client code generators leave a lot to be desired. For example, I have yet to find one that properly deals with recursive data structures like an arbitrarily-nested tree structure with multiple node types. Several of them just flat-out crash, and the ones that don't generate code that won't compile or that bombs out. We've had to resort to hacks like tagging the recursive structures' descriptions with magic keywords that trigger a postprocessing step to fix up the generated code.

But I don't really view this as a problem with OpenAPI per se. The data structures in question can be correctly and unambiguously described in the OpenAPI JSON document.


> In this simple example, the moonwalk version has 20% less lines and one less level of indentation.

It doesn't sounds like a notable change given a lot of OpenAPI specs are generated and not necessarily read by humans?


Agreed. I'm still using 2.0. I don't write the JSON directly (except for the JSON Schema part), nor do I look at it directly. These major backwards-incompatible changes don't seem like the right move to me, they fragment the tooling and make it difficult for a given library to support multiple versions.

This is almost like calling JSON as XML 2.0.


One of the gripes I have about OpenAPI is that it has a very low signal-to-noise ratio. It was bad in JSON, it's just as bad in YAML, with an added whitespace pedantry.

It's great to see a number of alternatives listed in this thread - there's much more active development in this space then I was aware of, and I hope that some of it gets upstreamed back into OpenAPI.

I'll shamelessly plug our tool in this space - Taxi (https://github.com/taxilang/taxilang), which has a dedicated DSL (not YAML) you can either use standalone, or embeddedd within OpenAPI.

I also happen to think that (for internal teams at least), generating clients on ${apiSpec} is a form of tight coupling, where producer and consumer become tied together. If you can avoid it, you should, as it allows producers and consumers to stay loosely coupled and evolve independetly without the gymnastics of avoiding breaking changes.

I've talked about this before, with proposed solutions.[0]

[0]https://orbitalhq.com/blog/2023-01-16-using-semantic-metadat...


OpenAPI triggers me so much... It's so painful to use.


My experience has been the opposite: I've much much much preferred it over the tedium and error-prone-ness of manually writing API clients and server routes.


I feel like this line in the Moonwalk proposal was written for you! "Deep nesting can become unnecessarily cumbersome for reading and writing OpenAPI descriptions."


of course im glad they are putting in efforts to improve it though :)


I've found OpenAPI to be fine to work with until you start trying to do really silly things with query parameters or multipart bodies, etc.

I can understand why OpenAPI has those issues though - it is because OpenAPI is aiming to DOCUMENT APIs rather than SPECIFY them. That is a hard task given how wide a set of things you can do with HTTP.

So be charitable when comparing OpenAPI to XYZ API specification tool.


Doing an API-first approach - which I recommend -

a) involves an incredible amount of DRY in the specs (to the extend we tinkered with a DSL to generate the openapi which feels wrong) b) doesn't have very good ways of splitting large files up and c) is YAML which is horrible. (Yes, JSON too, but that's even worse for authoring).

I can see if you're trying to describe an existing API with OpenAPI there are enhancements here which you will welcome.

If you're using OpenAPI to develop new APIs, I've come to the conclusion of "don't. Use GraphQL". After initially worrying about over-fetching and N+1 stuff, and thinking "yeah GraphQL for the front end, but the serious stuff should be OpenAPI" I've ditched that. GQL Federation was the final nail; it /does/ force some conversations up the chain (how exactly ought two, supposedly completely independent APIs, federate) but in practice this is a useful attribute.


I have a question: how do these systems handle webhooks ? Do they generate event handlers too ? I'm asking this because notions like "quality of service" are essential when you're dealing with the semantically asynchronous parts of an API. With MQTT you can chose between QOS 0 (at most one, this is fire and forget HTTP events, very bad), QOS1 (at least once) and QOS2 (exactly once). This imply coding some kind of broker that will track the state of the communication and carry it to its completion.


I was always a big proponent of openAPI. But the reality is: the client generators are often times lacking, spewing out shitty code with ages old dependencies. You sometimes have to make weird mental acrobatics to get your API reality modelled.

Then, not directly related, you have the problem of each service having to have their own client. Maintenance doubles.

We're going down the graphQL federation with "one graph" for backend services path now. Surely not a holy grail but way better than openAPI.


I recently stumbled upon ts-rest which is a contract library, you create a with subcontracts from which you can derive clients which each have their methods, I personally think it's easier and less work that generating clients methods

Sorry if that's not very clear, better read : https://ts-rest.com/docs/intro

Also, it integrates well with OpenAPI to document the API

I am using it between NestJs and SvelteKit and it's great


Having full support for the uriTemplates makes reverse mapping impossible, so I suspect adoption of the proposal in the API gateways will be close to 0


There are ways that URI Templates could be disambiguated for reverse mapping- that would be a discussion worth opening on the Moonwalk repo.


My biggest pain point is the fact that OpenAPI uses YAML. They always demo it with the simple short examples but soon as you go above a handful of endpoints the YAML will be just horrible to maintain. This is not my only pain point with OpenAPI but it's definitely my biggest. I'd rather use something else and then generate out OpenAPI specs


You can write it in JSON, you know. Not even "JSON as a subset of YAML" but actual JSON. The proposed media types are application/openapi+yaml and application/openapi+json


I evidently need to put this reply in a hotkey or something, because it comes up every time someone rants about yaml, but if you hate yaml so much then write it in json as yaml is a superset of json


OpenAPI Technical Steering Committee (TSC) member and OAS Community Manager here. Happy to answer or redirect all questions related to Moonwalk / OpenAPI v4.


    pathResponses:
      notFound:
        status: 404
        contentType: application/http-problem
    apiResponses:
      serverError:
        status: 5XX
        contentType: application/http-problem

Can't stuff like this be implicit rather than needing to be defined? Or, to say it another way, we're building this over HTTP, which already defines these things and many others.


It’s explicit in the responses you should expect for a given request, versus what you should expect. For example if the specification defined that a 404 is a valid use case then null or empty list is not considered an exception, but if it isn’t defined in the spec and you receive a 404 unexpectedly, then you can treat it as an exception rather than a valid response.


Exactly. Also you want to be able to give, for instance, 400s a body that's JSON schema'd


Ugh, or try having a mostly common response with just a slight mutation (eg the data is array of Company rather than Contact). Verbose for what could be a "mixing" or "sub-class" or something.


OpenAPI does support "subclassing" via allOf and oneOf.


This way you can provide a schema for the error such that a client can parse the response. It makes sense for an API schema to include it.


This. And it may not be immediately obvious if you’re not familiar with RFC 7807, but in the example the responses’ content types specify their schema.


We follow the Moonwalk project in WireMock, because the new features clearly provide some opportunities for better API integration testing and request/response validation that us now embedded in WireMock 3 Beta.

Our TL;DR: the standard looks interesting, the developer tools need a lot of love. The whole world is using JSON/YAML these days, but developer experience for JSON Schema is lightyears behind "legacy" XSD


I'll repeat a relevant bit from an earlier reply of mine:

The ideal system, to me (speaking as the most prolific contributor to JSON Schema drafts-07 through 2020-12), would have clearly defined code generation and runtime validation features that did not get in each other's way. Keywords like "anyOf" and "not" are very useful for runtime validation but should be excluded from type definition / code generation semantics.

This would also help balance the needs of strongly typed languages vs dynamically typed languages.

The fundamental problem is that JSON Schema was designed as a constraint validation system (https://modern-json-schema.com/json-schema-is-a-constraint-s...) and it's been overloaded for type definition in ways that don't always make sense. But the JSON Schema alternatives that I've seen go too far in the other direction. There is a lot of value in being able to perform more complex runtime validation in a language-independent way.

There is a balance and clear separation of concerns needed between data definition and runtime validation, although they still should live in the same contract as there is considerable overlap. Now if I could only find someone who wants to fund the design of such a system... :-)


I wish OpenAPI had a stronger mapping to typescript types.


It’s definitely possible, with a (fair) bit of glue code.

In the past, I wrapped io-ts with OpenAPI docgen logic. This worked great: ~every network boundary type was defined once, providing runtime parse/validation and serialization, inferred static types, and API documentation all at once.

Unfortunately I didn’t get permission to open source the solution. But if I ever get bandwidth to build its spiritual successor, I’ll tackle it from the opposite direction: the OpenAPI/JSON Schema specs are very well suited to define the underlying primitives for a zod/io-ts like solution. The great thing about inverting the direction is that it defers “generating” anything to the static type system, ie there’s much less surface area for the runtime and doc schemas to diverge.

It also provides opportunities to enrich static types with more information in a general way (eg “brand” a number with its valid range, or a string as a valid email address). This would allow the benefits of runtime checks at API boundaries to be treated as static checks internally without additional/redundant internal runtime overhead.


I’ve been wanting to write a tool that takes in a open api spec and generates zod/io-ts for a while now but I haven’t had the time. That sounds very useful though unfortunate you can’t open it up!


I’m trying to achieve generator-less mapping from OpenAPI to Typescript types at https://github.com/varanauskas/oatx


Nice! So this goes OpenAPI -> JSON Schema -> typescript?


OpenAPI uses JSONSchema to define object (e.g. request, response body) schemas, so it would be more accurate to say it:

Extracts the JSONSchema based on path+method+response type from OpenAPI and then converts that to typescript


This is a problem I also encountered. I created my own OpenAPI generator with hacks around the AST generation to support a field for specifying the TS type of the Request / Response

If the spec supports a field to specify the type for a component, that would help a lot with static type generation.


Isn't that more a function of the code generator you use, than the specification format itself?


Or let us describe an custom type (GUID/ULID/UUID)


It's possible to use Typescript Class to map to openapi spec.


Do you mean TypeAPI?


I recommend https://solidproject.org/ for both data ownership/control and global machine interoperability.


In this simple example, the moonwalk version has 20% less lines and one less level of indentation.

and no different in understandability.


does it add support for streams?


See https://www.asyncapi.com/ for the equivalent event based spec & tooling.


OpenAPI is so crap, it’s the main driving factor for adopting graphql in our organization. Any time we need to go back and add or change existing non-graphql http apis…pulling teeth is preferable.


Can you say what is so hard so we can know ahead of time the issues before running into them?




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: