[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)