#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,
00:13 rapid application development style of building Python apps to the web.
00:18 Those can be great, and I've covered a couple of them, but they usually reach a limit on what you can do
00:24 or how they integrate with the larger web ecosystem.
00:27 On this episode, we have Samuel Colvin back to share his latest exciting project, FastUI.
00:33 With FastUI, you can build responsive web applications using React without writing a single line of JavaScript or touching NPM.
00:41 Yet designers and other tools can focus on React frontends for a professional spa-like app experience.
00:48 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:12 This is your host, Michael Kennedy.
01:14 Follow me on Mastodon, where I'm @mkennedy, and follow the podcast using @talkpython, both on fosstodon.org.
01:22 Keep up with the show and listen to over seven years of past episodes at talkpython.fm.
01:27 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 part of that episode.
01:40 This episode is sponsored by Bright Data.
01:42 Bright Data is professional web scraping in a dataset marketplace.
01:46 If you need data and it doesn't have an API, check out talkpython.fm/Bright Data today.
01:53 And it's brought to you by Sentry.
01:56 Don't let those errors go unnoticed.
01:58 Use Sentry like we do here at Talk Python.
02:00 Sign up at talkpython.fm/sentry.
02:05 Hey, Samuel.
02:06 Welcome back to Talk Python to me.
02:07 Thank you.
02:08 Thank you very much for having me again.
02:09 So soon after last time.
02:11 It's always amazing to have you on.
02:12 In fact, you were on just last week in a really cool show that tons of people enjoyed
02:19 and is not yet out at the time of recording, but will be released to the world
02:23 by the time your show goes out live.
02:25 So it's a bit of a time travel thing.
02:27 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, right?
02:40 And you snuck in for a minute there on your travels.
02:44 But now you're back and we're here to talk properly about something really excellent
02:49 that you put together called Fast UI, which is going to be a lot of fun.
02:53 Yeah.
02:54 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:01 somewhere in Istanbul.
03:03 So yeah, it's nice to be there.
03:04 High marks for effort there.
03:06 Come on.
03:06 That was great.
03:07 It was good fun, but this is a better place to talk about these things.
03:12 Yeah.
03:12 Well, I hope you had a good trip and you're back in at it.
03:15 Kim out in the audience points out, hey, could you just write another impressive tool for
03:19 the next week's show?
03:20 Because things are going pretty prolifically over there.
03:23 Tell people a bit about Pydantic, the company they probably heard of the library, but just
03:27 what are you up to these days?
03:29 So Pydantic's obviously been around since 2017 originally, but then it's like something weird
03:34 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 5 million downloads then and we're now at 130 million.
03:43 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.
03:58 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.
04:06 Having originally told people it would take me alone three months, it took me and I guess
04:10 then six people a year in total.
04:12 But that was released back in the summer.
04:15 And now we're working on a platform that I'm not going to talk about now, but I would love
04:19 it if you'd have me back, I guess, beginning of Q2.
04:22 Is that next week or whatever?
04:24 It's not quite next week.
04:25 Q2 in 2024?
04:27 Something like that?
04:28 Yeah.
04:29 I think we're going to try and get to Open Beta in Q1.
04:32 So yeah.
04:33 Okay.
04:33 Fantastic.
04:34 Yeah.
04:35 Well.
04:35 But off the back of, so that without getting as much details on it has platform component
04:41 to it.
04:41 And so we have people, people will be logging in, et cetera, et cetera.
04:44 And I was just thinking about all of the path and the churn of building the relatively mechanical
04:50 bits of an application.
04:51 Again, it doesn't matter actually if you're building it with React or with one of the other
04:55 front-end frameworks, you end up having a whole bunch of stuff that's duplicated between
04:59 what the front-end guys are doing and what the full-stack developers or the back-end developers
05:04 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 of lots of
05:09 those bits.
05:09 And I was just dreading all of that churn.
05:12 And I had been wanting to build something like Fast UI for a long time, but the fact that we're
05:16 going to be using it internally really spurred me on to go and get it built and release it
05:21 in like a very incomplete phase to see what people thought.
05:23 And yeah, there's been a great reaction.
05:25 And here I am.
05:26 Yeah, there has been quite the reaction to it.
05:28 Let's see.
05:29 Do the GitHub star test.
05:31 It's 2.6 thousand stars and it's what?
05:36 Two weeks old?
05:36 Yeah.
05:37 A month old?
05:37 Yeah.
05:38 A month old?
05:38 Last month anyway.
05:39 Well, it was only released publicly like, yeah, two weeks.
05:42 Less than two weeks ago.
05:43 Or maybe two weeks ago today.
05:44 Oh, that's right.
05:45 Yeah.
05:45 You probably, so you worked on it a little bit private and then you flipped the bit on the
05:50 public status.
05:50 Yeah.
05:51 That makes a lot of sense because you don't want people just to go, whoa, what are they building?
05:54 I mean, maybe you do.
05:55 What is this GitHub repo?
05:56 They misspelled FastAPI.
05:59 I don't know what they're working on.
06:00 Yeah, exactly.
06:02 And also, I mean, we have a team with lots of people who've done lots of open source, very
06:06 strongly opinionated engineers.
06:08 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 this
06:15 thing.
06:16 Let's at least give it a try.
06:17 Yeah.
06:17 Because I don't know.
06:18 Maybe I'm wrong in this.
06:20 But I think it's quite a fundamentally different way of thinking about how you build user interfaces
06:26 from lots of the tools that exist today in the Python ecosystem.
06:30 And so there's a bit of a like education piece and trying to understand the principle as well
06:35 as the like mechanics of going and using it.
06:37 Yeah, absolutely.
06:38 Well, we're going to dive into the philosophy, but I'll give people that too long didn't read
06:43 version.
06:43 Basically, you can create UIs in pure Python in sort of dynamic web framework friendly ways.
06:50 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 fast UI is powerful and where we're using it in within the
07:01 pedantic team is actually we have got front end developers.
07:04 We've got some really expert guys like who are very comfortable building stuff in react.
07:08 But we want to those two roles to have to constantly communicate to build every every
07:13 individual bit.
07:14 So the idea is I think if you go down the page a little bit, I kind of explain it.
07:18 But like for a front for a Python developer, it's this way of building UIs without having
07:22 to touch TypeScript or JavaScript or NPM or any of those Byzantine like massive build tools.
07:28 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 back end guys to go and build
07:38 a 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:44 which is allow which is provide these like reusable components.
07:47 Yeah, absolutely.
07:48 Kind of a framework as well to bring the navigation and the cohesion of the whole app together,
07:53 not just a particular view or a page to what you would say, right?
07:56 Yeah.
07:56 Yeah.
07:57 So the weird bit is principle of RESTful interfaces.
08:00 We've all heard of RESTful and we all think we know what it means, which is basically something
08:05 to do with a URL structure and return me some JSON that like gives me the data I need to render
08:10 my view.
08:11 Well, if you look at the rifle that Roy Fielding's original PhD, as is brilliantly described in
08:16 this HTMX article that I talk about further on down here.
08:19 He's not really talking about that stuff.
08:21 Sure.
08:21 He has some stuff on what the URL structure should be.
08:24 But really, his principle is that the data returned from the back end should be self-describing
08:30 as if it should have everything 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:38 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 well.
08:47 I think if we follow that, yeah, I think they'll even on that page, there's a very jokey tone
08:51 lots of the time HTMX, but they also talk about a really cool thing.
08:55 Yeah, absolutely.
08:56 Somewhere I think they have, yeah, here we are, right?
08:57 So if you look at the traditional JSON response, which I think is the second one, and you were
09:01 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:08 But there was not enough.
09:09 It's got like an account number and a balance, which is a more complicated object, nested object
09:13 and those types of things.
09:15 Right.
09:15 It's got all the things that we can read account number.
09:17 Cool.
09:17 That's a number balance.
09:18 Yeah, that makes sense.
09:19 But if you're a computer, there's not enough there to go and render someone the nice user interface
09:24 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:32 you then need to go and have lots of very application specific or page specific logic to show where
09:39 the account number goes and where the balance goes and where the status goes and stuff like
09:42 that.
09:42 And that causes an enormous amount of churn.
09:44 And it means that it's particularly difficult when you have those engineers working in different
09:48 time zones because you end up having this 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:56 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 back in guys to go and add that to endpoint.
10:09 And then the front end, and that can be deployed.
10:12 And then the front end can be updated to show that and the data is available.
10:15 That is a lots of churn, lots of delay.
10:18 Right.
10:18 Lots of coordination between the two domain experts.
10:22 And then it kind of, you've got that microservice cascading, like it's got to do, then this one's
10:26 got to be upgraded.
10:27 And then eventually there's enough flow of data through the system that the UI people can put
10:32 it up there.
10:33 Right.
10:33 Right.
10:33 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 form where every field in the form needs to be completed, 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 Pynantic model that, you know, depending on how we've done it, probably
10:56 is used to define our form.
10:57 And it might even be used to define our database.
10:59 But like, we're not using a Pynantic model in the front end.
11:02 TypeScript, in my opinion, is a big Achilles heel in typing is that you don't have any, you
11:07 can't use type ins at runtime.
11:08 And so we don't have an equivalent of Pynantic.
11:12 And so we're basically trusting that data is how it is.
11:14 So yeah, FastAPI is an attempt, sorry, Fast UI is an attempt to basically remove that
11:20 need to like have complete synchronization between backend and front end by having beautifully
11:25 designed components in the front end.
11:27 Not saying what we have now is that beautiful, but that's the ideal log 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:39 Excellent.
11:40 Nice comment from Tony on the audience.
11:42 As I originally started in Python and went to using TypeScript, Pynantic made the transition
11:46 back to Python so nice.
11:48 And so in your description, you also have up here that this Pynantic is interesting,
11:54 is involved here.
11:55 Like what is the role that Pynantic plays in defining all this?
11:58 So the idea is that we're getting to, of this RESTful UI is really that we end up having a
12:04 bunch of components in a shared definition of some components.
12:08 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 Well, that's all very well, but if you're not careful, you end up not sending quite the
12:19 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 Pynantic models.
12:26 So Pynantic goes off and does not only the validation, but also the coercion.
12:31 And it does stuff like uses camel case.
12:33 So the front end developers are happy because we've got no underscores anywhere.
12:36 And so, yeah, all of the backend code for fast UI basically is just Pynantic models, which
12:44 implement these components.
12:46 Right?
12:47 So it might be useful for those who can see this to go in and I can talk through an example.
12:51 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 useful.
12:56 I showed it here.
12:57 So I've 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 and
13:08 we can look at like a really simple component, probably a button, which would be kind of understandable
13:13 to everyone.
13:14 Where's button?
13:15 Here we are.
13:15 So this is just a plain Pynantic model, which contains text, which is the text you put within
13:20 the button.
13:21 Then it contains the event that you want to fire when someone clicks on it.
13:24 And HTML type, which, you know, this matches what you can get in HTML button, reset, submit,
13:31 and then class name, which 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:45 And it's also used by a big switch statement in the TypeScript to basically decide what component
13:51 I'll go and render when I get an object.
13:54 Right.
13:55 So there's some TypeScript.
13:57 Maybe it makes sense to talk a bit about the building blocks.
14:01 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:07 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.
14:14 Yep.
14:14 And then we have NPM package called FastUI.
14:17 Again, it's in the Pydantic organization, which is where the meat of the logic resides.
14:23 And that's implementing basically the most of the components and all of the wiring to mean
14:29 that when I return a button, the button component gets rendered.
14:33 And then, but obviously, we don't probably want to end up using a vanilla button when we come
14:38 to display it.
14:40 So then I've implemented basically customization of the FastUI React library using Bootstrap.
14:45 So 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:55 So the modal in the default FastUI, the end package just basically shows me alert saying
15:01 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 builds it.
15:14 And that means we can go and basically return that prebuilt React app without having to get
15:20 our hands dirty with NPM on Yarn and Vite and all the other.
15:24 All the webpacky 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:33 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:40 perfectly well be, and really nicely, I just merged this the other day, we now use the JSON
15:46 schema generated by Pydantic and JSON schema generated by the React types to basically go
15:53 and test that there's an equivalent between those two 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 with something like HTML and HTMLX.
16:04 Or even you could go and use React Native and build, 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:20 And in theory, you don't 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 or whatever back end
16:29 can then communicate.
16:30 Whether that comes to pass, I don't know yet.
16:32 And obviously, I built the default back end in Pythin, because that's what I know best,
16:36 and where I think Pydantic is really helpful.
16:38 And I built the first front end in React and TypeScript, because one, that's what I know,
16:43 and two, it's what we're using within Pydantic.
16:45 But 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 fast UI in Vue, because I don't think it adds
16:55 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:04 That's interesting.
17:05 So first point is, these different components sound like they are potentially a little mix
17:11 and match.
17:11 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 endpoint.
17:20 Yeah.
17:20 I think it's something like, it'll be slightly skewed now because of tests, but I'd say it's
17:26 sort of twice as much front end to back end at the moment, as in the, yeah, it's skewed
17:30 a bit by tests, 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:41 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:46 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
18:08 incorporates building the UI in Python and validating and enforcing that with Pydantic
18:14 rather than just, 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 stuff,
18:26 just let's write Python, right?
18:28 So maybe you have a simple example of what it looks like to define a real simple example
18:34 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 the Python
18:44 abstract syntax tree, I guess, right?
18:48 And visually as well, the way you look at the code, it looks like the way it might look in
18:53 HTML.
18:53 Like give us a sense of what writing a UI in this would look like.
18:57 Right.
18:57 So I think the first of all, we have to talk about like the two enormous, the two most obvious
19:01 pitfalls for this.
19:02 One end of the pitfall you have, which I think is the biggest temptation is to basically mirror
19:09 all of HTML in Python.
19:11 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 going
19:19 to be a pig because I don't want to have to define every A, HRA, and everything else in
19:24 Python code.
19:25 It says, and there are going to be, it requires for a start, it requires you to know two things,
19:29 Python and HTML.
19:30 Whereas for HTML, you only need to know one.
19:34 This portion of Talk Python to Me is brought to you by Bright Data.
19:38 Bright Data helps you turn websites into structured data.
19:42 There's an unimaginable amount of data available on the internet.
19:46 And we're lucky to live in a time where we have so many APIs to access structured data.
19:52 But the truth is that most of the data out there is not served up over a clean API.
19:58 It's just sitting there on a web page as HTML.
20:01 Maybe it's even further obscured behind some front-end JavaScript framework like Vue or React.
20:07 What if you need access to that data?
20:09 Web scraping to the rescue, right?
20:12 Yes, but just like you wouldn't set up your own production infrastructure in your home office,
20:18 running a web scraping job on a single computer at a fixed location can lead to a web
20:22 your program being unreliable with data pinned to that IP's location and much of the time
20:28 blocked for rate limits and other such causes.
20:30 If you need to do professional web scraping, Bright Data is the place to start.
20:35 They have award-winning proxy networks and powerful web scrapers.
20:39 What's more is they have ready-to-use datasets for download, so you might not even need to scrape data at all.
20:46 And if you can't find the dataset in their marketplace, they'll even build a custom dataset for you.
20:52 From listening to the show, you know that I'm a privacy-conscious person,
20:56 and that's why I'm happy to see that they are both CCPA and GDPR compliant.
21:01 Bright Data has both low-code solutions as well as Python programming models with Async,
21:07 IO, and Playwright.
21:08 So if you have serious data needs and those websites don't offer APIs, then you need Bright Data.
21:15 check them out today at talkpython.fm/brightdata.
21:19 And please use that URL.
21:21 That way they know you heard about them from us.
21:23 That's talkpython.fm/brightdata.
21:27 The link is in your podcast player show notes.
21:28 Thank you to Bright Data for supporting the show.
21:32 I always find these things that try to dodge, like dodge the fact that HTML exists.
21:37 I find them, I don't know, I just, they don't resonate with me.
21:40 I'm not entirely sure why.
21:42 It's like, we have really nice things like CSS, and we have really, there's just so much tooling and frameworks,
21:50 you know, you mentioned Brutestrap already, right?
21:53 That just plug into there.
21:54 And if it's like, well, we're just going to write, recreate it in Python.
21:57 Well, it has all the oddities of HTML if it's going to be really high parity.
22:02 And then you just have a less well-known way to do the same weird thing.
22:06 You know, I don't know.
22:06 It 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 you work out what you need to do in SQL.
22:15 Then you try and translate back from SQL to ORM, and it would be much nicer just to write my SQL.
22:21 I mean, not always the case.
22:22 ORMs can be powerful, but I think that they both can fall into the same trap if you're not careful.
22:27 And then I was going to say, at the far end of the spectrum, the other end of the spectrum, you have, and I guess Django's admin view,
22:33 for understandable reasons, could suffer from this, that you basically have a very small set of things.
22:36 You have a table page and a details page and a form page, and that's kind of it, right?
22:41 So there's this difficult trade-off, and where in that continuum do we try to choose what size of component to implement, right?
22:48 So for example, here we have a heading, which is almost one-for-one matches what you 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 different syntax,
22:59 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:13 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 do them,
23:26 where I think a framework like Fast UI gets super powerful, because we can get you a table here 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, then we could go write out all the HTML for that.
23:43 And it's much more concise to read.
23:45 It's like, it's consistent enough that something like GitHub Copilot will help you write it out
23:50 where you do have a bit of customization to do.
23:52 I think this is where it can be super powerful.
23:55 Yeah, it is pretty interesting.
23:56 And I like the hierarchy.
23:57 For people listening, just check out github.com/pydantic slash fast UI.
24:02 The example right there on the page.
24:03 But what you do is you create a, in this case, a FastAPI, API endpoint, and then you return a hierarchy of elements out of fast UI.
24:12 So we have a page.
24:14 The page has components.
24:15 The components are a list of a header and a table.
24:18 The table has data, which maps over to a list of pydantic models, which then help 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 Yeah.
24:31 And obviously we can add other components like pagination that works.
24:34 I think just to come back to the top, to how we do these views.
24:38 The very simple, and it's most simple what fast UI's React app does, is it basically takes whatever the URL is you go to.
24:45 So in this case, you might go to slash, to the base URL, and it prepens slash API and makes a request to that endpoint to basically say,
24:54 what should I render?
24:55 And it gets back.
24:56 So here we're basically returning a list of pydantic models.
25:00 All that the fast UI model is really doing is taking that list of pydantic models
25:05 and calling model dump JSON on it to get the JSON that we return to the front end.
25:10 And as I say, the front end then knows how to render each of those, each dictionary in the list is what it is.
25:17 At its core, it's a list of objects to use JavaScript parlance.
25:21 It just knows how to render each of them and renders each of them in turn.
25:24 And then obviously they can then have nested other models, all of which it knows how to render.
25:29 Yeah.
25:30 It reminds me of a couple of things.
25:31 I have an example.
25:33 Is this?
25:33 No.
25:34 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:44 but then it has JavaScript arrow functions, right?
25:49 But it has the same nested feel, right?
25:51 Did React inspire you to create it this way or not really?
25:55 Yeah, it did.
25:55 I've done quite a lot of React and I like it a lot.
25:58 I know as a popular piece of technology, there were lots of people who like to berate it,
26:05 but I do think React has been a powerful step forward.
26:07 And the greatest form of flattery is copying.
26:11 There are enough other, like, sure, there are other more powerful, arguably more powerful, arguably more performant,
26:17 new front-end libraries, but everything is component-based now.
26:20 Like, you know, React has changed the, there was a sea change in how we did front-end
26:25 with that component architecture.
26:26 And JSX, similarly, is super powerful.
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 context or a switch
26:39 or something that is not typically known in HTML.
26:41 And these are higher order building blocks in the UI space, right?
26:45 So when people think about what they're creating here in Python, it's not just the fundamental DOM objects and elements, is it?
26:53 Right. So that is actually, yeah.
26:55 So page here is a bit of ambiguity about how we're going to define a page.
26:59 Like default implementation does something reasonably sensible.
27:02 It like, you know, pads it, et cetera.
27:04 But like heading isn't, there isn't much to do really.
27:07 You're going to return a heading, but when you come to a table, there's a lot of debate 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 the,
27:17 how exactly that's implemented is, you know, in some sense it's completely the choice
27:21 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 it doesn't
27:27 and shouldn't be like each HTML tag is written out.
27:31 Because as I say, I think that would be a like obvious failure mode for this.
27:34 Yeah.
27:34 The other thing this reminds me of, by the way, just for people out there listening is
27:39 that it looks a lot like a Flutter.
27:42 If people have done any Flutter, you've got these widget hierarchies.
27:46 You build them, you maybe set some properties, you add in a bunch of, a bunch of elements, you know,
27:52 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.
28:02 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:09 the Rust bit of Pydantic, is effectively not entirely different to this, right?
28:13 You define these nested structures of different validators.
28:17 Everything at its core is a like combined validator, which is in Rust terms,
28:22 an enormous enum of all the different types of validator, some of which have nested within them,
28:26 more and more validators.
28:27 And that's how you build up nested structures of Pydantic models, which in turn is what these are.
28:33 We're getting there.
28:33 Yeah, the validators in the UI, they kind of like have a similar structure.
28:37 A bit of a sidebar, just a bit of a piece of code in here.
28:40 You've got table, which is a class, square bracket, user, which is another class,
28:46 square bracket.
28:47 I imagine that you and your team are deeper into the Python type system than the vast majority of others out there
28:55 with all the work with Pydantic and the interoperability with Rust.
28:58 What is that?
28:59 Tell people about this.
29:01 Yes, a table is a generic.
29:02 So if you, you can imagine if you were doing list events, you would do list,
29:06 square bracket, int.
29:07 And that's basically the point is that list is a generic around its elements.
29:13 Same as a dict is generic around its keys and its values.
29:16 Well, table here is generic around the Pydantic model that you're using to,
29:21 using for each row.
29:22 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,
29:43 even if data was 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 doing fancy things with Python types.
30:00 That is definitely occupational hazard of what we do.
30:02 Yeah.
30:02 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,
30:10 it was, it was unnecessary.
30:11 So you can definitely do too much, such a thing as too much Python typing.
30:15 Yeah.
30:15 Yeah.
30:15 Yeah.
30:15 Yeah.
30:15 For sure.
30:16 It is pretty interesting.
30:17 So let's maybe talk about some of the examples.
30:20 Actually, before we do, just give us a sense of where does this fit in the UI space for Python?
30:27 On one hand, we've got Flask, Django, FastAPI, returning HTML, et cetera,
30:33 where it's all on you.
30:36 you're doing all the five languages of web apps, SQL or some query language,
30:41 Python, JavaScript, CSS, some other tools, right?
30:45 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 dropy sort of thing,
30:55 which is, is really neat, but it fits into a kind of a, 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.
31:05 We've seen a lot of these like, get me a UI more quickly.
31:08 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,
31:14 but then there's places where Python goes to make it dynamic, right?
31:18 So where in that spectrum would you put fast UI as it is today?
31:23 Interestingly, and one of the reasons I wanted to come and talk to you was I heard your,
31:25 you were, you were talking the other day on, on your other podcast and I heard you talking about fast UI and kind of,
31:32 I'd say categorizing it into that, that group.
31:35 And what I wanted to kind of, one of the things I wanted to come and say was,
31:37 yes, we can do that.
31:39 But the, the use case we have within Pydantic is actually to go and build a pretty complex,
31:43 fully fledged application with, with front end developers building components,
31:47 but just get rid of that churn.
31:49 Right.
31:49 Something more like Gmail, less like, here's a table that I can click on and see some related table.
31:56 Right.
31:56 Exactly.
31:56 And what I should probably put in the demo and probably where Pydantic is people most associated
32:01 and where it's, this is going to be most useful is within forms.
32:05 So I don't know if you want to go to the, to the demo and I can talk people through,
32:08 but like within fast UI is dedicated to forms.
32:12 We can do things like nested Pydantic models all become components within a form.
32:17 And obviously we can do client side validation with a whole bunch of stuff,
32:20 but we can also do server side validation, but then we get all the fancy stuff.
32:24 Like if the, if the data is invalid and you get a validation error on the,
32:29 on the server side, we'll then basically re-render the form with the errors in place.
32:33 All that stuff that like anyone building a web application has to go and implement some version of it.
32:38 At the moment there's, there are some, some react libraries that will build you a form from JSON schema,
32:44 but they don't perfectly fit in with, with what Pydantic does or with, with FastAPI.
32:48 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 to build our web applications completely with Django
32:59 because it's, it's pretty all or nothing despite the wonder that it's Django.
33:03 And so that's the kind of space where for me, this, this like becomes a really stands out because what would have been to do it properly?
33:12 It's days of work to get form, to get form submission to work, get client side validation,
33:16 server side validation, get the redirect after your form.
33:19 None of that stuff is, is entirely trivial, even for those of us who've done it before.
33:22 Whereas with the theory is with fast UI and in, although fast UI does not require FastAPI,
33:29 the form stuff is, is quite tightly integrated with FastAPI.
33:33 and you can get, yeah, a really good experience of building, building stuff like forms.
33:37 I think that, that where the alternative really today is, is to use no disrespect to any of the fast libraries or any of the other things.
33:45 But I think the only real alternative right now is implement it yourself or use Django.
33:50 Yeah.
33:50 But I do also want to, but maybe before we get to that, let's try to take a little survey of what are these widgets,
33:56 these building blocks that you can use.
33:58 Yeah.
33:58 Is that right?
33:58 Yeah, absolutely.
33:59 I think I can find them here.
34:01 Yes.
34:01 Yeah.
34:02 So you've got a fast UI demo, which I'll link to at onrender.com prefix,
34:07 but you talk about some of the things that you can just create in that Python hierarchy
34:13 that you return that builds up your UI there.
34:17 So maybe we talk us through some of the things that are here.
34:19 Yes.
34:19 We have the kind of generic markdown component, which will go up and renders a markdown.
34:24 This table itself is, is implemented using the markdown component.
34:27 Just a one side note, the markdown and the code, because they have quite a lot of JavaScript associated with them,
34:33 but they're actually lazily loaded to make the, make the prebuilt fast UI app faster to load.
34:38 Then we have text, probably the simplest one of all, just render some text paragraph.
34:42 Again, very simple page titles, a slightly funny one.
34:46 It doesn't actually display anything on the page, but it changes the, the browser title.
34:50 So what you see in the tab at the top of the page, 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:56 And like, it takes a little bit of integration there.
34:58 Yeah.
34:58 Right.
34:59 Exactly.
34:59 Heading again, very simple, like one to six HTML heading code, bit more sophisticated.
35:05 And if you click on code, maybe, maybe those who can see it will be able to click through code.
35:10 Yeah.
35:10 So code is there.
35:11 We, we get a like highlighted bit of, a bit of source code displayed.
35:15 It's color coded with like class types, having a color and keywords, having a color.
35:20 That's nice.
35:21 Like you would see in, in GitHub or something like that.
35:23 So again, just, just like work out the box.
35:25 Then we have some components like a link list and link, which are used in other components mostly.
35:30 So if you, the nav bar, you see at the top of the page there that uses a link list.
35:34 And 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,
35:40 which loads a dynamic modal.
35:42 So that when the modal loads, it will make a request to get the content.
35:45 You want to see within that modal.
35:47 So that could be a form or it could be customized depending on, on the form in the page.
35:51 Then we have loading content from the server, which is the same thing we were doing in the modal,
35:55 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 side events to basically
36:04 dynamically update a react component.
36:06 If you weren't using that.
36:08 So your server load SSE widget that provides, like you said, server sent events,
36:14 which I don't know how many people are familiar with SSE.
36:16 I'm sure they're familiar with web sockets and they're familiar with just
36:20 like a JavaScript event, but this is like an intermediate sort of lightweight one directional,
36:24 but the normally the opposite in reverse, I guess from the server to the client sort of pushing out stuff.
36:29 Right.
36:29 So that's a really powerful thing.
36:31 And if it's, if it's that easy to just hook a function call when something happens,
36:35 that's pretty cool.
36:35 One of the things I want to try with SSE that I think will work really nicely is LLM responses where you get like one token at a time
36:42 because you don't want to wait for the whole thing.
36:43 Yeah.
36:43 The center events would be perfect for basically printing out the response
36:47 from an LLM.
36:48 And again, it would be like, you know, 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 pure JavaScript or react or whatever framework.
36:58 Yeah.
36:59 And we have, have iframe, which again, kind of map, we're back to kind of mapping one-to-one to a component.
37:04 One of the nice things to say about both iframe and image is they were by other people.
37:09 So I don't think I'd even created an issue asking for them, but people have come along 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 my initial release,
37:20 or sorry, the second release of fast UI.
37:22 So yeah, good engagement from lots of people.
37:24 Image.
37:24 Yeah.
37:25 So you've got a bunch of UI stuff here and it just, as I look at this and I see what you're building,
37:30 it just makes me think of like, wow, there's an opportunity for stuff like,
37:34 like what you get out, not necessarily the same as, but like what you get out of say tailwind UI,
37:39 where the things you might work with are on off switches, you know, like toggles,
37:44 like you might see in your phone or other sort of elements that have like
37:48 a lot of design imbued in them that people can just grab and use almost like a Django philosophy for the front end in a sense there.
37:56 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,
38:06 like calendar completely obvious choice, right?
38:09 Complete faff to go and implement that yourself in HTML.
38:12 Commonly used trivial to define because, because the definition, there aren't that many different things to define.
38:17 You, you choose your month, you know, most of us are on the Gregorian calendar,
38:21 right?
38:21 We're not, we're not going to have to change too much what calendar we're going to render.
38:24 So yeah, that's a perfect example of the kind of thing.
38:27 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 company and you want to go and customize it,
38:39 you can totally do that.
38:40 And you can have a front end developer go through and implement the classes that basically customize,
38:44 customize the look.
38:45 I wanted to come back just and show you some of the, some of that, some of the other components.
38:49 So we were on, yeah, this one.
38:51 Yeah.
38:52 I don't know if we have anything more below that, but I would love to show you the tables because the tables and the forms are really where it comes into.
38:58 So cities is probably the best example.
39:00 Cities is the one.
39:00 Okay.
39:00 Yeah.
39:01 Awesome.
39:01 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, start searching like UN or something,
39:13 you'll see we're doing 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, use some like, whatever, this is a list of countries.
39:25 So if you do like, all countries, sorry, I'm typing in cities.
39:27 Good.
39:28 Like UN, United Kingdom and United States.
39:30 Yeah.
39:30 Perfect.
39:31 There you go.
39:31 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:37 Building this and wiring it all up and using one of the, we use react select here,
39:42 but you can use select two or one of those components.
39:44 It's not trivial.
39:45 You need to also set up the backend.
39:47 You need to set up, there's like a few hundred lines of react dedicated just to setting up those,
39:53 those 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 UI pretty trivially.
40:00 Secondly, if you go to the bottom of the page on cities, you'll 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 internal
40:10 endpoint, for example, to show all of your users doing all that pagination and like wiring all that
40:15 up is not trivial, but we effectively do the work for you to have that component and do the maths of
40:20 which page we're on and stuff like that.
40:22 Nice.
40:22 I want to like reiterate, this is the fast UI is not just designed as a kind of Django admin interface
40:28 alternative.
40:29 We within financing are going to go and use it for UI that we're going to show
40:33 to end users.
40:33 But obviously it also comes into its own when people want to just get something
40:37 up quickly.
40:40 This portion of talk Python to me is brought to you by Sentry, you know,
40:43 Sentry for the air monitoring service, the one that we use right here at talk Python.
40:46 But this time I want to tell you about a new and free workshop.
40:51 He means the Kraken managing a Python monorepo with Sentry.
40:55 Join Salma Alam Nayor, Senior developer advocate at Sentry and David Winterbottom,
41:00 head of 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 that powers
41:13 the Kraken utility platform.
41:15 In this workshop, David will share how his department of 500 developers who deploy around 200 times a day
41:22 use Sentry to reduce noise, prioritize issues, and maintain code quality without relying on a dedicated Q&A team.
41:28 You'll learn how to find and fix root causes of crashes, ways to prioritize the most urgent crashes and errors,
41:35 and tips to streamline your workflow.
41:37 Join them for free on Tuesday, February 27th, 2024 at 2 a.m.
41:42 Pacific time.
41:43 Just visit talkpython.fm/sentry dash monorepo.
41:47 That link is in your podcast player show notes.
41:49 2 a.m.
41:51 might be a little early here in the U.S., but go ahead and sign up anyway if you're a U.S. listener,
41:55 because I'm sure they'll email you about a follow-up recording as well.
41:59 Thank you to Sentry for supporting this episode.
42:02 If we have a design language or something like that, or even using a framework,
42:08 I mean, you mentioned Bootstrap, but Tailwind or Bulva, 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,
42:17 how easy is it to sort of bring in those elements there?
42:21 So if I show you here on Bootstrap, to ask you how we customize it with Bootstrap,
42:26 which 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 pre-built version.
42:33 So this, this is obviously the pre-built version of Fast UI you can get,
42:37 but it's actually 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.
42:46 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
42:56 classes and we 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 the classes,
43:04 you'll see that at its core, it's just this big old switch.
43:07 So this is all 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 and all the different things.
43:21 Yeah.
43:21 Based on the switch, we just go through, and this is all just like defining the classes we want for all of the
43:26 different components.
43:27 Some of them depending on the exact state of the component.
43:29 So all of these form inputs, we customize them depending on which type they are and on which mode we're in,
43:35 et cetera, et cetera.
43:36 But it's, it's all very mechanical, just like laying out the classes we need for each and each individual case.
43:41 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, nav bar, modal and pagination,
43:51 we define our own, custom react components.
43:54 So here's the one for nav bar where we use a bunch of bootstrap types to render a bootstrap nav bar.
44:00 So you can basically create a react component that has all the settings necessary to create a nav bar in tailwind or whatever.
44:08 Right.
44:08 And then just plug that stuff in.
44:10 So, so if you wanted to use tailwind, what's this like 20, it's like a hundred lines of code to define all of the classes and it's pretty mechanical code,
44:18 right?
44:18 So it would be, it wouldn't be hard at all to go and use tailwind, it wouldn't be hard at all to go and use tailwind,
44:21 tailwind CSS.
44:22 And then you might want to define a few of your components specifically.
44:26 Yeah.
44:26 But actually modal, modal, I think is the only one that really requires it to be custom implemented because the default just shows you an alert because there's nothing.
44:33 Right.
44:33 JavaScript.
44:34 The page says, it's like, oh, no, the page doesn't say this isn't going to work.
44:38 Yeah.
44:39 So, yeah, I think this is one of the bits I'm most proud of here is that like how much you could customize it and how simply you could start to customize it.
44:46 Right.
44:46 Those are really like kind of pluggable or extensible.
44:49 So you don't have to, you know, 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:57 And so, yeah, and all of the types, it's all typescripted.
45:01 So you, the type should do a lot of help telling you what, what you can implement.
45:04 The last thing I'll show you is, yeah, so here in the default build, as I said,
45:09 we, our custom render function is not just a bootstrap one.
45:12 We do one special thing, which is where we, we have this idea of a custom component,
45:18 which 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 hit take custom.
45:26 And if the subtype is cow say, we render that as a particular block, like use this,
45:32 this component here.
45:33 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, look at that component here.
45:42 Yeah.
45:42 We've got this like slightly silly example of a custom component of cow say,
45:46 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, for the fallback 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:03 Yeah.
46:03 This looks like something that one person could take one for the team, create a tailwind or a whatever generator,
46:10 class name generator, and then put that as either a contribution or put it up on GitHub.
46:16 And then you just, you're kind of good to go.
46:18 Yeah.
46:18 I think we might, we might actually do it.
46:20 We're, we're using tailwind and radix within Pydantic.
46:23 So I suspect our front end guys will at some point get annoyed with my use of bootstrap
46:26 and go off and go and change it.
46:29 One of the reasons I use bootstrap is that because bootstrap is completely customized via
46:33 SCSS and there's SCSS compilers for Python.
46:37 We have the, at least the possibility in future to allow you to customize the complete look and feel of your
46:42 app without ever having to touch NPM.
46:44 Cause 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:53 But if I hear you see, I've set the primary color to be black.
46:56 And so you'll see the buttons 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 commented out primary.
47:05 You'll see that the primary, which is the bootstrap primary button.
47:11 If I changed the, I got rid of the default font.
47:14 You would see, we went back to whatever the other font was.
47:17 So there's a world in future where we allow you to customize the look and feel
47:20 even within 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 SAS, which is S A S S S, which was, is, is basically,
47:32 a more powerful version of, of CSS where you can.
47:36 SAS and less.
47:37 Those were the two.
47:38 Yeah.
47:38 there was SAS and less.
47:39 And then we kind of settled on SAS, but then we had a CSS, which is SAS 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 like variables for,
47:53 they were available in CSS and, and defaults.
47:56 And even you can do weird stuff like map functions.
47:59 And they use very heavily in bootstrap.
48:01 But the nice bit is because the compiler is written in C.
48:04 There's Libsass in Python, where you can get kind of a front end customization without needing the whole of
48:11 node and the, the whole dog and pony show of front end development.
48:15 Yeah.
48:15 Excellent.
48:15 It's got a lot of legs.
48:17 So when I saw this and I saw, okay, this is so for, for web apps and it's kind of got this,
48:22 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:28 One of the thoughts I had was, wouldn't it be neat if there was a, got a little bundler 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, you know, kind of a friend of Django type of thing?
48:45 I have not used electron for a very long time, so I don't pretend to be an expert.
48:49 What I will say is that unlike some of the other UI libraries, we're not trying to do clever things with web sockets and do all of the,
48:58 all of the rendering requiring duplex communication between the client and the
49:02 server.
49:02 It's pretty simple.
49:03 It's like make a request and the Jason contains some information about how to
49:07 render it.
49:07 And then the front end goes off and renders it.
49:09 So it's the result.
49:10 What you get when you finish is very, in terms of a networking point of view,
49:14 very, very simple, very conventional.
49:16 It's like make an HTTP request, get back Jason, JavaScript knows how to render it.
49:21 And so I don't see why it shouldn't, shouldn't work in electron.
49:25 There's even the world in which we don't need the whole of electron.
49:28 And we could, someone could go and build fast UI components for, for whatever native library.
49:33 And we could get like native apps running that are based on fast drive.
49:36 not saying that's necessarily a good idea, but like those possibilities exist.
49:40 It is.
49:41 It does exist.
49:42 Okay.
49:42 Yeah.
49:42 Yeah.
49:43 Very interesting.
49:43 Another thing that is convention, I suppose.
49:46 I'll see if I can pull it out here is the UI.
49:49 A lot of times you'll have either just slash, you'll have slash users, but then you'll have 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,
50:00 in this 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 with the API
50:13 inserted.
50:14 Right.
50:14 You want to talk about that convention a little bit?
50:15 So people kind of see where that's going.
50:17 So that's how, how I've set it up in the default app.
50:20 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 fun.
50:28 But yeah, the, the, the principle that the default simplest way of basically doing a,
50:32 excuse me, a calculation to go from, I've got a URL.
50:35 How do I get the data for it?
50:37 Is as I said earlier, basically prepend slash API.
50:39 So maybe a more general way to think about it is for every page, there is an endpoint that is a FastAPI endpoint or a pair of them.
50:47 Maybe even one returns the HTML front end stuff that makes it run.
50:52 It talks around and goes back to itself.
50:54 Right.
50:55 Yeah.
50:55 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 available.
51:08 There's 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 hit,
51:16 will render the standard HTML.
51:18 And one of the nice things is that the Python library gives you this prebuilt HTML,
51:23 which will basically render you some, render you the HTML that you'll get.
51:26 If you, I went here and I view page source, you'll see.
51:30 You just go to home page, yeah.
51:31 Returning.
51:31 Well, yeah.
51:32 In this particular, if I went to 8,000, then it wouldn't be messed up by Vite.
51:36 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 like matching endpoints for, for every view you might want to have one to get,
51:46 to return the Jason, the one to, 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 would all just work out the box with,
52:02 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 Jason is that writing a test.
52:18 There's quite a lot here, but you'll see most of it is, is markdown.
52:21 So writing a test that our views contain what we expect them to is massively easier
52:26 when we're testing against Jason, which we can convert to Python objects and tests than it would be.
52:30 If we've got an HTML page, we're running a bunch of regexes for does this page contain the user's name?
52:35 Does it contain the word logout?
52:37 Blah, blah, blah.
52:38 Yeah.
52:38 By a right type of things or those types of tests.
52:42 Sure.
52:42 Oh yeah.
52:43 Even worse.
52:44 You end up with like play, right.
52:45 And like play, right.
52:46 That's an image of it and see if the image looks like the image used to look.
52:49 And yeah, 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 end up with them in fast UI to like even more
52:57 certainty that our components work correctly, but hopefully that thereby avoid everyone else having to,
53:02 having to go and build.
53:03 Is there any concern that maybe there's unintended APIs in the sense that like
53:08 all of this stuff, I'm sure this is probably true for pretty much any react site,
53:13 but like a lot of the page is available also as an API, even if you don't intend it to be an API,
53:18 like what's.
53:19 Yeah.
53:19 That's a limitation of any, I mean, in some ways the data will be slightly less nice to.
53:24 Yeah.
53:24 You're right.
53:25 If you're a company that give people foreign exchange rates and you want them
53:29 to always come to your site, you obviously can't render that with, with react because there's going to be a Jason endpoint where someone can just
53:35 go scrape your exchange rates or whatever else.
53:37 Right.
53:37 But you can still do session based off and say you have to log in to do it.
53:41 Right.
53:42 It's not just that it's public.
53:43 It just, there's always a Jason version, but honestly, there's so many interesting ways to pull data out of HTML.
53:49 Like, yeah.
53:50 If someone's that valuable, someone will do it anyway.
53:53 I also think that like, in theory, if your options are build pure react or do this,
53:59 and this has the, the, like, as I say, there's the realistic chance.
54:03 Someone's going to come 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 Jason 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:16 I guess you could maybe do some kind of server side rendering potentially as well.
54:20 Exactly.
54:20 That's what I mean.
54:21 Whether it's Python server side rendering, or whether it's JavaScript server side rendering,
54:24 or whether it's edge rendering.
54:25 I've tried to build a sort of edge rendering thing in Cloudflare years ago using Rust.
54:30 And for a bunch of reasons, it didn't quite work, but there's real possibility of doing like,
54:34 yeah, any number of different things in that direction.
54:36 That's interesting.
54:37 Some of the CDNs have pretty dynamic stuff right at the edge, where you can sort of put your last bit of code.
54:42 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 But again, in theory, I mean, maybe I'm overblowing it, and Fast UI will remain what it is now.
54:54 But like, in theory, we've set up this language of different components that hopefully is,
55:00 whilst by no means universal, complete enough that you can build lots of common user interfaces with it.
55:05 And then, if it really gains adoption, then people can go and build new backends and new frontends,
55:10 and they all, in theory, should be able to mix and match with each other.
55:13 We'll see if that happens.
55:14 Yeah.
55:15 And widgets too, right?
55:16 Kind of like, see a Tailwind UI create a paid thing for higher order widgets,
55:21 potentially.
55:21 Just being React already makes that, that probably exists, and I just don't know.
55:25 And there's been a number of issues of people wanting to render existing,
55:30 basically build extensions to Fast UI to render their widgets.
55:33 I think we will probably support the rep for HTML, that things like Pandas data frames already returned,
55:39 so that you could, for example, return a data frame, and it might not be pretty,
55:42 but you'll get something coming up as HTML, and, you know, start ugly, and then move on to doing those things in an even more powerful way.
55:49 Sure.
55:49 Yeah, I didn't even think of the data science side, but there's probably a lot of cool dashboard widgets connected to pandas and pullers that are potential out there.
55:57 Yeah.
55:57 And charts and visualizing data is something Pydantic is interested in.
56:00 There's no reason why a lot of them couldn't be implemented as Fast UI components and then 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.
56:13 Just talk real quickly about forms, right?
56:15 What do you think?
56:16 Yeah, absolutely.
56:16 So if you, probably easiest, if you share, let me see, share my screen.
56:20 I'll do it from here, because I can also, it's like, you can show more behind the scenes.
56:25 Yeah, yeah, yeah.
56:25 It's probably most interesting if we, if we look at the, how the form is implemented in the code first,
56:31 and then we look at what that, what that means for the UI.
56:33 So this is the, the login form that Michael, you were just showing here that I can show,
56:37 which is just, so there's a login form with an email address, password, some validation,
56:41 basically like that.
56:42 Yeah.
56:43 powered entirely by, again, a completely vanilla Pydantic model.
56:45 And the way that we return that is we return three things, heading, which is like just telling the person what we're looking at here in the demo.
56:53 And then this third thing is the, it's the interesting bit where again, actually the model form is again,
56:59 generic around the Pydantic model.
57:00 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
57:10 and you give it a Pydantic model.
57:12 And so it looks at the Pydantic class and says, we're going to create like an email address and a password field and so on.
57:19 Right.
57:19 Exactly that.
57:20 Awesome.
57:20 Okay.
57:21 And then when you submit that form, it's submitted as form data.
57:25 So is it not as, as JSON data, but as a vanilla HTML form, a standard form post type of thing.
57:32 Post form.
57:33 And then we have this, it's this syntax is definitely slightly funky here,
57:37 but, but it's how we do it in fast.
57:38 You are a FastAPI.
57:39 We have form, which is annotated as a login form, but it's also got fast UI form,
57:45 which in turn, which also takes login form, all of which looks a bit ugly.
57:49 But what we're really doing in the background is converting form data into the Pydantic model,
57:54 including flattening and deflattening the model in the case where we have nested models,
57:59 which I'll 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 of 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 form.
58:13 And this has, has a bunch more stuff in it.
58:15 So it has file inputs.
58:17 Now file inputs are one of the reasons we can't just submit, submit JSON because,
58:21 Yeah.
58:22 Because we need a multi-part encoding and all those things.
58:25 Yeah.
58:26 All those things.
58:26 Right.
58:27 And so here we have name.
58:29 We use bold again, as I have before to, to indicate required fields.
58:33 So we could, I don't know, have 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 case.
58:45 I've got a calendar picker.
58:46 Very nice.
58:47 Is that just input type equals?
58:49 That's just input type equals, equals date.
58:51 Okay.
58:51 We have switches.
58:52 We have, and then you'll see here, we have size model arrow width and size model arrow height.
58:57 And the, the point is that we're doing here, and these are integer fields,
59:00 but the cool bit is that they map to a nested Pydantic model within the big
59:06 model.
59:06 What fast UI is doing internally is basically flattening this into, one list of form fields,
59:12 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,
59:19 it just has the width and the height, the one after another.
59:21 Size width, size height.
59:22 Exactly.
59:23 If I put a, a requirement or a restriction like min or max onto the field in the size
59:29 model, would that become a client side min and max in the form?
59:33 There's an open PR to do exactly that.
59:35 Yeah.
59:35 Awesome.
59:36 But obviously we will get server side validation as well.
59:39 And then 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'll be fun.
59:45 And then you'll, you'll see in uploads, we have some, 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 file,
59:55 file, which takes two optional arguments of what rule, what accepts to apply.
01:00:00 So that will both in the browser, when you open the, when you choose a file browse dialogue,
01:00:06 yeah, it'll tell you.
01:00:07 You have a MIME.
01:00:08 So for people listening, you have the MIME type set, not like a extension,
01:00:11 but you have image slash star, which means, you know, image slash JPEG, PNG,
01:00:15 WebP, et cetera.
01:00:16 Right.
01:00:16 And that's understood by the browser and then by the, and then by the OS to,
01:00:20 to let you select files, but it's also validated server side.
01:00:23 So if someone goes and edits their HTML and submits a not image, the server side validation will check at least based on the file extension
01:00:30 that it, that it looks like an image and you get back the bytes.
01:00:33 So you could also go do validation that the bytes are a valid image.
01:00:36 If you, if you say you can read the bomb, the, the mark that indicates the file type that's sometimes in these different files.
01:00:43 Yeah.
01:00:43 If I submit this, but let's say, well, first of all, if I try and submit this,
01:00:46 because we've got server side validation of which fields are required, it won't let me submit if this file field is not completed.
01:00:52 And then I think if we put a name and we don't capitalize it in this case,
01:00:56 we'll go off and do the validation and come back and we'll say, name will start with the capital because I've implemented it.
01:01:02 Where's that validation?
01:01:03 Oh, I see.
01:01:03 That's a function that you write.
01:01:05 Right.
01:01:05 So just to prove the point, I've just written a validator in, in Pydantic,
01:01:09 which says this must start with, with uppercase.
01:01:11 And if I then went in here and edited that, print out form, is that going to now clear 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.
01:01:24 We got the, we got the different file objects and we got the raw data all come through as a Pydantic model.
01:01:29 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 appears on what feels like client side,
01:01:40 but is really server side validation run by React, right?
01:01:43 Yeah, exactly that.
01:01:44 so we'll do stuff like link checks and all the things you can do on an input client side as well.
01:01:49 But of course, there'll also be, be enforced server side, which obviously if you're building anything that you're going to be exposed to the internet,
01:01:55 you've got to do.
01:01:56 Yeah, you should never, never trust what comes into your web app.
01:01:59 It's just put it online for five minutes and look at the log.
01:02:02 It's already trying.
01:02:03 Somebody's already after WP admin.php, you know?
01:02:06 Yeah, exactly that.
01:02:07 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:13 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 it.
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 out.
01:02:29 And what it's doing internally is, and again, this is the kind of thing that would be lots and lots of work to implement if you're doing it yourself,
01:02:35 is it's storing in session storage, the auth token, then adding it as a header where we do the fetch from the front end to the back end.
01:02:43 So we can effectively store, store sessions that way.
01:02:46 Oh yeah.
01:02:46 Very cool.
01:02:46 Yeah.
01:02:47 That auth token's coming in as a header item or being set as a header item.
01:02:50 Excellent.
01:02:51 Right.
01:02:51 Exactly.
01:02:52 Cool.
01:02:52 So yeah, I hope that we've done a bit of a whirlwind tour through, through fast UI and what's there now and what,
01:02:57 what I hope is coming up and the like slightly philosophy of how, why I,
01:03:02 why I built it.
01:03:02 But yeah, that was interesting.
01:03:03 It's super interesting.
01:03:04 And it's really early days.
01:03:06 I'm, I'm looking forward to two things to see what people go do with it,
01:03:09 what widgets and stuff they build.
01:03:11 So, you know, 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 months.
01:03:19 Absolutely.
01:03:20 Yeah.
01:03:21 Thanks so much for, for having me and letting me witter on about, about this,
01:03:26 this random library.
01:03:27 Yeah, of course.
01:03:28 Good work.
01:03:28 It's certainly creative.
01:03:30 Maybe just give people a sense of, you know, 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:37 Maybe they're interested.
01:03:38 What do you tell that crew?
01:03:39 I'd love people to contribute both.
01:03:41 I mean, almost most useful is, it's issues saying how you're using it, where it's working,
01:03:46 where it's not.
01:03:46 There is a bunch of people who've already submitted PRs and, and continue to do so.
01:03:50 And yeah, I think what works works pretty rigorously and it's probably better implemented and tested than lots of like private code,
01:03:58 but definitely within internal uses, use it now.
01:04:01 And like I say, Pynantic is building things, building things with it now.
01:04:04 So look, I mean, I'm not, I give the open source guarantee that it's relatively safe,
01:04:10 which is the guarantee 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 your session authentication.
01:04:18 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 give feedback.
01:04:25 Excellent.
01:04:25 All right.
01:04:26 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.
01:04:31 I suppose.
01:04:31 Looking forward to talking to 2024.
01:04:33 Absolutely.
01:04:33 Have a good Christmas.
01:04:34 Thank you so much.
01:04:35 Yeah.
01:04:35 Thanks.
01:04:36 Bye.
01:04:36 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:42 It really helps support the show.
01:04:44 Bright 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/bright data today.
01:04:56 Take some stress out of your life.
01:04:59 Get notified immediately about errors and performance issues in your web or mobile applications with
01:05:05 Sentry.
01:05:05 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:20 Our content ranges from true beginners to deeply advanced topics like memory and async.
01:05:25 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,
01:05:42 and the direct RSS feed at /rss on talkpython.fm.
01:05:46 We're live streaming most of our recordings these days.
01:05:49 If you want to be part of the show and have your comments featured on the air,
01:05:53 be sure to subscribe to our YouTube channel at talkpython.fm/youtube.
01:05:57 This is your host, Michael Kennedy.
01:05:59 Thanks so much for listening.
01:06:00 I really appreciate it.
01:06:02 Now get out there and write some Python code.
01:06:04 I'll see you next time.