[HN Gopher] Show HN: FastOpenAPI - automated docs for many Pytho...
       ___________________________________________________________________
        
       Show HN: FastOpenAPI - automated docs for many Python frameworks
        
       Author : mr_Fatalyst
       Score  : 143 points
       Date   : 2025-03-22 14:10 UTC (1 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | mr_Fatalyst wrote:
       | Hey everyone!
       | 
       | While working on a project that required OpenAPI docs across
       | multiple frameworks, I got tired of maintaining separate
       | solutions. I liked FastAPI's clean and intuitive routing, so I
       | built FastOpenAPI, bringing a similar approach to other Python
       | frameworks (Flask, Sanic, Falcon, Starlette, etc).
       | 
       | It's meant for developers who prefer FastAPI-style routing but
       | need or want to use a different framework.
       | 
       | The project is still evolving, and I'd love any feedback or
       | testing from the community!
        
         | asabla wrote:
         | for someone that comes primarily from a .net background. This
         | looks fantastic!
         | 
         | Just one thing that I tried to find more information about is:
         | are you suppose to rely on the prefix for specifying api
         | version?
         | 
         | Disclaimer: I'm on a phone while writing this, so I just might
         | have missed something obvious
         | 
         | other then that, kudos for releasing this package!
        
           | mr_Fatalyst wrote:
           | In the examples, I used prefixes to demonstrate API
           | versioning, but you're not limited to this approach. Prefixes
           | can be used for general route structuring as well (like
           | grouping entities, etc.), not just for versioning.
           | 
           | Personally, I prefer using router composition for flexible
           | route organization. You can see a clear example of this with
           | Flask here: https://github.com/mr-
           | fatalyst/fastopenapi/tree/master/examp...
           | 
           | In this example, routes are split into routers by entities,
           | which are then grouped into an api_v1 router, and finally,
           | this api_v1 router is added to the main router.
        
         | fjdjshsh wrote:
         | In what context do you need to maintain multiple frameworks?
         | 
         | My use case for fastAPI is very specific (we only maintain APIs
         | for ML models), so I'm curious to learn about this.
        
           | odie5533 wrote:
           | Legacy applications built with Flask and modern ones with
           | FastAPI.
        
         | pamelafox wrote:
         | Does the flask extra also support quart?
        
           | pamelafox wrote:
           | And would it document a streaming API? (With transfer-
           | encoding: chunked) The support for that in OpenAPI is still
           | in progress, I believe.
        
             | mr_Fatalyst wrote:
             | Currently, FastOpenAPI doesn't provide built-in support
             | specifically for documenting streaming APIs. As far as I'm
             | aware, support for streaming (chunked responses) in the
             | OpenAPI specification itself is still limited.
        
           | mr_Fatalyst wrote:
           | Yes, Quart is supported.
           | 
           | The full list of frameworks is: Falcon, Flask, Quart, Sanic,
           | Starlette, and Tornado.
           | 
           | Looks like I accidentally missed Quart in some parts of the
           | docs--my bad, apologies! It's included in the examples.
        
             | raylad wrote:
             | Why no Django?
        
               | mr_Fatalyst wrote:
               | How I answered before, I started working on a router for
               | DRF/Django integration, but Django's project structure
               | made it surprisingly tricky to implement cleanly. I keep
               | it in my mind.
        
       | memset wrote:
       | This is really cool - something I've been looking for with Flask.
       | Cleanest implementation with just the decorator that I've seen.
       | 
       | (As an aside, is there an open-source UI for docs that actually
       | looks good - professional quality, or even lets you try out
       | endpoints? All of the decent ones are proprietary nowadays.)
        
         | mr_Fatalyst wrote:
         | Thanks a lot! Glad to hear it fits your needs.
         | 
         | For a clean, documentation UI, the best open-source options
         | right now are probably Swagger UI and ReDoc. FastOpenAPI uses
         | both by default:
         | 
         | - Swagger UI: interactive, lets you try out endpoints live. -
         | ReDoc: more minimalist and professional-looking but static.
         | 
         | If you're looking for something different, you might check out
         | RapiDoc, which is also open-source, modern, customizable, and
         | supports interactive API exploration.
        
         | ddorian43 wrote:
         | Maybe Rapidoc?
        
       | zapnuk wrote:
       | Why not just use fastAPI and have it built into the framework?
        
         | dtkav wrote:
         | It sounded to me like they need to retrofit several projects
         | written in different python servers.
        
         | mr_Fatalyst wrote:
         | Sometimes you simply can't switch frameworks--due to legacy
         | code, project constraints, or team preferences. FastOpenAPI is
         | specifically designed for situations like these: it provides
         | FastAPI-style routing and automated OpenAPI docs without
         | forcing you to change the underlying framework.
         | 
         | P.S. I'd prefer FastAPI as well ;)
        
         | karolinepauls wrote:
         | Because not everyone wants to be a part of the asyncio trend.
         | 
         | Asyncio in Python is a poor feature that splits the language's
         | ecosystem into 2 mutually-incompatible worlds, something Python
         | only gets away with because it's too big to fail.
         | 
         | Meanwhile we've had Gevent for decades now. It gives us async
         | that you can forget you have. Because rather than making code
         | async, it makes the VM async.
         | 
         | Gevent could have been merged into CPython, but they chose
         | explicit "structured concurrency" and the rest is history.
         | History of sometimes moving forward and sometimes straying from
         | the path and getting lost.
         | 
         | And lost Python's asyncio is. PDB, which lots of other
         | debuggers base on, is still broken (cannot use await). The
         | ecosystem? IPython uses asyncio internally so it cannot easily
         | be embedded in a working async program. The only embeddable
         | REPL I was able to find is this: https://github.com/prompt-
         | toolkit/ptpython/blob/master/examp...... actually, it looks
         | like someone is working on adding `await` support to PDB now,
         | years after asyncio's first release.
         | 
         | Overall, lots of churn to get something (maybe) as good as
         | Gevent, which we had in Python 2.7, or even before.
         | 
         | If a similar amount of effort was spent on first-class support
         | for code hot-reloading and live program inspection, we would
         | get a massive boost of productivity. But somehow even otherwise
         | bright people choose to reimplement working solutions into
         | something objectively worse, meanwhile our
         | development/debugging loop still emulates loading punchcards
         | into mainframes.
        
           | ddorian43 wrote:
           | Agree on every word. They'll probably make free threaded
           | shitty too somehow. We'll see.
        
       | dtkav wrote:
       | Nice work! What's your take on spec-first vs. code-first?
       | 
       | I'm a fan of spec-first (i worked on connexion), but I've noticed
       | that code-first seems to be more popular.
        
         | mr_Fatalyst wrote:
         | Thanks! I personally prefer code-first because it aligns well
         | with Python's dynamic nature and feels more natural in daily
         | coding. Spec-first definitely has advantages (especially
         | clarity and collaboration), but it can sometimes introduce
         | friction, especially when rapidly iterating on APIs.
         | 
         | I think the popularity of code-first tools (like FastAPI)
         | mostly comes from the convenience of quickly defining and
         | changing APIs right alongside your code.
        
           | dtkav wrote:
           | Yeah, that's fair. Do you maintain any Public APIs or mostly
           | private ones?
           | 
           | There are a bunch of trade-offs based on your starting point
           | and where you want to get to.
           | 
           | I have found Spec-First is useful for a retrofit and having
           | large org API design standards, but then code first can be
           | helpful again if you are writing a framework to have
           | consistent endpoints by default (like pocketbase's API).
           | 
           | If you're maintaining a private API then it makes sense to
           | optimise for individual developer velocity and code-first
           | seems like a good fit.
        
             | mr_Fatalyst wrote:
             | You're right, I'm mostly maintaining different private
             | APIs. In that context, optimizing for individual developer
             | velocity definitely makes code-first more appealing. But
             | you're spot-on about larger orgs and standards--spec-first
             | can simplify collaboration and consistency in those
             | scenarios.
        
         | RadiozRadioz wrote:
         | Spec-first is my preferred approach these days, but I had to
         | grow into it. It didn't make sense early on until I'd written
         | the same boilerplate 100s of times and realised how much time I
         | was wasting.
         | 
         | The upfront cost is higher than the 10 lines it takes to make a
         | working FastAPI app, but once you're past that it becomes a
         | huge timesaver. It's an investment that pays dividends, so
         | definitely for the patient programmer with a long-term view.
         | Not to mention the automatic improvement in API consistently.
         | 
         | I worry slightly about AI completion generating all the code-
         | first boilerplate before people give spec-first a try. It's the
         | same speedup, but with none of the determinism or
         | standardisation.
        
           | dtkav wrote:
           | For me it was two things:
           | 
           | - collaborative live API design/review with rapid iteration.
           | 
           | - developing automation on openapi specs to help teams avoid
           | making backwards compatibile changes.
           | 
           | It is much easier to catch things in design.
           | 
           | spec-first is probably most useful for large public APIs.
        
         | DanHulton wrote:
         | Just to drop another two cents in here - I feel like code-first
         | is great when it's a solo project or very experimental, but
         | when you're working on a larger team, or more to the point,
         | working with other teams, spec-first is invaluable.
         | 
         | You can publish a working spec long before worrying about any
         | sort of technical implementation, which means you can get
         | feedback from the other teams involved, which can save an
         | immense amount of time. Additionally, the other team can start
         | working from your clear spec sooner, so you unblock them, AND
         | there are all kinds of great mocking tools to fake your api
         | until it's actually done. Oh, and there are libraries that can
         | check your requests/responses in your tests, to ensure you're
         | keeping to the agreed-on spec, so it makes tests more valuable
         | and easier to write, too!
         | 
         | Honestly, even with all that, I wasn't sold on spec first at
         | first because authoring OpenAPI specs SUCKS. It's such a
         | verbose and hard to read and write format. But then I found
         | TypeSpec, and I haven't looked back. I'm converted our existing
         | specs to TypeSpec and they're half the size or less (usually
         | way less). This is easier to write, but critically, easier to
         | read, which makes PRs against a spec a lot more understandable
         | and meaningful.
         | 
         | If you've ever been on the fence about spec-driven development,
         | give TypeSpec a try. It was a real game changer for me.
         | 
         | https://typespec.io/
        
           | dtkav wrote:
           | Cool, I introduced something like typespec at the last
           | company i worked for and it was great. We called it the
           | domain graph and we able to generate entire platform APIs and
           | clients.
           | 
           | I still want to build something that can handle protocol
           | evolution and also do protocol up/down migration on the
           | response (like the stripe API team has done).
        
         | jillesvangurp wrote:
         | I do the opposite and leave generating openapi docs to an LLM.
         | Mostly that just involves spelling out the obvious; so it's not
         | a particularly hard job for an LLM.
         | 
         | The code is the full specification of what a thing does.
         | Anything else is just a watered down version of the thing.
         | 
         | In architecture terms, there is no blue print for the blue
         | print, typically. This is a fundamental misconception some
         | people have about software design vs. traditional
         | engineering/architecture.
         | 
         | When designing buildings, you put all your effort in the blue
         | print. And then you build it. With software, you put all your
         | effort in the blue print (i.e. the source code). And then you
         | run/compile it. In neither case is it valuable to have a meta
         | blue print. At best you might do some sketching, prototyping,
         | modeling. But these are activities intended to learn, not to
         | document. 3D printing makes the metaphor more obvious maybe.
         | Because it makes engineering more similar to software
         | development. All the key work is digital.
        
           | dtkav wrote:
           | I think you might have a fundamental misunderstanding about
           | what OpenAPI specs are for.
           | 
           | If you just need docs then maybe that works for you. OpenAPI
           | can do so much more though - it can specify a protocol.
           | 
           | If you can't see why a protocol specification is different
           | from an implementation of that protocol then I don't know
           | what to tell you.
        
       | Onavo wrote:
       | No love for Django? I am looking for an alternative to DRF and
       | Django-ninja that can optionally generate typed APIs and docs
       | directly from the model definitions.
        
         | mr_Fatalyst wrote:
         | I actually started working on a router for DRF/Django
         | integration, but Django's project structure made it
         | surprisingly tricky to implement cleanly. It's still on my list
         | though.
        
           | scrollaway wrote:
           | I believe django-ninja is as good as it gets for this, to be
           | honest. But I wouldn't try to support DRF. Django Ninja
           | implements its own routing and it's a lot better that way.
        
             | Onavo wrote:
             | Django Ninja isn't particularly well maintained, there have
             | been a few attempts at forking already. Also I think the
             | author of Django Ninja is more concerned about surviving
             | the war right now.
        
           | Onavo wrote:
           | I would suggest having an option for pure Django integration,
           | without DRF.
        
         | jensenbox wrote:
         | Why are you looking for an alternative to Django Ninja? What
         | about it is deficient for you? Curious because I am about to
         | use it.
        
           | mariocesar wrote:
           | Not a technical reason: I've been using Django Ninja to
           | medium/big app with lot of validation logic, and it was a
           | delight. It was easy to start and integrates well with
           | Django, but I'm moving away from it, not because I dislike
           | it, I still like the approach and ergonomics. However, the
           | project seems somewhat abandoned or at least struggling with
           | updates (last release is in August 2024) and with lots of PRs
           | staled. There are forks like django-shinobi
           | https://github.com/pmdevita/django-shinobi that are moving
           | forward and have releases
           | 
           | Right now I'm shifting to FastAPI + Django since much of my
           | logic is already in Pydantic classes, and authentication is
           | token based, so FastAPI mainly is a wrapper for my Django
           | app. Still, it doesn't feel ideal. I would prefer to use
           | django-shinobi, but when I first try to migrate to FastAPI I
           | did it most of the hard stuff in a day
           | 
           | If you're considering options, I recommend giving django-
           | shinobi a try. I hope it gains more traction and involves
           | more maintainers.
        
             | vital1k wrote:
             | Hi mariocesar
             | 
             | Django ninja creator here
             | 
             | The project is used in a lot of critical infrastructure so
             | we are prasing more about stability and performance rather
             | then newest featers
             | 
             | On the other hand we prise all fork and keep an eye on them
             | on the features that seems interesting
             | 
             | BTW next relrase is planned by the end of this month
             | 
             | Cheers
        
               | mariocesar wrote:
               | Im really happy to hear from you and from Django Ninja!
               | 
               | First off, I just want to say how grateful I am for your
               | work. I know how challenging it can be to maintain
               | opensource projects, and I truly appreciate the effort
               | 
               | Wishing you all the best.
               | 
               | This is a bit unrelated, but something thats been on my
               | mind, how are things for you with everything going on in
               | Ukraine? I cant imagine how difficult it must be to deal
               | with such situation while also staying active in open
               | source
        
         | stackskipton wrote:
         | There is already plenty available that will do what you want.
         | FastAPI or Litestar are two popular ones.
        
         | ensignavenger wrote:
         | Django Ninja provides this already for Django, and it is great.
        
           | odie5533 wrote:
           | Docs are a bit lacking still
        
         | sastraxi wrote:
         | DRF-spectacular is an okay choice here, you have to manage
         | consistency with return types yourself but the docs and
         | customization options are well done.
        
       | ltbarcly3 wrote:
       | Every FastApi project I've worked on (more than a few) had an
       | average of less than 1 concurrent request per process. The amount
       | of engineering effort they put into debugging the absolute mess
       | that is async python when it was easily the worst tool for the
       | job is remarkable. If you don't know why it is hilarious that a
       | FastApi project would have less than one concurrent request per
       | process you shouldn't be making technical decisions.
        
         | dtkav wrote:
         | lol what. Did they not use an asgi server? Sounds like it was
         | just misconfigured.
        
           | tempest_ wrote:
           | Honestly it is mostly caused by people from the machine
           | learning end of the ecosystem not understanding how
           | cooperative multitasking works and trying to bolt a web
           | framework to their model.
           | 
           | That coupled with the relative immaturity of the python async
           | ecosystem leads to lots of rough edges. Especially when they
           | deploy these things into heavily abstracted cloud ecosystems
           | like Kubernetes.
           | 
           | FastAPI also trys to help by making it "easy" to run sync
           | code but that too is an abstraction that is not majorly
           | documented and has limitations.
        
             | ltbarcly3 wrote:
             | Everything you say here is true, but if you do an analysis
             | and run benchmarks on non-toy projects you'll quickly find
             | that async Python is a bad choice in virtually every use
             | case. Even for use cases that are extremely IO bound and
             | use almost no compute async python ends up dramatically
             | increasing the variance in your response times and lowering
             | your overall throughput. If you give me an async python
             | solution, I will bet you whatever you want that I can
             | reimplement it using threads, reduce LOC, make it far more
             | debugabble and readable, make it far easier to reason about
             | what the consequences of a given change are for response
             | times, make it resistant to small, seemingly
             | inconsequential code changes causing dramatic, disastrous
             | consequences when deployed, etc etc etc. Plus you won't
             | have a stupid coloring problem with two copies of every
             | function. No more spending entire days trying to figure out
             | why some callback never runs or why it fires twice. Async
             | python is only for people who don't know what they are
             | doing and therefore can't realize how bad their solution is
             | performing, how much more effort they are spending building
             | and debugging vs how much they should have to put into it,
             | and how poorly it performs vs how it could perform.
        
         | acdha wrote:
         | That's completely off topic, and it says more about the team
         | than the tool.
        
           | ltbarcly3 wrote:
           | The topic is generating documentation for FastApi API's
           | right? If someone came and said "here's a great way to
           | prevent over-spray when painting your dog" I think it would
           | be reasonable to take one small step back and just explain
           | that painting your dog is a bad idea.
        
             | acdha wrote:
             | The first line of the linked page says otherwise:
             | 
             | > FastOpenAPI is a library for generating and integrating
             | OpenAPI schemas using Pydantic v2 and various frameworks
             | (Falcon, Flask, Sanic, Starlette, Tornado).
             | 
             | And, no, the analogy to painting dogs isn't valid. I'm sure
             | you're right to say that the projects you worked on did not
             | end well but that single anecdote doesn't invalidate all of
             | the other projects which didn't have that problem, much
             | less the desire other people might want for a similarly-
             | easy experience when using different frameworks.
        
         | supriyo-biswas wrote:
         | I'm not sure about your workload but FastAPI should definitely
         | be able to process more than one request per second assuming
         | that the workload isn't placing a compute bound or synchronous
         | task in the event loop and as long as you're using an ASGI
         | server like Gunicorn for serving requests.
         | 
         | The thing about not marking compute bound or synchronous tasks
         | properly was the cause of a gnarly performance issue with an
         | application at a previous employer, and such mistakes are easy
         | to make -- I'll give you that.
        
       | adhamsalama wrote:
       | Cool!
        
       | bravura wrote:
       | I'm looking for a solution to filter large openapi specs to the
       | most concise complete subset. I've implemented three different
       | variations, two of which appear not to prune enough, and one of
       | which appears to prune too much.
       | 
       | Any recommendations?
        
         | dtkav wrote:
         | Are you trying to prune inaccessible types or something?
         | 
         | I'm not sure what you mean by concise complete subset, but in
         | the past I had good success with custom rules in spectral [0].
         | 
         | [0] https://github.com/stoplightio/spectral
        
           | bravura wrote:
           | The task: I have a massive OpenAPI spec, and I want to drop
           | all operations except for read-only ones. I want to preserve
           | all referenced types, but slim the YAML as much as possible
           | and remove extraneous elements.
           | 
           | I've tried prunes operations while preserving referenced
           | components using redocly.
           | 
           | I've tried openapi-extract CLI to extract only components I
           | reference.
           | 
           | And I've tried openapi-format CLI.
           | 
           | They all give different results, and I can't tell whether I
           | am pruning too much or too little.
           | 
           | And yes I'm using spectral at the end, but it doesn't
           | necessarily show it you're missing something that isn't
           | referenced in the final output.
        
         | servercobra wrote:
         | Interesting, are you trying to automatically create and use
         | components? Or only show certain fields?
        
       | wseqyrku wrote:
       | I like this. I think genai could be used to fill in gaps in, for
       | example, Wikipedia with a note that it's AI generated. If
       | anything I think that's a good starting point.
        
       | JodieBenitez wrote:
       | No Bottle ?
        
       | wg0 wrote:
       | After years of development - Now I prefer declarative approach.
       | Specs first, generate the code from it and implement required
       | Interfaces.
       | 
       | One great too for that is TypeSpec[0].
       | 
       | This also allows thinking about the API first and ensures that
       | what's documented is what's implemented.
       | 
       | [0] https://typespec.io
        
         | monsieurbanana wrote:
         | > Now I prefer declarative approach
         | 
         | Doesn't most people? Until you're no longer in the happy path
         | of whatever you use to generate code.
        
           | wg0 wrote:
           | Nah. Has not happened.
        
         | RainyDayTmrw wrote:
         | Being able to retrofit declarations/specifications to existing
         | code, both for maintaining backwards compatibility and reducing
         | rework, is very valuable, though.
        
         | lvncelot wrote:
         | I'm also really happy with spec first. We're using openapi-
         | generator[1] to generate types from a yaml schema (inverting
         | the more standard approach of generating the yaml) in our
         | Typescript (mostly Nest.js) backends, and export those types as
         | packages for use in our frontends.
         | 
         | [1] https://github.com/OpenAPITools/openapi-generator
        
       | gister123 wrote:
       | Python async has been a big mess. I haven't looked back since
       | moving to a Go + GRPC + Protobuf stack. I would highly recommend
       | it.
        
         | qwertox wrote:
         | I really enjoy Python's asyncio. I'm a big fan of aiohttp and
         | the entire aio* ecosystem.
         | 
         | Then there's Rust's Tokio for the things that need performance.
        
           | linkdd wrote:
           | You should take a look at AnyIO, which unifies asyncio and
           | Trio (it can use both event loops as a backend).
           | 
           | Two big deals of Trio and AnyIO are channels (similar to Go's
           | channels), the ability to return data from starting a task in
           | a nursery/task group:                   async def
           | my_consumer(task_status = anyio.TASK_STATUS_IGNORED):
           | tx, rx = anyio.create_memory_object_stream()
           | task_status.started(tx)                  async for message in
           | rx:                 ...              async def
           | my_producer(tx):             await tx.send("hello")
           | await tx.send("world")             await tx.aclose()
           | async def main():             async with
           | anyio.create_task_group() as tg:                 tx = await
           | tg.start(my_consumer)
           | tg.start_soon(my_producer, tx)
        
         | jt_b wrote:
         | Love Go (and async python, for different reasons) but miss me
         | with the gRPC unless you are building hardened internal large
         | enterprise systems. We adopted it at a late stage startup for a
         | microservices architecture, and the pain is immense.
         | 
         | So many issues with type duplication due to weird footguns
         | around the generated types. Lots of places where we needed to
         | essentially duplicate a model due to the generated types not
         | allowing us to modify or copy parts of a generated type's value
         | and so forth.
        
       | These335 wrote:
       | Love Flask, but this has always been a missing tool. I have a
       | question though - it seems like you're actually modifying the
       | response data type for Flask routes so that it's a Pydantic
       | model. Is that an optional approach? While I wish that were the
       | official standard, if it is not optional then I think that's
       | quite a big ask for maintainers of existing APIs who want to use
       | your docs library. Regardless, I'm looking forward to trying it
       | out! Looks great.
        
         | mr_Fatalyst wrote:
         | Glad you like the idea!
         | 
         | Actually, returning a Pydantic model directly isn't mandatory--
         | it's just a recommended and convenient approach to ensure
         | automatic data validation and documentation.
         | 
         | If you prefer, you can keep your existing route handlers as-is,
         | returning dictionaries or other JSON-serializable objects.
         | FastOpenAPI will handle these just fine. But using Pydantic
         | models provides type safety and cleaner docs out of the box.
        
       | Everdred2dx wrote:
       | Nice. This was one of the main shortcomings in Falcon that pushed
       | me to switch some projects to FastAPI. That said FastAPI had many
       | other benefits that went far beyond API specs.
        
       | odie5533 wrote:
       | Awesome project! It looks so seamless for Flask! Just switch
       | routers, and you model deserialization/serialization, and /docs.
       | Really impressive work!
       | 
       | Is there any way to not need the response_model= and instead
       | infer from return type?
        
         | mr_Fatalyst wrote:
         | Thanks!
         | 
         | Right now, explicitly specifying response_model is required,
         | but only for documentation purposes. Python's type annotations
         | alone aren't sufficient for reliable inference at runtime. I'm
         | considering adding automatic inference support not only for
         | models but also for basic types (like built-in primitives).
        
       ___________________________________________________________________
       (page generated 2025-03-23 23:01 UTC)