#449: Building UIs in Python with FastUI Transcript
00:00 Building web UIs in Python has always been an interesting proposition.
00:04 On one end, we have the full web design story with artisanal HTML and CSS.
00:09 On the other end, there are several Python platforms that aim to bring RAD, Rapid Application
00:15 Development style of building Python apps to the web.
00:19 Those can be great, and I've covered a couple of them, but they usually reach a limit on
00:23 what you can do or how they integrate with the larger web ecosystem.
00:28 On this episode, we have Samuel Colvin back to share his latest exciting project, Fast
00:33 UI.
00:34 With Fast UI, you can build responsive web applications using React without writing a
00:39 single line of JavaScript or touching NPM.
00:42 Yet designers and other tools can focus on React front ends for a professional spa-like
00:48 app experience.
00:50 This is Talk Python to Me, episode 449, recorded December 14th, 2023.
00:55 Welcome to Talk Python to Me, a weekly podcast on Python.
01:13 This is your host, Michael Kennedy.
01:15 Follow me on Mastodon, where I'm @mkennedy, and follow the podcast using @talkpython,
01:20 both on fosstodon.org.
01:22 Keep up with the show and listen to over seven years of past episodes at talkpython.fm.
01:28 We've started streaming most of our episodes live on YouTube.
01:31 Subscribe to our YouTube channel over at talkpython.fm/youtube to get notified about upcoming shows and be
01:37 part of that episode.
01:40 This episode is sponsored by Bright Data.
01:43 Bright Data is professional web scraping and a dataset marketplace.
01:47 If you need data and it doesn't have an API, check out talkpython.fm/brightdata today.
01:54 And it's brought to you by Sentry.
01:57 Don't let those errors go unnoticed.
01:58 Use Sentry like we do here at Talk Python.
02:01 Sign up at talkpython.fm/sentry.
02:02 Hey, Samuel, welcome back to Talk Python to Me.
02:08 - Thank you.
02:09 Thank you very much for having me again.
02:10 So soon after last time.
02:11 - It's always amazing to have you on.
02:13 In fact, you were on just last week in a really cool show that tons of people enjoyed and
02:20 is not yet out at the time of recording, but will be released to the world by the time
02:24 your show goes out live.
02:25 So it's a bit of a time travel thing.
02:28 Very, very appropriate here.
02:29 But it was under the full-time open source developers panel of like a bunch of folks.
02:35 For example, Charlie Marsh, Will McGugan, Gina Houska, and so on.
02:40 And you snuck in for a minute there on your travels, but now you're back and we're here
02:46 to talk properly about something really excellent that you put together called Fast UI, which
02:52 is gonna be a lot of fun.
02:53 - Yeah, thanks so much for having me.
02:55 And yeah, I'm in a slightly better environment for a podcast than the stairwell of a restaurant
03:02 somewhere in Istanbul.
03:03 So yeah, it's nice to be here.
03:05 - High marks for effort there.
03:06 Come on, that was great.
03:08 - It was good fun, but this is a better place to talk about these things.
03:12 - Yeah, well, I hope you had a good trip and you're back and at it.
03:16 Kim out in the audience points out, "Hey, could you just write another impressive tool
03:18 for the next week's show?
03:20 'Cause things are going pretty prolifically over there." You tell people a bit about Pydantic, the company, they probably heard of the library,
03:27 but just what are you up to these days?
03:29 - So Pydantic's obviously been around since 2017 originally, but then it's like something
03:34 weird happened at the beginning of 2021.
03:36 I don't know quite what that was, but Pydantic, the downloads just went crazy.
03:40 So we were at like 5 million downloads then and we're now at 130 million.
03:44 So yeah, it's gone crazy.
03:46 And then just a bit more than a year ago, I was very lucky.
03:49 Sequoia got in touch with me and basically said that I want to start a company.
03:53 I had been meaning to do that after I released Pydantic V2 that I was then working on.
03:58 Yeah, I started the company beginning of this year and now have an amazing team of 10 people
04:03 working with me.
04:04 So we released Pydantic V2 finally, having originally told people it would take me alone
04:08 three months.
04:09 It took me and I guess then six people a year in total, but that was released back in the
04:14 summer and now we're working on a platform that I'm not going to talk about now, but
04:19 I would love it if you'd have me back, I guess, beginning of Q2.
04:23 - Is that next week or whatever?
04:24 - It's not quite next week.
04:25 - Q2 2024, something like that?
04:26 - Yeah.
04:27 - Okay.
04:28 - I think we're going to try and get to open beta in Q1.
04:32 So yeah.
04:33 - Okay, fantastic.
04:34 Yeah, well.
04:35 - But off the back of, so that without getting into a lot of details on it, has platform
04:40 components to it.
04:41 And so we have people, people will be logging in, et cetera, et cetera.
04:45 And I was just thinking about all of the path and the churn of building the relatively mechanical
04:50 bits of an application again, with, it doesn't matter actually if you're building it with
04:54 React or with one of the other front end frameworks, you end up having a whole bunch of stuff that's
04:58 duplicated between what the front end guys are doing and what the full stack developers
05:03 or the backend developers are building for us.
05:06 And I guess for lots of people, there's a pydantic model that's kind of at the core
05:08 of lots of those bits.
05:10 And I was just dreading all of that churn.
05:12 And I had been wanting to build something like FastUI for a long time, but the fact
05:16 that we're going to be using it internally really spurred me on to go and get it built
05:20 and release it in a very incomplete phase to see what people thought.
05:24 And yeah, there's been a great reaction and here I am.
05:26 - Yeah, there has been quite the reaction to it.
05:29 Let's see, do the GitHub star test.
05:32 It's 2.6 thousand stars and it's what, two weeks old?
05:37 A month old?
05:38 Yeah, a month old.
05:39 Last month anyway.
05:40 - Well, it was only released publicly like, yeah, two weeks, it left them two weeks ago.
05:43 Or maybe two weeks ago today.
05:45 - Oh, that's right.
05:46 Yeah, you probably, so you worked on it a little bit private and then you flipped the
05:49 bit on the public status.
05:50 Yeah, that makes a lot of sense.
05:52 Because you don't want people just to go, "Whoa, what are they building?"
05:55 Maybe you do.
05:56 Maybe you're like, "What is this GitHub repo?" They misspelled FastAPI.
05:59 I don't know what they're working on.
06:01 - Yeah, exactly.
06:02 And also, I mean, we have a team with lots of people who've done lots of open source,
06:06 very strongly opinionated engineers.
06:08 I can't even get my team to use it without kind of proving the value in it.
06:12 So I worked on it a bit without really talking to them and then was like, "Right, I built
06:15 this thing, let's at least give it a try." I don't know, maybe I'm wrong in this, but I think it's quite a fundamentally different
06:23 way of thinking about how you build user interfaces from lots of the tools that exist today in
06:29 the Python ecosystem.
06:30 And so there's a bit of a like education piece and trying to understand the principle as
06:34 well as the like mechanics of going and using it.
06:37 - Yeah, absolutely.
06:38 Well, we're gonna dive into the philosophy, but I'll give people the too long, didn't
06:43 read version.
06:44 Basically, you can create UIs in pure Python in sort of dynamic web framework friendly
06:49 ways, right?
06:51 - Yeah, probably the mistake is in my description of it because yes, it does that.
06:55 But where I personally think FastUI is powerful and where we're using it within the Pydantic
07:01 team is actually, we have got front-end developers, we've got some really expert guys who are
07:06 very comfortable building stuff in React.
07:08 But we want those two roles to have to constantly communicate to build every individual bit.
07:14 So the idea is, I think if you go down the page a little bit, I kind of explained it.
07:18 But like for a Python developer, it's this way of building UIs without having to touch
07:22 TypeScript or JavaScript or NPM or any of those Byzantine like massive build tools.
07:29 But then for a front-end developer, it's this opportunity to go and build the best components
07:32 you can and allow, basically provide a powerful interface for your backend guys to go and
07:38 build a UI with it.
07:40 So kind of split those two things up and I guess allow React to do what React does brilliantly,
07:45 which is provide these like reusable components.
07:47 - Yeah, absolutely.
07:49 Kind of a framework as well to bring the navigation and the cohesion of the whole app together,
07:54 not just a particular view or a page too, you would say, right?
07:57 - Yeah, so the weird bit is principle of RESTful interfaces.
08:01 We've all heard of REST or RESTful and we all think we know what it means, which is
08:03 basically something to do with a URL structure and return me some JSON that like gives me
08:09 the data I need to render my view.
08:11 Well, if you look at the Roy Fielding's original PhD, as is brilliantly described in this HTMX
08:17 article that I talk about further on down here, he's not really talking about that stuff.
08:21 Sure, he has some stuff on what the URL structure should be, but really his principle is that
08:26 the data returned from the backend should be self-describing as if it should have everything
08:32 you need to go and render the user interface.
08:34 So let's say, I think they're using the HTMX example, example of like a bank account.
08:39 And if you go down to like principle, the long version, here we are, right?
08:43 I've linked to the PhD, but more importantly, the HTMX article, which explains it really
08:47 well.
08:48 I think if we follow that, yeah, I think they'll even on that page, there's a very jokey tone
08:52 lots of the time HTMX, but they also have a really cool thing.
08:55 - Yeah, absolutely.
08:56 - Somewhere I think they have, yeah, here we are, right?
08:58 So if you look at the traditional JSON response, which I think is the second one, and you were
09:02 trying to show, yeah, right.
09:03 So this, you and I as humans can read this and be like, yeah, that kind of explains my
09:07 bank account and what's going on.
09:09 But there was not enough-
09:10 - Right, it's got like an account number and a balance, which is a more complicated object,
09:13 nested objects and those types of things.
09:15 - Right, it's got all the things that we can read account number, cool, that's a number
09:18 balance, yeah, that makes sense.
09:20 But if you're a computer, there's not enough there to go and render someone the nice user
09:23 interface they would want where they would have it displayed on a page.
09:26 So if you were the engineering team in the bank trying to turn this into a web interface,
09:33 you then need to go and have lots of very application specific or page specific logic
09:38 to show where the account number goes and where the balance goes and where the status
09:41 goes and stuff like that.
09:42 And that causes enormous amounts of churn and it means that it's particularly difficult
09:46 when you have those engineers working at different time zones because you end up having this
09:50 spec between the two.
09:51 And then you always have this problem with software where, fine, we can get it to work,
09:55 but what happens when we come to add it?
09:57 So what's the process of, let's say we want to show as well on this page, your like joint
10:02 account balance, let's say, just to make something up.
10:04 What we probably need to do is we need to get backend guys to go and add that to end
10:09 point and then the front end and that can be deployed and then the front end can be
10:13 updated to show that and the data is available.
10:15 That is a lots of churn, lots of delay in that.
10:18 Right.
10:19 Lots of coordination between the two domain experts and then it kind of, you got that
10:23 microservice cascading, like it's got to do, then this one's got to be upgraded.
10:28 And then eventually there's enough flow of data through the system that the UI people
10:31 can put it up there, right?
10:33 Right.
10:34 And so, and it's bad in this case of like showing your bank balance, but it gets even
10:38 worse when you have a pool where every field in the form needs to be, needs to be completed,
10:43 for example.
10:44 And so we basically have to deploy the front end that has all of the form components and
10:48 the backend that receives that new form at the same time.
10:52 And we've got this piloting model that, you know, depending on how we've done it probably
10:56 is used to define our form and it might even be used to define our database.
10:59 But like we're not using a piloting model in the front end TypeScript, in my opinion,
11:04 the big Achilles heel in typing is that you don't have any, you can't use type in at runtime.
11:09 And so we don't have an equivalent of I'd answer it.
11:12 And so we're basically trusting that data is how it is.
11:15 So yeah, FastAPI is a, is an attempt, sorry, fast UI is an attempt to basically remove
11:19 that need to like have complete synchronization between backend and front end by having beautifully
11:25 designed components in the front end.
11:28 Not saying what we have now is that beautiful, but that's the idea long term.
11:31 But then the backend can basically just do the orchestration can say, show me a table,
11:35 show me a form, show me a modal and put the following content in it, et cetera.
11:40 Excellent.
11:41 Nice comment from Tony on the audience says I originally started in Python and went to
11:44 using TypeScript.
11:45 Pydantic made the transition back to Python so nice.
11:49 And so in your description, you also have up here that this Pydantic is interesting,
11:54 is involved here.
11:55 Like what is the role that Pydantic plays in defining all this?
11:58 So the idea is that we're getting to have this restful UI is really that we, we end
12:04 up having a bunch of components in a shared definition of some components.
12:09 And we basically promise that the backend is going to send data that matches the types
12:13 defined in the front end.
12:15 That's all very well, but if you're not careful, you end up not sending quite the right data.
12:19 So what's nice is that all of the components that you can return from fast UI are themselves
12:25 Pydantic models.
12:26 So Pydantic goes off and does not only the validation, but also the coercion and it does
12:31 stuff like uses camel case.
12:33 So the front end developers are happy because we've got every no underscores anywhere.
12:37 And so yeah, the, all of the front end, sorry, the backend code for fast UI is basically,
12:43 it's just Pydantic models, which, which implement these components.
12:46 Right.
12:47 So it might be useful for those who can't see this to go in and I can talk through an
12:50 example if we go into the code here and I can talk you through like a very basic component.
12:55 Oh, maybe it'd be, I showed it here.
12:57 So I've got, got the code base open here, just working on something.
13:02 But if I open up here, source and then the Python package, and then we look into components
13:08 and we can look at like a really simple component, probably a button, which would be kind of
13:13 understandable to everyone.
13:14 Where's button?
13:15 Here we are.
13:16 So this is just a plain Pydantic model, which contains text, which is the text you would
13:20 put within the button.
13:21 Then it contains the event that you want to fire when someone clicks on it and HTML type,
13:27 which matches what you can get in HTML, button, reset, submits, and then class name, which
13:33 becomes the classes that get applied.
13:35 And then critically this type, which is a literal, which has to be button.
13:39 And that is used by the discriminated union in Pydantic to do the validation of different
13:45 types.
13:46 And it's also used by a big switch statement in the, in the TypeScripts to basically decide
13:51 what component I'll go and render when I, when I get an object.
13:54 Right.
13:55 So there's some TypeScript, maybe it makes sense to talk a bit about the building blocks.
14:01 So you say FastUI is made up of four things just so people can get a sense of like, you
14:06 know, what's at play here.
14:07 Right.
14:08 So, so the four things that we have now package a Python package called FastUI, which I was
14:12 just showing you there, the types for, and then we have NPM package called FastUI again,
14:18 it's in the Pydantic organization, which is where the meat of the, of the logic resides.
14:23 And that's, that's implementing basically the most of the components and all of the,
14:29 the wiring to mean that when I return a button, a button, the button component gets, gets
14:33 rendered.
14:34 And then, but obviously we don't probably want to end up using a vanilla button when
14:38 we come to display it.
14:40 So then I've implemented basic customization of the FastUI React library using Bootstrap.
14:46 And all that's really doing is it's deciding what classes to append to use with each component
14:50 and also just customizing a few of them.
14:52 So for example, modal, there's no like nice way to do a vanilla modal.
14:56 So the modal implementation in the default FastUI package just basically shows me alert
15:01 saying this isn't implemented.
15:02 Whereas the Bootstrap one uses a nice Bootstrap modal.
15:05 And then we have finally FastUI prebuilt, which basically uses the FastUI package, customizes
15:11 it with FastUI Bootstrap and then, and then builds it.
15:14 And that means we can, we can go and basically return that prebuilt React app without having
15:19 to get our hands dirty with NPM on yarn and all the other.
15:24 All the web packy bundling minifying transpiling business.
15:29 But the cool bit, in my opinion of FastUI is that at its core, it's really the definition
15:34 of a bunch of different schemas effectively.
15:36 Those schemas are defined in Pydantic and they're defined in TypeScript, but they could
15:41 perfectly well be, and really nicely, I just merged it the other day.
15:45 We now use the JSON schema generated by Pydantic and JSON schema generated by the React types
15:52 to basically go and test that there's an equivalence between those two, those models everywhere.
15:57 But in theory, there's nothing to stop the front end from being built with another JavaScript
16:01 library or even, even with something like HTML and HTMX, or even you could go and use
16:06 React Native and builds, or even some kind of embedded device.
16:09 You could go and implement those components.
16:11 And then on the other side, and this is even more achievable, you could go and return data
16:16 that matches those models from a Rust or Go service.
16:21 And in theory, not have to change your UI at all, because all you're doing is I promise
16:24 that I'm going to match these schemas and then whatever front end and whatever back
16:29 end can then communicate.
16:31 Whether that comes to pass, I don't know yet.
16:32 And obviously I built the default backend in Python, because that's what I know best
16:36 and where I think Pydantic is really helpful and I built the first front end in React and
16:42 TypeScript because one, that's what I know.
16:43 And two, it's what we're using within Pydantic.
16:45 But there's a, you asked, lots of people have asked about HTMX.
16:48 People have also asked about Svelte and others.
16:50 I think I wouldn't see the point in building like fast UI in Vue because I don't think
16:55 it adds much.
16:56 It's just a lot of work.
16:57 But I think there's a world where we build a HTMX template rendered version of fast UI's
17:03 front end that could be super valuable.
17:05 That's interesting.
17:06 So first point is these different components sound like they are potentially a little mix
17:11 and match.
17:12 You know, you could take it all as one big thing, or you could say really like the way
17:15 it defines the React front end, but we're going to implement it some other end point.
17:20 Yeah.
17:21 I think it's something like, it'll be slightly skewed now because of tests, but I'd say it's
17:25 sort of twice as much front end to backend at the moment as in the, yeah, it's skewed
17:30 a bit by test, but even now there's more TypeScript.
17:33 So I think the simplest thing to do, and you could do it pretty trivially, would be to
17:37 use another backend, another language for your backend service.
17:42 And as long as it matches those types, and you could even go and use something like JSON
17:45 Schema to enforce that.
17:47 But yeah, re-implementing the front end, probably a bigger piece of work, but totally doable.
17:51 I mean, I did it in my spare time in two weeks, built the whole thing.
17:54 So it's not, you know, millions of different things.
17:56 There's kind of 20 components at the moment that are then composable to build reasonably
18:00 sophisticated like UIs.
18:02 So this is a web front end like Flask or Django sort of framework, but a way that really incorporates
18:09 building the UI in Python and validating and enforcing that with Pydantic rather than just,
18:15 Hey, file new HTML.
18:17 Let's just start typing and hope they line up, you know, like instead of trying to juggle
18:21 all those different languages, CSS, HTML, all the JavaScript tooling for packing up
18:26 stuff, just let's write Python, right?
18:29 So maybe you got a simple example of what it looks like to define a real simple example
18:35 here on the readme.
18:37 It's got a very interesting parity between what is in the HTML DOM and is what is in
18:44 the Python abstract syntax tree, I guess, right?
18:49 And visually as well, the way you look at the code, it looks like the way it might look
18:53 in HTML.
18:54 Like give us a sense of what writing a UI in this would look like.
18:57 Right.
18:58 So I think the first of all, we have to talk about like the two enormous, the two most
19:01 obvious pitfalls for this.
19:03 One end of the pitfall you have, which I think is the biggest temptation is to basically
19:09 mirror all of HTML in Python.
19:12 And for those of us who are happy writing HTML or writing React, that sounds like hell.
19:16 It's going to be slow because you have to do some weird rendering, but it's also just
19:19 going to be a picky because I don't want to have to define every A and Href and everything
19:23 else in Python code.
19:25 It's just, and there are going to be, it requires for start, it requires you to know two things,
19:29 Python and HTML, whereas HTML, you only need to know one.
19:35 This portion of Talk Python to Me is brought to you by Bright Data.
19:39 Bright Data helps you turn websites into structured data.
19:43 There's an unimaginable amount of data available on the internet.
19:47 And we're lucky to live in a time where we have so many APIs to access structured data.
19:53 But the truth is that most of the data out there is not served up over a clean API.
19:59 Just sitting there on a web page as HTML.
20:02 Maybe it's even further obscured behind some front end JavaScript framework like Vue or
20:06 react.
20:07 What if you need access to that data?
20:10 Web scraping to the rescue, right?
20:12 Yes, but just like you wouldn't set up your own production infrastructure in your home
20:17 office, running a web scraping job on a single computer at a fixed location can lead to your
20:22 program being unreliable with data pinned to that IP location and much of the time blocked
20:28 for rate limits and other such causes.
20:31 If you need to do professional web scraping, bright data is the place to start.
20:36 They have award winning proxy networks and powerful web scrapers.
20:40 What's more is they have ready to use data sets for download.
20:43 So you might not even need to scrape data at all.
20:46 And if you can't find the data set in their marketplace, they'll even build a custom data
20:51 set for you.
20:53 From listening to the show, you know that I'm a privacy conscious person.
20:57 And that's why I'm happy to see that they are both CCPA and GDPR compliant.
21:02 Bright Data has both low code solutions as well as Python programming models with async
21:07 IO and playwright.
21:09 So if you have serious data needs, and those websites don't offer API's, then you need
21:14 bright data, check them out today at talkpython.fm/brightdata.
21:19 And please use that URL that way they know you heard about them from us.
21:24 That's talkpython.fm/bright data.
21:27 The link is in your podcast player show notes.
21:29 Thank you to bright data for supporting the show.
21:33 I always find these things that try to dodge like dodge the fact that HTML exists.
21:37 I find them I just they don't resonate with me.
21:40 I'm not entirely sure why it's like we have really nice things like CSS and we have really
21:46 all there's just so much tooling and frameworks, you know, you mentioned bootstrap already,
21:53 right, that just plug into there.
21:54 And if it's like, well, we're just going to write, recreate it in Python.
21:58 Well, it has all the oddities of HTML if it's going to be really high parity, and then you
22:03 just have a less well known way to do the same weird thing.
22:06 You know, I don't know, just it doesn't resonate super with me.
22:08 I agree.
22:09 And I found the same thing at times with ORMs that you end up the worst case of an ORM is
22:14 you work out what you need to do in SQL, then you try and translate back from SQL to ORM.
22:19 And it would be much nicer just to write my SQL.
22:21 I mean, not always the case, ORMs can be powerful, but I think that they, they both can fall
22:25 into the same same trap if you're not careful.
22:28 And then I was gonna say at the far end of the spectrum, the other end of the spectrum,
22:30 you have, and I guess Django's admin view for understandable reasons could suffer from
22:35 this that you basically have a very small set of things you have a like a table page
22:38 and a details page and a form page.
22:40 And that's kind of it, right?
22:41 So there's this difficult trade off in where in that continuum do we try to choose what
22:46 size of component to implement, right?
22:48 So for example, here we have, we have a heading, which is almost one for one matches what you
22:53 would do in HTML.
22:54 We have the text that goes within it and we have the level, which, you know, it's slightly
22:58 different syntax, but it's basically one for one matching an HTML tag.
23:02 But then we have a table, which it doesn't look very much like an HTML table at all.
23:07 We're not having to explicitly define the table body versus the table head.
23:12 We're not having to put in each column.
23:14 We're not having to worry.
23:15 Yeah, there's lots of stuff here that is much less like it.
23:17 And that's where it's in these very common components where there is consistent things
23:23 that lots of people want to do, or lots of places in your app where you might want to
23:26 do them, where I think a framework like fast UI gets gets super powerful because we can
23:31 get you a table here with with users defined and with a few columns with some customization
23:37 on what happens when you, how we render each column much more quickly than we could go
23:41 write out all the HTML for that.
23:43 And it's much more concise to read it.
23:45 Like it's consistent enough that something like Copilot will help you write it out where
23:51 you do have a bit of customization to do.
23:53 I think this, this is where it can be super powerful.
23:55 Yeah, it's, it is pretty interesting.
23:56 And I like the hierarchy for people listening, just check out github.com/pydanics/fast UI
24:02 and the example right there on the page.
24:04 But what you do is you create a, in this case, a FastAPI, API endpoint, and then you return
24:10 a hierarchy of elements out of fast UI.
24:13 So we have a page, the page has components, the components are a list of a header in a
24:17 table, the table has data, which maps over to a list of pydantic models, which then help
24:24 say what goes in the field and for the column headings and things like that.
24:29 It's pretty interesting.
24:30 I think it's neat.
24:31 And obviously we can add other components like pagination that works.
24:34 I think just, just to come back to the top, to how we do these views, the very simple
24:39 and it's most simple what fast UI's react app does is it basically takes whatever the
24:44 URL is you go to.
24:46 So in this case, you might go to slash to the base URL and it pre-pens slash API and
24:52 makes a request to that endpoint to basically say, what should I render?
24:56 And it gets back.
24:57 And so this here, where we're basically returning a list of pydantic models, all the fast UI
25:03 model is really doing is taking that list of pydantic models and calling model dump
25:07 JSON on it to get the JSON that we returned to the front end.
25:11 As I say, the front end then knows how to render each of those.
25:16 Each dictionary in the list is what it is at its core.
25:18 At its core, it's a, it's a list of objects to use JavaScript parlance.
25:22 It just knows how to render each of them and renders each of them in turn.
25:25 And then obviously they can then have nested other models, all of which it knows how to
25:29 render.
25:30 Yeah.
25:31 It reminds me of a couple of things.
25:32 I have an example of this, no, somewhere along here.
25:34 I pulled it up.
25:35 It reminds me of kind of what react looks like.
25:39 If people have done react, you know, you write a function that returns kind of an HTML thing,
25:45 but then it has JavaScript arrow functions, right?
25:48 It's a, but it has the same nested feel, right?
25:52 Did react inspire you to create it this way or not really?
25:55 Yeah, it did.
25:56 I've done quite a lot of react and I like it a lot.
25:58 I know there were as a, as a popular piece of technology, there were lots of people who
26:02 like to like to break it, but I do think react.
26:06 So like being a powerful step forward and the greatest form of flattery is, is copying.
26:11 And there are enough other, like sure there are other more powerful, arguably more powerful,
26:16 arguably more performant new front end libraries, but everything is, is component based now.
26:21 Like, you know, react has changed, changed the, was the sea change in how we did front
26:25 end with that component architecture and JSX similarly is, is superpower.
26:29 So one of the things that I think we're going to get to, I don't want to dive into it yet,
26:32 but like in react, you would say like, we're going to return a photo contacts, a context
26:37 or a switch or something that is not typically known in HTML.
26:41 And these are higher order building blocks in the UI space.
26:45 Right?
26:46 So when people think about what they're creating here in Python, it's not just the fundamental
26:51 DOM objects and elements, is it?
26:54 Right.
26:55 So that, that, that was actually, yeah.
26:56 So page here is a bit of ambiguity about how we're going to define a page.
26:59 Like default implementation does, does something reasonably sensible.
27:02 It like, you know, pads it, et cetera.
27:05 But like heading isn't, there isn't much to do really.
27:08 You're going to return a heading, but when you come to a table, there's a lot of debate
27:11 about how you're going to do that.
27:12 And then when you move on to like even higher order components, like a modal, then that's
27:17 the, the, how exactly that's implemented is, you know, in some sense it's to completely
27:21 the choice of how you've implemented it in the front end.
27:23 You could, you could do lots of different things, but yeah, the whole point is that
27:26 it doesn't and shouldn't be like each HTML tag is written out.
27:31 Cause as I say, I think that would be a like obvious failure mode for this.
27:34 Yeah.
27:35 The other thing this reminds me of, by the way, just for people out there listening is
27:40 it looks a lot like a flutter.
27:42 If people have done any flutter, you've got these widget hierarchies, you build them,
27:47 you maybe set some properties, you add in a bunch of, a bunch of elements, you know,
27:53 set some children to an array of other sub elements.
27:56 And this is done of course in Dart, but it's, you know, this is kind of a Python version
28:01 that's similar as well, these higher order widgets.
28:03 Yeah, absolutely.
28:04 Similar thing.
28:05 And actually the other place where I've built this before is that internally Pydantic core,
28:10 the Rust bit of Pydantic is effectively not entirely different to this, right?
28:14 You define these nested structures of validators.
28:18 Everything at its core is a like combined validator, which is in Rust terms, an enormous
28:22 enum of all the different types of validator, some of which have nested within them, more
28:26 and more validators.
28:27 And that's how you build up nested structures of Pydantic models, which in turn is what
28:32 these are.
28:33 We're getting a bit of it.
28:34 Yeah.
28:35 The validators and the UI, they kind of like have a similar structure.
28:37 A bit of a sidebar, just a bit of piece of code in here.
28:40 You've got table, which is a class, square bracket, user, which is another class, square
28:46 bracket.
28:47 I imagine that you and your team are deeper into the Python type system than the vast
28:53 majority of others out there with all the work with Pydantic and the interoperability
28:57 with Rust.
28:59 What is that?
29:00 Tell people about this.
29:01 Yes, a table is a generic.
29:03 So you can imagine if you were doing list of ints, you would do list square bracket
29:07 int.
29:08 And that's basically the point is that list is a generic around its elements, same as
29:13 a dict is generic around its keys and its values.
29:16 While table here is generic around the Pydantic model that you're using for each row.
29:23 And particularly what that means is that what it means practically is that table has access
29:27 to the class when it's deciding what the default columns are.
29:32 So if you don't define the columns list as we have here to say what columns to display,
29:36 it'll show all of the fields in the Pydantic model.
29:39 And the point is we get access to that to the user before we've, even if the data was
29:44 empty before the validation has happened.
29:47 Is it necessary?
29:48 Is it slightly like, yeah, fancy use of Pydantic types, Python types, maybe it is.
29:54 But yeah, if you know, forgive the Pydantic team or me in particular for occasionally
29:58 doing fancy things with Python types.
30:00 That is definitely occupational hazard of what we do.
30:02 Yeah.
30:03 I didn't mean it as a negative.
30:04 I just thought it was interesting.
30:05 No, I agree.
30:06 And actually I had it somewhere else on forms and I removed it and realized it was, it was,
30:10 it was unnecessary.
30:11 So you can definitely do too much.
30:13 Such a thing as too much Python typing.
30:15 Yeah.
30:16 Yeah, for sure.
30:17 It is pretty interesting.
30:18 So let's maybe talk about some of the examples.
30:21 Actually before we do, just give us a sense of where does this fit in the UI space for
30:27 Python?
30:28 On one end we've got Flask, Django, FastAPI, returning HTML, et cetera, where it's all
30:35 on you.
30:36 You're doing all the five languages of web apps, SQL or some query language, Python,
30:43 JavaScript, CSS, some other tools, right?
30:46 Like you're doing all that and you're doing my hand.
30:48 On the other end, we've got tools that are pretty cool.
30:50 Like we've got Anvil that lets you just write Python and do a draggy droppy sort of thing,
30:56 which is, is really neat, but it fits into a kind of a box for those types of apps.
31:00 I just discovered DropBase.
31:02 Have you heard of DropBase?
31:03 Not seen DropBase.
31:04 Yeah, but I've seen a lot of these like, get me a UI more quickly.
31:09 A lot of them are like kind of low code.
31:11 Anvil, maybe I wouldn't really quite put it there, but they're pretty like low code, but
31:14 then there's places where Python goes to make it dynamic.
31:18 Right.
31:19 So we're in that spectrum.
31:20 Would you put fast UI as it is today?
31:23 Interestingly.
31:24 One of the reasons I wanted to come and talk to you was I heard you were talking the other
31:27 day on your other podcast, and I heard you talking about fast UI and kind of, I'd say
31:32 categorizing it into that group.
31:34 And what I wanted to kind of, one of the things I wanted to come and say was, yes, we can
31:38 do that, but the use case we have within Pydantic is actually to go and build a pretty complex,
31:44 fully fledged application with front end developers building components, but just get rid of that
31:48 churn.
31:49 Right.
31:50 So it's more like Gmail, less like here's a table that I can click on and see some related
31:56 table.
31:57 Right, exactly.
31:58 And then what I should probably put in the demo and probably where Pydantic is people
32:00 most associated and where this is going to be most useful is within forms.
32:05 So I don't know if you want to go to the demo and I can talk people through, but like within
32:10 fast UI is dedicated to forms.
32:12 We can do things like nested Pydantic models all become components within a form.
32:17 Then obviously we can do client side validation with a whole bunch of stuff, but we can also
32:21 do server side validation, but then we get all the fancy stuff.
32:24 Like if the data is invalid and you get a validation error on the server side, we'll
32:30 then basically re-render the form with the errors in place, all that stuff that like
32:35 anyone building a web application has to go and implement some version of it.
32:38 At the moment there are some React libraries that will build you a form from JSON schema,
32:44 but they don't perfectly fit in with what Pydantic does or with FastAPI.
32:49 And so I have built some variant of that about five times.
32:53 I still think the state of the art until now is Django, but like lots of us don't want
32:57 to build our web applications completely with Django because it's pretty all or nothing
33:01 despite the wonder that is Django.
33:03 And so that's the kind of space where for me, this like becomes a really stands out
33:09 because what would have been to do it properly, it's days of work to get form validation,
33:14 to get form submission to work, get client side validation, server side validation, get
33:18 the redirect after your form.
33:19 None of that stuff is entirely trivial, even for those of us who've done it before.
33:23 Whereas the theory is with fast UI and in, although fast UI does not require FastAPI,
33:30 the form stuff is quite tightly integrated with FastAPI and you can get a really good
33:35 experience of building stuff like forms.
33:38 I think that where the alternative really today is to use, no disrespect to any of the
33:44 fast libraries or any of the other things, but I think the only real alternative right
33:48 now is implementing yourself or use Django.
33:50 - Yeah, but I do also want to, but maybe before we get to that, let's try to take a little
33:54 survey of what are these widgets, these building blocks that you can use.
33:58 Yeah, is that right?
33:59 - Yeah, absolutely.
34:00 - I think I can find them here.
34:01 Yes.
34:02 Yeah.
34:03 So you have a UI demo, which I'll link to at onrender.com, the prefix, but you talk
34:08 about some of the things that you can just create in that Python hierarchy that you return
34:14 that builds up your UI there.
34:17 So maybe you talk us through some of the things that are here.
34:19 - Yes.
34:20 We have the kind of generic markdown component, which will go up and renders a markdown.
34:24 This table itself is implemented using the markdown component.
34:27 Just one side note, the markdown and the code, because they have quite a lot of JavaScript
34:32 associated with them, they're actually lazily loaded to make the prebuilt fast UI app faster
34:38 to load.
34:39 Then we have text, probably the simplest one of all, just render some text.
34:42 Paragraph, again, very simple.
34:44 Page titles, a slightly funny one.
34:46 It doesn't actually display anything on the page, but it changes the browser title.
34:50 So what you see in the tab at the top of the page.
34:52 - It's not always easy to do.
34:53 Like how do you inject it into the head when you're in the body?
34:57 It takes a little bit of integration there, yeah.
34:59 - Right, exactly.
35:00 So again, very simple, like one to six HTML heading.
35:03 Code, a bit more sophisticated.
35:05 And if you click on code, maybe those who can see it will be able to click through.
35:09 Oh, code is, yeah.
35:10 So code is there.
35:11 We get a highlighted bit of source code displayed.
35:16 - It's color coded with class types having a color and keywords having a color.
35:20 That's nice.
35:21 - Like you would see in GitHub or something like that.
35:23 So again, just work out of the box.
35:25 Then we have some components like a link list and link, which are used in other components
35:30 mostly.
35:31 So if you, the nav bar you see at the top of the page there, that uses a link list and
35:34 then we have links.
35:35 Then we get into kind of more sophisticated components.
35:37 So the first one, you see a button, which loads a modal and then the button, which loads
35:41 a dynamic modal.
35:42 So when the modal loads, it will make a request to get the content you want to see within
35:46 that modal.
35:47 So that could be a form or it could be customized depending on the form in the page.
35:52 Then we have loading content from the server, which is the same thing we were doing in the
35:55 modal, but on the page.
35:56 Then we have this SSE component.
35:58 So again, very simple to use within Fast UI, but like quite a lot of work to use server
36:03 side events to basically dynamically update a React component if you weren't using that.
36:08 - So your server load SSE widget, that provides, like you said, server sent events, which I
36:15 don't know how many people are familiar with SSE.
36:17 I'm sure they're familiar with WebSockets and they're familiar with just like a JavaScript
36:21 event.
36:22 So it's like an immediate sort of lightweight, one directional, but normally the opposite
36:26 in reverse, I guess, from the server to the client, sort of pushing out stuff.
36:29 So that's a really powerful thing.
36:31 And if it's that easy to just hook a function call when something happens, that's pretty
36:35 cool.
36:36 - One of the things I want to try with SSE that I think will work really nicely is LLM
36:40 responses where you get like one token at a time because you don't want to wait for
36:42 the whole thing.
36:43 - Yeah, exactly.
36:44 - The event would be perfect for basically printing out the response from an LLM.
36:48 And again, it would be like two lines of code to add that to an app with Fast UI.
36:52 It would not be two lines of code to go and implement that yourself, whether you're using
36:56 pure JavaScript or React or whatever framework.
36:59 And we have iFrame, which again, kind of map, we're back to kind of mapping one-to-one to
37:03 a component.
37:04 One of the nice things to say about both iFrame and images, they were contributed by other
37:08 people.
37:09 So I don't think I'd even created an issue asking for them, but people have come along
37:12 and added them.
37:13 It's been one of the nice things to see.
37:14 I think we had 18 or so people contribute to the first release, first release after
37:18 my initial release, or sorry, the second release of Fast UI.
37:22 So yeah, good engagement from lots of people.
37:24 Image.
37:25 - Yeah, so you've got a bunch of UI stuff here.
37:27 And it just, as I look at this and I see what you're building, it just makes me think of
37:32 like, wow, there's an opportunity for stuff like what you get out, not necessarily the
37:36 same as, but like what you get out of say, Tailwind UI, where the things you might work
37:41 with are on-off switches, you know, like toggles, like you might see in your phone or other
37:46 sort of elements that have like a lot of design imbued in them that people can just grab and
37:52 use, almost like a Django philosophy for the front end, in a sense there.
37:57 Is that something that you are dreaming of or?
38:00 - Someone was complaining somewhere that we didn't have a grid component yet.
38:03 And I think we'll do one, but like those bits get quite opinionated, but yeah, like calendar,
38:07 completely obvious choice, right?
38:10 Complete faff to go and implement that yourself in HTML, commonly used, trivial to define
38:14 because the definition, there aren't that many different things to define.
38:17 You choose your month.
38:18 You know, most of us are on the Gregorian calendar, right?
38:21 We're not going to have to change too much what calendar we're going to render.
38:25 So yeah, that's a perfect example of the kind of thing.
38:28 Tiles like this, again, totally possible to go and implement them.
38:31 And again, obviously you can use, we can provide some nice default, but also if you're a bigger
38:36 company and you want to go and customize it, you can totally do that.
38:40 And you can have a front end developer go through and implement the classes that basically
38:43 customize the look.
38:45 I wanted to come back just to show you some of the other components.
38:49 So we were on, yeah.
38:51 This one here.
38:52 I don't know if we have anything more below that, but I would love to show you the tables
38:55 because the tables and the forms of really where it comes into cities is probably the
38:59 best example.
39:00 Okay.
39:01 Yeah.
39:02 Awesome.
39:03 This is a list of cities just for some public data set with country and population.
39:06 But at the top you see we have a filter to choose by country.
39:10 And if we click here, if you start searching like UN or something, you'll see we're doing
39:14 a server side.
39:15 We're loading from the server, the list of cities.
39:17 So again, this component to go and implement, if you were going to do that from scratch,
39:21 you've got to have you some like clever, this is a list of countries.
39:25 So if you do like, oh, country, sorry, I'm typing in cities.
39:27 Good.
39:28 Like UN, you'll get United Kingdom and United States.
39:30 Perfect.
39:31 There you go.
39:32 And then we do United States or whatever.
39:34 Yeah.
39:35 And then we'll get a bunch of cities in the United States.
39:38 Building this and wiring it all up and using one of the, we use react select here, but
39:42 you can use select two or one of those components.
39:45 It's not trivial.
39:46 You need to also set up the backend.
39:47 You need to set up this.
39:48 There's like a few hundred lines of react dedicated just to setting up those, those
39:53 selects correctly.
39:55 And as you'll see in a minute on a form, you can add this to a, to form with us.
39:59 You are pretty trivially.
40:00 Secondly, if you go to the bottom of the page on cities, you will see pagination again,
40:05 not a trivial thing to go and set up.
40:07 If you've got, if you're just starting from scratch and you want to show like build an
40:10 internal endpoint, for example, to show all of your users doing all that pagination and
40:14 like wiring all that up is not trivial, but we effectively do the work for you to have
40:18 that component and do the maths of which page we're on and stuff like that.
40:22 I want to reiterate, this is the fast UI is not just designed as a kind of Django admin
40:27 interface alternative.
40:29 We within Pananzi are going to go and use it for UI that we're going to show to end
40:33 users.
40:34 But obviously it also comes into its own when people want to just get something up quickly.
40:40 This portion of Talk Python To Me is brought to you by Sentry, you know, Sentry for the
40:44 air monitoring service, the one that we use right here at talk Python.
40:47 But this time I want to tell you about a new and free workshop.
40:51 He mean the Kraken managing a Python monorepo with Sentry.
40:55 Join Salma Alam Nayyar, senior developer advocate at Sentry and David Winterbottom, head of
41:01 engineering at Kraken technologies for an inside look into how he and his team develop,
41:06 deploy and maintain a rapidly evolving Python monorepo with over 4 million lines of code
41:13 that powers the Kraken utility platform.
41:16 In this workshop, David will share how his department of 500 developers who deploy around
41:20 200 times a day, use Sentry to reduce noise, prioritize issues and maintain code quality
41:26 without relying on a dedicated Q&A team.
41:29 You'll learn how to find and fix root causes of crashes, ways to prioritize the most urgent
41:34 crashes and errors, and tips to streamline your workflow.
41:38 Join them for free on Tuesday, February 27 2024 at 2am civic time.
41:43 Just visit talkpython.fm/sentry-monorepo.
41:47 That link is in your podcast player show notes.
41:50 2am might be a little early here in the US, but go ahead and sign up anyway if you're
41:54 a US listener, because I'm sure they'll email you about a follow up recording as well.
42:00 Thank you to Sentry for supporting this episode.
42:05 If we have a design language or something like that, or even using a framework, I mean,
42:09 you mentioned bootstrap, but tailwind or Bulma is that one of the new ones?
42:13 Like if we're working with one of those, and we wanted to use this, like how easy is it
42:19 to sort of bring in those elements there?
42:21 So if I show you here on boot, so I'll show you how we customize it with bootstrap, which
42:26 is probably the best definition of it.
42:28 So you'll see here, this is in the, this is the, where am I looking?
42:32 This is the prebuilt version.
42:33 So this, this is obviously the prebuilt version of fast UI you can get, but it's actually
42:38 just, it's a very simple app in terms of react.
42:41 This app has one, well, two components.
42:43 It has a div which contains the fast UI component, and then we customize it in a bunch of ways.
42:48 We have a like component that we render for not found.
42:50 We have a component we render for spinner and for transitioning.
42:53 But then these are the two that really matter, where we can customize the classes and we
42:57 can customize how we render certain components.
43:00 So if we come in here to have this function from bootstrap, which is how we customize
43:04 the classes, you'll see that at its core, it's just this big old switch.
43:08 So this is all a TypeScript, like type safe because types are very powerful in TypeScript,
43:13 but like all of the props will have this type key.
43:16 As I showed you earlier, when we were looking at the Python code, That's like, and all the different things.
43:21 Yeah.
43:22 Based on the switch, we just go through and this is all just like defining the classes
43:25 we want for all of the different components.
43:27 Some of them depending on the exact state of the component.
43:30 So all of these form inputs, we customize them depending on which type they are and
43:34 on which mode we're in, et cetera, et cetera.
43:36 But it's all very mechanical, just like laying out the classes we need for each individual
43:41 case.
43:42 And then we have the other way of customizing it, which is to use custom components.
43:46 We basically for three in particular components, navbar, modal and pagination, we define our
43:52 own custom React components.
43:54 So here's the one for navbar where we use a bunch of bootstrap types to render a bootstrap
43:59 navbar.
44:00 So you could basically create a React component that has all the settings necessary to create
44:06 a navbar in Tailwind or whatever.
44:08 Right.
44:09 And then just plug that stuff in.
44:10 So if you wanted to use Tailwind, what's this, like 20, it's like a hundred lines of code
44:14 to define all of the classes.
44:16 And it's pretty mechanical code, right?
44:18 So it would be, it wouldn't be hard at all to go and use Tailwind, Tailwind CSS.
44:23 And then you might want to define a few of your components specifically.
44:26 But actually modal, I think is the only one that really requires it to be custom implemented
44:30 because the default just shows you an alert because there's nothing.
44:35 The page says, it's like, ah, no, the page doesn't say this isn't going to work.
44:39 Yeah.
44:40 So yeah, I think this is one of the bits I'm most proud of here is that like how much you
44:43 could customize it and how simply you could start to customize it.
44:46 Right.
44:47 Those are really like kind of pluggable or extensible.
44:49 So you don't have to get in and know too much about it.
44:53 You just plug in the class name generator and the renderer for a specific one.
44:58 And so, yeah.
44:59 And all of the types, it's all typescripted.
45:01 So the types should do a lot of help telling you what you can implement.
45:05 Last thing I'll show you is, yeah, so here in the default build, as I said, we, our custom
45:10 render function is not just a bootstrap one.
45:13 We do one special thing, which is where we have this idea of a custom component, which
45:18 basically all it has is a subtype, which basically you should use to render it however you like.
45:24 So in our case, we take custom and if the subtype is cow say, we render that as a particular
45:31 block, like use this component here.
45:34 And we print out the cow says whatever it was that the input was from the server.
45:37 And otherwise we just go back to using the bootstrap render.
45:39 And so if you look at that component here, yeah, we've got this like slightly silly example
45:45 of a custom component of cow say saying something.
45:47 Oh, that's fun.
45:48 But yeah, it shouldn't be too difficult to customize.
45:51 And then even if you're customizing to go back to using bootstrap for the full back
45:54 case of everything else.
45:55 Okay.
45:56 So you could almost just for one section that has to be really specialized to some custom,
46:01 but otherwise just lean on a framework.
46:02 Yeah.
46:03 Okay.
46:04 Yeah.
46:05 This looks like something that one person could take one for the team, create a tailwind
46:09 or a whatever generator, class name generator, and then put that as either a contribution
46:14 or put it up on GitHub and then you just, you're kind of good to go.
46:18 Yeah.
46:19 I think we might, we might actually do it.
46:20 We're, we're using tailwind and radix within Pythontics.
46:23 So I suspect our front end guys will at some point get annoyed with my use of bootstrap
46:27 and go off and go and change it.
46:29 One of the reasons I use bootstrap is that because bootstrap is completely customized
46:32 via SCSS and the SCSS compilers for Python, we have the, at least the possibility in future
46:39 to allow you to customize the complete look and feel of your app without ever having to
46:43 touch NPM because you just go change basically the color definitions as we do here.
46:48 So, so the, the default version of maybe I can even change it here and as it's running,
46:53 it'll change.
46:54 But if I hear you say I've set the primary color to be black and so you'll see the buttons
46:58 here are all rendered as black.
47:00 If I were to change it, I haven't tried this for a bit, so I hope it works.
47:04 Comment it out primary.
47:05 You'll see that all of the primary, which is the bootstrap primary button.
47:11 And if I changed it, I got rid of the default font, you would see we went back to whatever
47:16 the other font was.
47:17 So there's a world in future where we allow you to customize the look and feel even within
47:21 bootstrap from Python code.
47:22 Yeah.
47:23 Tell people maybe who don't know what SCSS is.
47:25 They probably know what CSS is.
47:27 It's generally referred to as SASS, which is S A S S, which was, is, is basically a more
47:34 powerful version of, of CSS where you can.
47:36 SAAS and LESS.
47:37 Those were the two.
47:38 Yeah.
47:39 And then we kind of settled on SASS, but then we had SCSS, which is SASS with more CSS syntax.
47:46 It's a way to like do slightly more powerful things in, in CSS and minify it and have stuff
47:52 like variables for they were available in CSS and defaults.
47:56 And even you can do weird stuff like map functions and they use very heavily in bootstrap.
48:01 But the nice bit is because the compiler is written in C, there's lib SAS in Python where
48:06 you can get kind of a front end customization without needing the whole of node and the,
48:13 the whole dog and pony show front end of it.
48:15 Yeah.
48:16 Excellent.
48:17 It's got a lot of legs.
48:18 So when I saw this and I saw, okay, this is a, for, for web apps and it's kind of got
48:22 this, this Python code running that defines the backend and it's got the UI and it's all
48:27 a little self-contained.
48:29 One of the thoughts I had was, wouldn't it be neat if there was a, got a little bundler
48:34 type of thing that made this into an electron app.
48:36 Would this be possible?
48:37 Can we get something that you could send out?
48:40 Or is this really just going to be intended to be kind of a, a friend of Django type of
48:45 thing?
48:46 I have not used electron for a very long time, so I don't pretend to be an expert.
48:50 What I will say is that unlike some of the other UI libraries, we're not trying to do
48:55 clever things with web sockets and do all of the, all of the rendering requiring duplex
49:00 communication between the client and the server.
49:02 It's pretty simple.
49:03 It's like make a request and the JSON contains some information about how to render it.
49:08 And then the front end goes off and renders it.
49:09 So it's the result, what you get when you finish is very, in terms of a networking point
49:14 of view, very, very simple, very conventional.
49:17 It's like make an HTTP request to get back JSON, JavaScript knows how to render it.
49:21 And so I don't see why it shouldn't, shouldn't work in, in electron.
49:25 There's even the world in which we don't need the whole of electron and we could, someone
49:29 could go and build fast UI components for whatever native library, and we could get
49:34 like native apps running that are based on fast drive.
49:37 Not saying that's necessarily a good idea, but like those possibilities exist.
49:41 It is, it does exist.
49:42 Okay.
49:43 Yeah.
49:45 Very interesting.
49:46 Another thing that is convention, I suppose, I'll see if I can pull it out here is the
49:49 UI.
49:50 A lot of times you'll have either just slash or have slash users, but then you'll have
49:55 an API that backs it.
49:56 And there's this convention that if it's in the URL, if you have slash API slash, in this
50:01 example we were talking about before, it's like slash table slash cities.
50:04 If you say API slash table slash, that's the data endpoint.
50:07 And then if you drop the API, that's the front end that then turns around and calls the backend
50:12 with the API inserted.
50:13 Right.
50:14 You want to talk about that convention a little bit so people kind of see where that's going.
50:18 So that's how, how I've set it up in the default app.
50:21 It doesn't, you don't have to do it like that.
50:22 And I think we're using a separate subdomain to avoid like path-based routing and all that
50:27 fun.
50:28 But yeah, the, the, the principle that the default simplest way of basically doing a
50:32 calc excuse me, a calculation to go from, I've got a URL, how do I get the data for
50:36 it is as I said earlier, basically prepend slash API.
50:40 So maybe a more general way to think about it is for every page, there is an endpoint
50:45 that is a FastAPI endpoint or a pair of them.
50:47 Maybe even the one returns the HTML front end stuff that makes it run that talks around
50:53 and goes back to itself.
50:54 Right.
50:55 Yeah.
50:56 So what we have in the default app here, what I would generally recommend is where are we?
51:00 We have a bunch of routers that connect and do all of the API stuff.
51:05 And I've just been implementing all which I can show you in a minute, but that's not
51:08 available as a PR for it, but it's not available in the demo you're looking at.
51:11 But then we have this like basically catch all endpoint, which if nothing else has been
51:15 hit, will render the standard HTML.
51:18 And one of the nice things is that the Python library gives you this prebuilt HTML, which
51:23 will basically render you the HTML that you'll get if you went here and I view page source,
51:30 you see returning.
51:31 Yeah.
51:32 Well, yeah.
51:33 And this particular, if I went to 8,000, then it wouldn't be messed up by beat.
51:37 You just get this very simple HTML, which in turn renders the app.
51:39 So yeah, there's effectively, you're right.
51:41 There's two, there's two, there's a like matching endpoints for, for every view you might want
51:45 to have one to get to return the Json, the one to render the HTML.
51:49 But you don't write, you don't write them both, right?
51:51 You write the API one and then fast UI magically turns out into UI.
51:56 Right.
51:57 And whatever, and this would all of most of this, with the exception of the form submission
52:01 would all just work out the box with, with any Python web framework.
52:04 You just need to produce your financing model, dump it to Jason and return that in a response.
52:10 But one of the really nice things about the, this being the like actual data existing in
52:16 Json is that writing a test, there's quite a lot here, but you'll see most of it is,
52:20 is Markdown.
52:21 So writing a test that our views contain what we expect them to is massively easier when
52:26 we're testing against Json, which we can convert to Python objects and tests.
52:30 Then it would be if we've got an HTML page and we're running a bunch of regexes for,
52:33 does this page contain the user's name?
52:35 Does it contain the word log out?
52:37 Blah, blah, blah.
52:38 Yeah.
52:39 So you can just say, write type of things or those types of tests.
52:42 Sure.
52:43 Oh yeah.
52:44 Even worse, you end up with that play wright and like play wright that's image of it and
52:47 see if the image looks like the image used to look and yeah.
52:50 Things I don't want to have to build.
52:51 I mean, they have to happen occasionally, but like we're, and ironically we'll probably
52:55 end up with them in fast UI to like even more certainty that our components work correctly,
52:59 but hopefully that thereby avoid everyone else having to, having to go and build them.
53:03 Is there any concern that maybe there's unintended APIs in the sense that like all of the stuff
53:09 I'm sure this is probably true for pretty much any react site, but like a lot of the
53:14 page is available also as an API, even if you don't intend it to be an API, like what's
53:19 yeah.
53:20 That's a limitation of any, I mean, in some ways the data will be slightly less nice to
53:24 yeah.
53:25 You're right.
53:26 If you're a company that give people foreign exchange rates and you want them to always
53:29 come to your site, you obviously can't render that with, with react because there's going
53:33 to be a JSON endpoint where someone can just go scrape your exchange rates or whatever
53:36 else.
53:37 Right.
53:38 And if you have a function based off and say you have to log in to do it, right.
53:42 It's not just that it's public.
53:44 It just, there's always a JSON version, but honestly there's so many interesting ways
53:48 to pull data out of HTML.
53:50 Like if someone will do it anyway.
53:53 I also think that like in theory, if your options are build pure react or do this, and
54:00 this has the, the, like, as I say, there's the realistic chance someone's going to come
54:03 along and implement a fast UI front end that, that renders HTML.
54:07 And then, and then you don't have to expose your expose those JSON endpoints at all.
54:12 And you could, you could return HTML from your server.
54:14 We just haven't got around to building it yet.
54:16 Yeah.
54:17 I guess you could maybe do some kind of server side rendering potentially as well.
54:20 Exactly.
54:21 That's what I mean.
54:22 Whether it's server side rendering or whether it's JavaScript server side rendering or whether
54:25 it's edge rendering, I've tried to build a sort of edge rendering thing in Cloudflare
54:29 years ago using Rust and for a bunch of reasons it didn't quite work, but there's real possibility
54:34 of doing like, yeah, any number of different things in that direction.
54:36 Oh, that's interesting.
54:37 I know the CDNs have pretty dynamic stuff right at the edge where you can sort of put
54:42 your last bit of code.
54:43 I haven't done anything with that.
54:44 That's kind of what Remix is doing and Next.js to a lesser extent.
54:48 So, but again, in theory, the, I mean, maybe I'm overblowing it and fast UI will remain
54:53 what it is now, but like in theory, we just, we've set up this, this language of different
54:58 components that, that hopefully is whilst by no means universal, complete enough that
55:03 you can build lots of common user interfaces with it.
55:06 And then if it really gains adoption, then people can go build new backends and new frontends
55:10 and they all in theory should be able to mix and match with each other.
55:14 We'll see if that happens.
55:15 Yeah.
55:16 And widgets too, right?
55:17 Kind of like see a Tailwind UI create a paid thing for higher order widgets, potentially
55:22 just being React already makes that, that probably exists.
55:25 I just don't know.
55:26 And there's, there's been a number of issues of people wanting to render existing, basically
55:31 build extensions to fast UI to render their widgets.
55:33 I think we will probably support the repo HTML that things like pandas data frames already
55:38 returned so that you could, for example, return a data frame and it might not be pretty, but
55:42 you'll get something coming up as HTML and, you know, start ugly and then move on to doing
55:47 those things in an even more powerful way.
55:49 Sure.
55:50 Yeah.
55:51 I didn't even think of the data science side, but there's probably a lot of cool dashboard
55:53 widgets connected to pandas and pullers that are potential out there.
55:57 Yeah.
55:58 And charts and visualizing data is something I don't think is interested in.
56:01 There's no reason why a lot of them couldn't be implemented as fast UI components and then
56:05 displayed.
56:06 Okay.
56:07 We are running pretty short on time.
56:09 I feel like we should probably bring a little more Pydantic to the side and just talk real
56:14 quickly about forms, right?
56:15 What do you think?
56:16 Yeah, absolutely.
56:17 So if you, probably easiest if you share, let me see, share my screen.
56:20 I'll do it from here.
56:21 Cause I can also, it's like the form is pretty boring.
56:24 You can show me behind the scenes.
56:25 Yeah, yeah, yeah.
56:26 It's probably most interesting if we, if we look at the, how the form is implemented in
56:30 the code first, and then we look at what that, what that means for the UI.
56:33 So this is the login form that Michael, you were just showing here that I can show, which
56:37 is a login form with an email address, password, some validation, basically like that.
56:42 Yeah.
56:43 Powered entirely by, again, a completely vanilla Pydantic model.
56:46 And the way that we return that is we return three things, a heading, which is like telling
56:52 the person what we're looking at here in the demo.
56:54 And then this third thing is that it's interesting bit where again, actually the model form is
56:58 again, generic around the Pydantic model.
57:01 And then it takes one other argument, which is the submit URL.
57:03 And that's enough information.
57:04 Right.
57:05 So what you're returning as part of that hierarchy in Python is a model form and you give it
57:11 a Pydantic model.
57:12 And so it looks at the Pydantic class and says, we're going to create like an email
57:17 address and a password field and so on.
57:19 Right?
57:20 Exactly that.
57:21 Awesome.
57:22 Okay.
57:23 And then when you submit that form, it's submitted as form data.
57:26 So as not as JSON data, but as a vanilla HTML form.
57:30 A standard form post type of thing.
57:33 Post form.
57:34 And then we have this, it's this syntax is definitely slightly funky here, but it's how
57:38 we do it in FastAPI.
57:40 We have form, which is annotated as a login form, but it's also got fast UI form, which
57:45 in turn, which also takes login form, all of which looks a bit ugly, but what we're
57:49 really doing in the background is converting form data into the Pydantic model, including
57:56 flattening and deflattening the model in the case where we have nested models, which I'll
57:59 show you in a minute.
58:00 But the result of this is once we, in our, in our post endpoint, we get an instance of
58:05 the login form that we can then go do stuff with.
58:07 If I show you a more comprehensive or complex example, this is big model here becomes big
58:13 form and this has a bunch more stuff in it.
58:15 So it has file inputs.
58:18 File inputs are one of the reasons we can't just submit, submit JSON because yeah, we
58:22 don't want to be part of encoding and all those things.
58:26 Yeah.
58:27 All those things.
58:28 Right.
58:29 And so here we have name.
58:30 We use bold again, as I have before to indicate required fields.
58:34 So we could, I don't know, I've got some Pydantic logos here that I'll use as images.
58:39 This one is multiple images.
58:41 So we can select multiple images, a date field in this date.
58:45 I've got a calendar picker.
58:47 Very nice.
58:48 So that's just input type equals.
58:49 That's just input type equals date.
58:51 Okay.
58:52 We have switches.
58:53 We have, and then you'll see here, we have size model, arrow width and size model, arrow
58:57 height.
58:58 And the point is that we're doing here, and these are integer fields, but the cool bit
59:01 is that they map to a nested Pydantic model within the big model.
59:07 What FastUI is doing internally is basically flattening this into one list of form fields,
59:13 which is then what we get rendered here.
59:14 I see.
59:15 So in your Pydantic model, you have a size object, but then in the form, it just has
59:19 the width and the height, the one after another.
59:21 Size width and size height.
59:22 Exactly that.
59:23 If I put a requirement or a restriction like min or max onto the field in the size model,
59:30 would that become a client side min and max in the form?
59:33 There's a PR to do exactly that.
59:35 Yeah.
59:36 Awesome.
59:37 We will get server-side validation as well.
59:39 And then we'll look at it for a couple of weeks.
59:40 So like it's, there's more to do, right?
59:43 But that's awesome.
59:44 That's really fun.
59:45 Yeah.
59:46 And then you'll see in uploads, we have some quite powerful things we can do here.
59:48 So we use the upload file, which is a starlet type, but we can also annotate it with form
59:55 file, which takes two optional arguments of what rule, what except to apply.
01:00:01 So that will both in the browser, when you open the...
01:00:04 Yeah.
01:00:05 When you choose a file browse dialogue.
01:00:06 Yeah.
01:00:07 It'll tell you what size.
01:00:08 You have a MIME.
01:00:09 So for people listening, you have the MIME typeset, not like an extension, but you have
01:00:11 image slash star, which means image slash JPEG, PNG, WebP, et cetera.
01:00:16 Right.
01:00:17 And that's understood by the browser and then by the OS to let you select files, but it's
01:00:21 also validated server-side.
01:00:23 So if someone goes and edits their HTML and submits a not image, the server-side validation
01:00:28 will check at least based on the file extension that it looks like an image and you get back
01:00:32 the bytes.
01:00:33 So you could also go do validation that the bytes are a valid image if you so wanted.
01:00:37 You could read the bomb, the mark that indicates the file type that's sometimes in these different
01:00:42 files.
01:00:43 Yeah.
01:00:44 If I submit this, but let's say, well, first of all, I try and submit this because we've
01:00:46 got server-side validation of which fields are required.
01:00:49 It won't let me submit if this file field is not completed.
01:00:52 And then I think if we put in name and we don't capitalize it in this case, we'll go
01:00:57 off and do the validation and come back and we'll say name will start with a capital because
01:01:01 I've implemented it.
01:01:02 Where's that validation?
01:01:03 Oh, I see.
01:01:04 That's a function that you write.
01:01:05 Right.
01:01:06 And just to prove the point, I've just written a validator in Pydantic, which says this must
01:01:10 start with uppercase.
01:01:12 And if I then went in here and edited that print out form, is that going to now clear
01:01:18 my form?
01:01:19 No, it's not, which is magic.
01:01:20 And if I submit that, you'll see here where I printed out the form, we got the different
01:01:26 file objects and we got the raw data all come through as the Pydantic model.
01:01:30 Yeah, that's really cool.
01:01:31 And so I love how even the custom validators in Pydantic, like Python code that you wrote
01:01:37 appears on what feels like client side, but is really server side validation run by React,
01:01:43 right?
01:01:44 Yeah, exactly that.
01:01:45 And so we'll do stuff like link checks and all the things you can do on an input client
01:01:48 side as well.
01:01:49 But of course, there'll also be enforced server side, which obviously if you're building anything
01:01:53 that is going to be exposed to the internet, you've got to do.
01:01:56 Yeah.
01:01:57 You should never, never trust what comes into your web app.
01:02:00 It's just put it online for five minutes and look at the log.
01:02:02 It's already trying, somebody is already after wpadmin.php, you know?
01:02:07 Yeah, exactly that.
01:02:08 And then the last thing I'll show, I know we haven't got very long at all, is authentication,
01:02:11 which I've just been working on now.
01:02:14 This is again, it's a simple form.
01:02:15 I'm just going to select an email, put in a random password and I can log in.
01:02:20 And in this case, I've logged in.
01:02:22 It just says who I am and how many people are logged in.
01:02:24 If I come back to this page, it'll show me logged in and I can do post requests to log
01:02:29 out.
01:02:30 And what it's doing internally is, and again, this is the kind of thing that would be lots
01:02:33 and lots of work to implement if you're doing it yourself, is it's storing in session storage,
01:02:38 the auth token, then adding it as a header where we do the fetch from the front end to
01:02:42 the back end so we can effectively store sessions that way.
01:02:46 Oh yeah, very cool.
01:02:47 Yeah, that auth token's coming in as a header item or being set as a header item.
01:02:51 Excellent.
01:02:52 Right, exactly.
01:02:53 Cool.
01:02:54 So yeah, I hope that we've done a bit of a whirlwind tour through FastUI and what's there
01:02:57 now and what I hope is coming up and the slightly philosophy of why I built it.
01:03:02 But yeah, I hope that was interesting.
01:03:04 It's super interesting.
01:03:05 And it's really early days.
01:03:07 I'm looking forward to two things, to see what people go do with it, what widgets and
01:03:10 stuff they build.
01:03:11 So can you drop in, like you said, a calendar or something awesome like that.
01:03:15 And I'm also looking forward to see what you all internally release in a couple of months
01:03:19 from it.
01:03:20 Absolutely.
01:03:21 And thanks so much for having me and letting me witter on about this random library.
01:03:27 Yeah, of course.
01:03:28 Good work.
01:03:29 It's certainly creative.
01:03:30 Maybe just give people a sense of, as we wrap it up, can they use it now?
01:03:35 Should they use it now?
01:03:36 Can they contribute?
01:03:38 Maybe they're interested.
01:03:39 What do you tell that crew?
01:03:40 I'd love people to contribute.
01:03:41 I mean, almost most useful is issues saying how you're using it, where it's working, where
01:03:46 it's not.
01:03:47 There is a bunch of people who've already submitted PRs and continue to do so.
01:03:51 And yeah, I think what works, works pretty rigorously and it's probably better implemented
01:03:56 and tested than lots of private code.
01:03:59 But definitely within internal uses, use it now.
01:04:01 And like I say, Pydantic is building things with it now.
01:04:05 So look, I mean, I give the open source guarantee that it's relatively safe, which is the guarantee
01:04:11 that means nothing.
01:04:12 But mostly because at the end, it's just defining how you build your UI and how you implement
01:04:17 your session authentication.
01:04:19 It's not having strong opinions about that.
01:04:20 So yeah, I think it's, I think it's the place where people should go and try it and give
01:04:24 feedback.
01:04:25 Excellent.
01:04:26 All right.
01:04:27 Well, thanks again for coming on the show.
01:04:28 Looking forward to talking to you next week.
01:04:29 No, just kidding.
01:04:30 Like two in a row, I suppose.
01:04:31 Looking forward to talking to you 2024.
01:04:32 Absolutely.
01:04:33 Have a good Christmas.
01:04:34 Thank you so much.
01:04:35 Yeah.
01:04:36 Thanks.
01:04:37 Bye.
01:04:38 This has been another episode of Talk Python to Me.
01:04:39 Thank you to our sponsors.
01:04:41 Be sure to check out what they're offering.
01:04:43 It really helps support the show.
01:04:45 This data is professional web scraping and a dataset marketplace.
01:04:49 If you need data and it doesn't have an API, check out talkpython.fm/brightdata today.
01:04:58 Take some stress out of your life.
01:05:00 Get notified immediately about errors and performance issues in your web or mobile applications
01:05:04 with Sentry.
01:05:06 Just visit talkpython.fm/sentry and get started for free.
01:05:10 And be sure to use the promo code talkpython, all one word.
01:05:14 Want to level up your Python?
01:05:16 We have one of the largest catalogs of Python video courses over at Talk Python.
01:05:21 Our content ranges from true beginners to deeply advanced topics like memory and async.
01:05:26 And best of all, there's not a subscription in sight.
01:05:28 Check it out for yourself at training.talkpython.fm.
01:05:31 Be sure to subscribe to the show.
01:05:33 Open your favorite podcast app and search for Python.
01:05:36 We should be right at the top.
01:05:37 You can also find the iTunes feed at /itunes, the Google Play feed at /play, and the Direct
01:05:43 RSS feed at /rss on talkpython.fm.
01:05:47 We're live streaming most of our recordings these days.
01:05:50 If you want to be part of the show and have your comments featured on the air, be sure
01:05:53 to subscribe to our YouTube channel at talkpython.fm/youtube.
01:05:58 This is your host, Michael Kennedy.
01:05:59 Thanks so much for listening.
01:06:01 I really appreciate it.
01:06:02 Now get out there and write some Python code.
01:06:05 [MUSIC PLAYING]