[HN Gopher] Making the Python back end for my new webapp
       ___________________________________________________________________
        
       Making the Python back end for my new webapp
        
       Author : eigenvalue
       Score  : 30 points
       Date   : 2024-10-16 15:08 UTC (7 hours ago)
        
 (HTM) web link (youtubetranscriptoptimizer.com)
 (TXT) w3m dump (youtubetranscriptoptimizer.com)
        
       | bilekas wrote:
       | Is your link working or maybe am I blocked on my network ?
       | 
       | If it's not working, then maybe maybe python the backend wasn't
       | the best idea in the end?
        
         | eigenvalue wrote:
         | It's working for me, and I see lots of traffic coming to it, so
         | it's probably blocked for you. Most likely because it has
         | "youtube" in the url!
        
       | varun_chopra wrote:
       | This post comes at a great time. I've been looking into what the
       | "perfect" stack would be for me (I'm OK with Python but haven't
       | done any frontend work).
       | 
       | Is anyone actually using FastAPI in a commercial, large scale
       | app? Would you prefer using...say Django or Flask + Gevent (since
       | they're more mature) over FastAPI?
       | 
       | I recently found this thread[1] about FastAPI. It's somewhat old
       | now but reviews are mixed. I'm wondering if the landscape has
       | improved now. Additionally, OP is using NextJS for the frontend
       | and even that isn't without complaints[2]. What's odd for me is
       | that the React website also asks you to pick between either
       | Next.js or Remix[3].
       | 
       | [1]
       | https://www.reddit.com/r/Python/comments/y4xuxb/fastapi_stab...
       | 
       | [2]
       | https://www.reddit.com/r/nextjs/comments/1g18xgu/nextjs_is_h...
       | 
       | [3] https://react.dev/learn/start-a-new-react-
       | project#production...
        
         | ruicaridade wrote:
         | Indeed, we use FastAPI in quite a large scale! I would not
         | trade FastAPI for anything else at this point. Before the
         | typing module became ubiquitous there used to be a lot of
         | "magic" frameworks that made heavy use of Python's dynamic
         | nature; both Django and Flask fall within this category: I am
         | not a fan of untyped Python, at all.
         | 
         | There's some gotchas in the way FastAPI works, mostly due to
         | its usage of thread pools and the GIL. I would recommend anyone
         | starting a project to exclusively use asynchronous I/O
         | (SQLAlchemy supports async with asyncpg), as FastAPI is very
         | clearly meant as a pure ASGI framework, despite what they
         | claim.
        
           | nickpadge wrote:
           | How is your experience with async SQLAlchemy with FastAPI?Ive
           | experienced a handful of nasty bugs, specifically around how
           | connection pooling is handled.
        
         | bb88 wrote:
         | Django/DRF are fine for API's particularly with DRF Spectacular
         | to generate the Open API specs. DRF couples tightly to the ORM
         | and plays nicely with the Django DB models.
         | 
         | FastAPI will have more boilerplate, but I'm not sure that's an
         | issue anymore in the age of AI coding assistants.
         | 
         | HTMX is also wonderful for both. It's a nice tech for
         | lightweight SPAs. If you're going to go deeper into the JS side
         | you can look at some of the more mature frameworks. I've been
         | kinda partial to Vue.js.
         | 
         | And if you really want to go crazy there's pyscript from
         | anaconda.
        
           | eigenvalue wrote:
           | FastAPI automatically generates the openapi.json file for
           | you, which is how it's able to also give you the Swagger page
           | "for free" once you've defined the route structure. It's very
           | convenient.
        
         | flakes wrote:
         | Yup, I use FastAPI for some large services, handling a few
         | million requests per day. Great experience overall, and speed
         | of development is significantly improved. You can feel
         | confident something is going to work after writing code. With
         | flask and django I was always second guessing if things are
         | hooked together properly. One pitfall I would avoid though is
         | mixing both sync and asyncio together. Ive found there are a
         | lot of footguns in that type of setup. Use one or the other,
         | but not both
        
           | E_Bfx wrote:
           | Hello, could you elaborate on the footgun with mixing sync
           | and asyncio ? I am currently devellopin one app with both
           | kind of endpoint + websocket and I prefer not discover too
           | late this problems .
        
             | eigenvalue wrote:
             | Basically, you want anything that has any kind of IO
             | (network, disk, etc.) or which is very slow to compute to
             | be fully async. If you have a function that returns almost
             | instantly, like computing the hash of something, you can
             | keep that sync.
             | 
             | If you're forced to use a slower sync function (say,
             | something from a library that you can't easily change),
             | then you can use asyncio.to_thread() so that it can run in
             | a separate thread without blocking your main event loop. If
             | you don't do that, then you sort of defeat the whole
             | purpose of the architecture because everything would stop
             | while you're waiting for that slow sync function to return.
        
             | flakes wrote:
             | I've found that when mixing the two types of routes, it can
             | be quite easy to accidentally introduce blocking paths
             | which freeze up the main event loop, especially if mixing
             | async dependencies with sync ones.
             | 
             | When a route is async, it gets scheduled on the main event
             | loop, meaning that any blocking calls can block all
             | requests in flight, and block unexpected things like start
             | up and teardown of api handlers. `asyncio.to_thread()` can
             | help here, but it's easy to forget (and there's no warnings
             | in case you forget).
             | 
             | If you do mix the two, I would be very careful to monitor
             | the timings of your requests to detect early if blocking is
             | occurring. For adding these metrics, I suggest using
             | something like statsd or open-telemetry libraries for
             | adding reporting to the endpoints, which you can feed into
             | telemetry dashboards.
        
         | turtlebits wrote:
         | I'd start with a pure server side stack like Flask or Django
         | and forego the complexity of front-end JS.
        
       | asplake wrote:
       | Oh, SQLModel [1] looks interesting - hadn't seen that before. For
       | apps with html front ends, are people replacing WTForms?
       | 
       | [1] https://github.com/fastapi/sqlmodel
        
         | eigenvalue wrote:
         | It's such a game changer... I always had the thought before in
         | the back of my mind, "Why do I need to create two versions of
         | every data model that basically specify the same information
         | (field name and type)?" And it turns out, you don't have to do
         | that, you can use the same model for both the ORM and the
         | response validation schema.
        
           | asplake wrote:
           | Right! And the forms too? Got to say though, even if it
           | doesn't do the html generation that WTForms does, it seems
           | the better split.
        
             | eigenvalue wrote:
             | No it doesn't do any forms stuff, but you can easily get
             | the forms using your preferred UI framework from the data
             | model definitions themselves using an LLM.
        
         | Spivak wrote:
         | Make sure you know the limitations of SQLModel before
         | committing to it. It doesn't support polymorphism which was an
         | immediate dq since that ends up being needed in every project.
        
       | daft_pink wrote:
       | I'm really interested in how you got the auth to interoperate
       | between nextjs and python. I find auth to be the most difficult
       | part of making blended code projects with JavaScript on the
       | frontend like this.
        
         | twolf910616 wrote:
         | authn or authz? Authentication is not terrible to build but
         | authorization yeah, I'm totally with you there. It's hard.
        
         | eigenvalue wrote:
         | Well you don't really need to get the auth to interoperate per
         | se; the only machine that is allowed to connect to the FastAPI
         | backend is the machine running the NextJS app, and it passes
         | along the email address of the user making the request to the
         | FastAPI backend.
         | 
         | And the user auth stuff in NextJS is incredibly easy using the
         | standard Next-Auth flow: https://next-auth.js.org/
         | 
         | You basically just set up a new application in the Google Cloud
         | console, enable the Google Plus API for the app, and create the
         | OAuth keys, and that's about it. Just add the secret key and
         | identifier to your .env file for the NextJS app and it "just
         | works".
        
           | daft_pink wrote:
           | So essentially, you only let the server side rendering
           | function, access the API and don't secure it at all beyond
           | that?
           | 
           | You could essentially use a static JWT token that only that
           | nexts cloud function knows?
        
             | eigenvalue wrote:
             | Yeah, I restrict it by the IP address, so the FastAPI
             | backend can only receive connections from localhost or the
             | one machine running the NextJS app. There are certainly
             | lots of ways you could restrict it, such as using a
             | password or key.
        
         | benn0 wrote:
         | I've been doing this with NextAuth and fastapi-nextauth-js
         | [https://github.com/TCatshoek/fastapi-nextauth-jwt]. With JWTs
         | it's pretty straightforward to do something similar for any
         | other auth provider. This is also using NextJS rewrites (see
         | [https://vercel.com/templates/python/nextjs-fastapi-starter]
         | for an example)
        
       | dennisy wrote:
       | Great article!
       | 
       | Bit of an aside, whilst SQLModel and merging the API validation
       | and ORM models is fast, is it a good idea? There could be reasons
       | these two things should grow individually and is it good to put
       | so much logic into external frameworks?
        
         | eigenvalue wrote:
         | Thanks. I don't really see how the validation schema and ORM
         | model would ever really diverge... it's basically just
         | specifying the various fields that are required or expected and
         | the types of those fields. Before I found SQLModel and I was
         | separately using SQLAlchemy ORM and Pydantic, I would always
         | end up with models that more or less looked the same but with
         | just different syntax. And actually keeping them in sync was
         | very annoying, since you would always have to remember to
         | change things in both places. It's very natural to combine
         | them.
         | 
         | The beauty of how tiangolo (creator of FastAPI/SQLModel)
         | implemented things is that an SQLModel class isn't just LIKE a
         | pydantic schema and LIKE an SQLAlchemy ORM data model-- they
         | literally ARE those things under the hood, so you can still use
         | those libraries separately for more advanced tinkering and
         | stuff "just works".
        
           | dennisy wrote:
           | Yeah I had a good read of the concept. I do agree for most
           | CRUD apps there will be no divergence.
           | 
           | My concern is that this breaks layering suggested by most
           | architecture frameworks.
        
       ___________________________________________________________________
       (page generated 2024-10-16 23:00 UTC)