|
|
12:48 |
|
show
|
4:06 |
Hello and welcome to this short mini course on the Responder web framework.
Maybe you've heard of Responder it's written by this guy, he's done a few open source projects in Python his name's Kenneth Reitz.
So, likely you've heard of Kenneth because of his Requests library and Kenneth is pretty well known for creating clean and well liked APIs.
So, when he said hey, I know there's a bunch of web frameworks out there, but I'm going to create another one to put my stamp on what that API might look like well that got my attention.
And probably it got your attention as well.
So, if you want to see what this web framework that Kenneth Reitz came up with looks like and take it for a tour well you've come to the right place.
Let's talk quickly about what we're going to cover.
First, I'm going to talk about some of the key features.
After all, with this mini course we're not going to be able to dive deep into some of the really intriguing things that this framework takes on, for example it has async run as background work that you can run in process.
It has web socket support it has really good async methods that you can work with.
And we're not going to dig deep into that but we will talk a little bit about it.
We're going to go and build an async capable API and notice I didn't say async API because we're not actually going into async here that's well beyond the scope of this I have a very long course on that and you're welcome to take it and it's super, super powerful and it's one of the things that drew me to this framework, however we're not going to go into those details.
If you know async await, all the view methods and API endpoints we create here with Responder you can put async def on the method and you can do await within it it's really, really great for scalability but again, we're not going into it.
We're going to create two kinds of views or processing with this web framework.
One is going to return templated Jinja2 based views.
I'm going to go to the database to go to a data source and then I'm going to convert that into a dictionary, I'm going to pass that dictionary to a Jinja2 template, Jinja2 template's going to be rendered into rich HTML, that's great.
The other kind are more HTTP API endpoints.
Here we're going to do a get request or a post request over to an endpoint and return some kind of JSON.
These JSON endpoints, they're fun and they're cool, but you know they just exchange little bits of data.
Wouldn't it be fun if we had a really awesome app built around it?
Why, yes it would.
So, we're going to take an app that I built using Vue JS to explore this API and it's really fun, it's really interactive.
Again, same reasons as async we're not going to go into Vue I'm going to show you how the app works I'll give you like the one minute flyer of Vue JS, but I will give you this rich application that works with this API that we will build during the class.
Now, I said it a few times but I just wanted to remind you, this is a fast course we're just going to go really quickly into some of the key elements of Responder we're going to build some JSON APIs we're going to build some cool apps to consume it.
Think we're going to have a lot of fun.
So, with that in mind, let's just keep moving.
Now, what do we expect you to know in order to take this class and get the most out of it?
Well, Python obviously.
We're not going to cover any of the foundations you don't know what a foreign loop is or things like that, there's other places you probably should start and then come back here.
This assumes that you know like the majority of the core Python language.
We're not doing meta classes and deep things but the basic Python syntax, you should definitely have that down.
And it is a web framework, we're not going really deep into the foundations of what REST APIs are or why you care about them.
Or what HTTP verbs are, we're going to assume you kind of are familiar with that and we want to build something in Python with Responder.
These are the expectations for the course.
And finally, let me introduce myself, who am I?
Who's this guy talking to you?
My name's Michael Kennedy that's a picture of me, you can find me on Twitter @MKennedy.
You might know me from the Talk Python to Me podcast you may also know me from the Python Bytes podcast but most relevant for this conversation I'm the founder and one of the main authors at Talk Python Training.
Welcome, welcome to the course.
It's going to be a lot of fun and it's not going to take a lot of time so I think that's a beautiful mix and I hope you enjoy it.
|
|
show
|
2:40 |
Now we're almost ready to start writing some code and talking about this framework.
But before we do, let's just make sure everyone's on a level playing field.
There's a couple things I want to share with you.
A couple things I want to give you.
And, also want to make sure you have what you need to take this course.
So the first thing I'm want to start with is what version of Python do you need.
Well of course we're on modern Python.
That in my mind I guess, is probably like Python 3.5 and above.
But you're actually going to need Python 3.6 'cause I believe we use some f-strings.
f-strings are a new way to format strings in Python which are great.
Also it has async and await which came in 3.5 but I believe some of the features that were added also required a little bit later.
So let's just say, 3.6 or later, maybe even 3.7.
Newer is better.
You have to have Python installed and it has to be Python 3.5 at an absolute minimum.
Ah, could be higher still.
You may even wonder all "That's great Michael I, really want to have Python installed but do I on this particular machine".
I don't know.
Well you can always ask.
You can go to your terminal in macOS or Linux and type Python3 -V and it will tell you, one of two things.
Either the version number or Python 3 not found.
If Python 3 not found, that means it's either not installed or just not in your path.
But, you can see I got Python 3.7.2 that's almost the latest.
Just the day I started pressing record here, 3.7.3 came out.
Pretty much the same.
On Windows, ah, Python3 -V sometimes works and you can get 3.7.2.
Depending on how you've installed Python.
You might have to type just Python, without the 3, -V and see what you get.
And especially on Windows '�ause until recently could not target the version by the executable name.
You have to make sure your path is just right so you can type "where Python" on Windows I think and "which Python" on Mac and Linux.
If that's wrong, you can switch it.
It's either which or where to show you where it's come from and if there is more it'll show you which, which is in the path and where you know which one comes first in the path and so on.
So if you have a new enough version of Python super, let's rock and roll.
If you don't, refer you over to realPython.com/installing-Python These guys have a really nice set of steps on giving this OS here's how you get Python there here's the trade off's and so on.
And, they're keeping it nice and up to date, so ah instead of showing you how install and maybe you know, six months there's some other way like Windows 10 now just offered Python 3.7 in the store which is a better way that getting it off Python.org for example.
So you can check out what they've got here.
This is pretty helpful and of course, you know get modern Python all set up if you don't have it and let's roll.
|
|
show
|
1:05 |
Now, we could use whatever editor we want but I am a big fan of PyCharm.
I think PyCharm strikes a really nice balance of not being too heavyweight it's somewhat heavyweight, but it's really not that bad with absolutely supporting proper web applications.
So, not only does it understand CSS and JavaScript and HTML it knows Python really well and it understands the relationships between your CSS files, your static files your Python files that you're working with.
It has nice refactoring.
All sorts of stuff.
So, we're going to be using PyCharm.
You can get the Community Edition which will do most of what you need here.
It'll basically do everything except for give you any form of support for the Jinja2 stuff or the CSS editing, all right?
You could still create those files and edit them I'm pretty sure but with the free community edition it won't do auto-complete within them.
They don't have native support for Responder built in anyway, so that's not a huge shortcoming but it is something to be aware of.
So we're going to use PyCharm Professional.
You can follow along with that.
Or use something else if you prefer but here's how you can get the same editor that we're using.
|
|
show
|
0:35 |
Now of course, everything you see me type and much more will be available to you in a free and open GitHub repository, and this one, so go to github.com/talkPython/responder-webframework-minicourse.
Here, you'll see all the demo code that you'll see created even a little bit more because I had to tweak a couple of things.
We added the Vue JS, there's stuff in there that we're going to talk about at the end and everything that you need to get going you can get it right here.
So be sure to go to this repository, star, and fork it and that way you'll be sure to have all the materials to follow along.
|
|
show
|
1:40 |
Now some of the content in fact the main demo where we build out this Responder API comes from this other course that we're working on and we have been working on for a long time called 100 days of Web in Python.
Haven't heard of it?
That's because this is the first time were publicly talking about it at all so workin' on this with Bob Belderbos and Julian Sequeira who helped with the 100 days of Python course 100 days of Code in Python course that we already did, and this is another massive course covering all sorts of things in the web framework world.
Vue JS, React, Flask, Django, Responder APIStar, you name it.
If you want to dig into a bunch of different web frameworks and kind of get a survey of the entire landscape this is the course where we're doing that.
It's going to be like 25 hours of content and it's going to be amazing.
So in the next chapter when we build out this API some of that presentation is coming from a little excerpt from his 100 Days of Web course.
Now, I didn't know anything about it or have any experience with this 100 Days of Web course but you'll see it in the demo links like in the fold or path.
Things like that if you see that and you're like, wait, what is this 100 Days of Web about?
Well, here's what it's about.
So we took this little bit of Responder from the 100 Days of Web course and we turned it into its own proper course this little mini course that you can take right here.
That's what it's about, check this out.
It's not out yet at the time of the recording but maybe the time of watching.
Anyway, if you subscribe to get notified somehow at training.talkpython.fm like you have an account and you haven't opted out for example, you'll definitely hear about this when it comes out.
Heads up, this a little excerpt from a really big course that's been blown up to be its own proper course.
|
|
show
|
2:42 |
Think back to when you were younger, much younger.
And you were playing with Legos or something like this.
These look like so much fun, right?
And see, there's a little dragon head there in the middle and there's a bunch of blocks and maybe somethin' from a spaceship, who knows?
Well, this looks like fun.
But it's a lot more fun to actually follow along and build something.
So this course is built for you to follow along in two ways.
So I want to highlight those right at the beginning.
In case you want to follow along, you can.
You don't have to, all right?
If you just want to watch and let it wash over you that's great, you can totally do that.
But if you want to follow along there's two things you can do.
First, when we work our way through all the demos and stuff you could pause the videos and just go and recreate that.
You might need to grab the data that we're using off of the GitHub repository.
But after that, you should be able to follow along and create it yourself.
So one, step one, round one, version one of this would be to follow along.
The second is this thing I'm calling "Your Turn." So if you GitHub repo, actually to this folder here linked at the bottom, you'll see we put together a separate independent project that was not presented in this video for you to also follow along.
So here we are in this responder webframe marked "Minicourse", Github repository.
And here's your turn I was talking about.
So if we go in here you can see, there's a couple of steps.
It's not like, do X, type Y, and so on.
It's more like, here's some ideas of how you can explore to build something with Responder.
We're going to use this Mockaroo service go over here you can see if I log in.
Mockaroo will let us generate things like ID, first name, email.
And I can even preview it and it'll show me some pretty cool data there, actually.
But you can go further and click here and say "I would like a animal scientific name," or, "Bitcoin address." You see, there's all sorts of stuff here.
So the idea is, you go to this Mockaroo service.
You look through that data source of sets of data sources you can generate, and go "Oh, I have an idea for a veterinary clinic," "or a Bitcoin company," or whatever, right?
Look through and find something interesting and generate a bunch of data.
You can save it as JSON, here's a way to load it back up as JSON into Python dictionaries that you can use.
And then here's a simple example of building out some sort of API endpoint.
And you'll have seen this, you'll see how this goes.
So here, just a reminder on how that works.
And you always look back at the demo code.
And I encourage you, after you've seen the short course after you've followed along, to go explore Mockaroo.
Build an interesting fake data set and then build an interesting fake service to work with that.
All right, well hopefully this adds a fun twist at the end of the course for you.
|
|
|
28:09 |
|
show
|
2:10 |
Before we start building our application with Responder, let's talk about a couple of the key features.
We're not going to be able to cover the majority of these things.
We're going to build a pretty simple app in this short chapter.
I want to highlight some of the other things that Responder does for you.
You can go check it out.
Well, you'll definitely see the API.
So there's a pleasant API.
This is from Kenneth Reitz and he's pretty good at putting together nice API's.
Things like requests are considered some of the better API's out there.
It has class-based views but you don't have to use inheritance.
You can just use a decorator on a class, basically.
It has a nice ASGI framework.
So these are the Async web Service Gateway Interfaces.
This is, we talked about this when we talked about the Quart framework.
This is the essential element that allows us to use async and await for our web view methods and actually use asyncio to do more concurrency.
And that's one of the key foundations of Responder is it's built on top of an ASGI and natively and first-class supports async web view methods.
That because of that it's pretty easy for it to support WebSocket.
It also has the ability to take any other ASGI or WSGI app and make that a sub part of the application.
So imagine there's some Flask app and you want to make that part of your sub application.
Or you want to take a Pyramid app and make that part of some CMS section, or who knows.
You can mount these other apps as sub routes and sort of combine them together.
That's pretty cool.
It has nice, simple f-string-like ways to declare routes.
So you don't have to do regular expressions and stuff like that.
It has a mutable response object that's passed to each view.
So you don't have to return anything.
You just set some properties and then it just picks those up as it goes.
One interesting feature is it has support for background tasks.
So instead of running those as part of the request you can actually just register stuff to run in the background and that's actually internally done with a ThreadPoolExecutor.
Also has support for GraphQL, OpenAPI schema generation and documentation, and even special support for single page web apps or SPA's.
That's quite a few cool features so it's a really neat framework.
|
|
show
|
0:48 |
When you first look at Responder, you might think of it as an entirely new, from scratch, API.
But the reality is, is it's more of a reinterpretation of existing frameworks.
So, for example, two of the main building blocks of Responder are Starlette and API Star.
We've talked about API Star already.
It's a cool way to build APIs of course from Tom Christie also of Django Rest Framework fame.
And then Starlette is an ASGI framework that really works well.
So you'll see a lot of the features of Responder are really coming from, especially Starlette.
These two things are foundational elements for working with Responder and that's kind of cool because that means it's not entirely new and from scratch, but it kind of builds on the work and the growth of these other frameworks.
|
|
show
|
1:07 |
Before we open up the API of Responder and start writing code with it I want to give you a quick tour of what we're going to build.
We're going to rebuild this service the Movie Db service from Talk Python.
You know this is a demo type of API that I took and built long ago for another one of my courses.
It allows you to search for movies so here you can see we're searching for "run" and we search for say "job" we get, you know The Italian Job and things like that.
So, we have this nice API here that we can work with.
We have this sort of landing page here at the front and you can also search by director or even pull up the details of an individual movie by IMDB code.
So, we're going to take the data backend for this which is really a Python file and just like a simple CSV and we're going to recreate this in Responder.
This one is actually running Pyramid on one of my servers but for our demo, we're going to take this and just recreate the same concept using the same data source with Responder.
Should be a lot of fun and you can check this thing out here of course or just check out the after code as we go through it.
|
|
show
|
1:44 |
Are you ready to write some code?
And build an API, that movie search service with responder?
Well, let's get started.
We're going to over here in our GitHub repo create a folder called movie_svc and I'm going to go into the service and just create a virtual environment as we have been all along.
So we'll run Python3 -m venv venv and that'll create an virtual environment and activate it.
Now the next thing to do is install Responder so we'll say pip install responder.
There we go it's all installed and if we also install a little tool here called pipdeptree you can see how all this stuff fits together.
You can just say pipdeptree and it shows you all of the moving pieces of Responder so you can see Responder is using aiofiles, API Star graphene, Jinja2, requests uvicorn for the async web server and then Starlette we already talked about.
So here's all the pieces that we got working.
Now let's open this up in PyCharm.
And now we are going to get started by just having a Pyhton file and I'll call it app.py.
You can actually call it whatever you want but that's fine.
Okay, we make sure everything is working by just saying import responder and then we can go ahead and just run this.
Okay loads up looks like everything is configured correctly.
Now we got to get started with the API create some view methods and then run our server.
Now before we do run that server though lets do one more thing lets create a requirements file here.
And here we'll just put responder as well okay great so we got our requrements.txt and we got our starter code that we're going to build our app right here.
|
|
show
|
1:46 |
Let's get started by just defining the most basic web app that we can with responder.
And then we're going to add some templated views and some API methods.
And also, when we get started we're going to build it all in this jammed-together app.py file, and then I'll show you one way at least to restructure it in a much much better way with API views broken out, and page views and routes and all the stuff that you would probably want to do for real apps broken apart in a much better way.
But we're going to start by jamming it in here.
So, let's get started.
Now, when you think of this API it's Flask-inspired but it's not exactly the same as Flask.
A lot of what you do, before mirroring Flask we did like Flask.app like this, Flask app.
Here, we're going to say responder.api, like so.
We're going to create this and then on to various methods we can say app.route, to add a route.
So let's say we want one for the home view and this will be index and this is going to take a request, and a response.
This is unlike Flask, which doesn't take these.
And then, what we can do is we can just say response.content = "Hello world".
Alright, now if we run this it's going to be not so inspiring, it just exits.
The last thing we've got to do is we've got to go down here and say app.run.
If we do this, clean it up a little and we run it it's up and going, let's see what we've got.
Hello world, there we go.
Hopefully you can tell this is a pretty simple API and it's also quite Flask-inspired in the way that it works.
Obviously, we want to replace this with some kind of templated view maybe an overall layout page and individual page details like we have in some of the other templated frameworks and things like that.
We'll get to that but here is a really nice way to get started.
|
|
show
|
2:25 |
Here's our target application.
It's going to look like this.
Now what I want to do is have a template that we can use.
A standard, dynamic HTML template.
Now this one I told you was Pyramid and so it's using Chameleon but Responder, as far as I know doesn't support Chameleon it supports Jinja2.
So what I'm going to do is I'm going to put the HTML already here and we're just going to look at it.
Because it's not really that interesting and we're just trying to recreate the same thing.
So we're going to create a templates folder and let's go ahead and actually mark that as a template directory.
Here in the _layout.html we have the overall look and feel for our site.
And it's going to be the same across everything.
And importantly notice right here we have our content block and then over here we're just saying this extends /shared/_layout.html and here's that content block And this parts pretty static honestly but you could imagine putting additional Jinja commands and so on.
Gives you enough to work with.
So these are in place now how do we use this?
Obviously that's not going to work.
I'm going to say the app and actually I kind of want to rename this.
Let's rename this to api.
There we go since it's an instance of the api.
So we'll say api.template and we can give it the name of the template.
And this is going to be relative to the working to the template folder here So we're going to say it like this.
We'll say home/index.html, okay.
And then this should get that content and any data we wanted to pass.
We could pass user equals Micheal or whatever you want.
Alright you can do keyword values.
I'll expand the dictionary there.
And it'll be passed to the Jinja template.
Alright let's run this and see what we get now.
Well it kind of looks good.
It looks okay.
If we compare these though notice there's some formatting that's missing.
Alright, for example, this is not so good it's suppose to be the right.
What's happening?
Well the static files over here if we go and inspect element and look at the network we'll look at all of it.
You can see we're getting 500 errors trying to get access to these static files that don't exist.
These really should be 404s I've actually submitted an error report like a Github issue, to the project saying those should be 404s but whatever it is the point here is that these are not working.
We got to now add a static route so that's what we're going to do next.
But we're already pretty close right?
We've got the template up and running.
All we got to do is say api.template and give it a relative path within the templates folder.
|
|
show
|
1:35 |
Our template file is working but the static files are not there.
Well, that's not surprising because we haven't created any.
There's a couple things we have to do.
Notice already it's adding this static folder that's just by running it creates the templates in the static folder.
So we're going to copy some stuff over copy some CSS and so on and you'll see that those are actually being imported right here at the top right there.
So, I just got to make sure those are available.
Now if we run this again click here, hey look at that.
It looks a lot better.
Our formatting is here and of course we still have this view which you can look at it like this go over to the network, go to requests you can see now we're getting good stuff for our static resources.
Let's go see just CSS, there they are.
304 even they're cached, which is great.
For this we don't have to do anything.
The static folder is already mapped with caching but if for some reason you wanted to control it I could go over here and say api.static_route then I could say /static and potentially add additional details so if you wanted to have another static folder, other things and then come over here and say static=true.
Okay so you can add additional routes.
I'll comment it out so you have it but it already creates one static folder for you to get started with.
It also does this templates thing which I've mapped as a template folder that's why it's purple here in PyCharm.
Okay it looks like this thing is up and running.
We got our web view working great.
How 'about this when we try to search not found, not working so well, huh?
All right well that's something we still got to build but we do have our static files working and we have our template working right here.
|
|
show
|
2:51 |
The next thing to do is to define the API routes.
Probably the easiest way is actually to go on and run this.
And grab them off this little description page.
We're going to do a GET to search for movies.
Like this.
Want to have that here.
That's something we're going to do.
And I'll put the others.
So this time we need to define three additional routes.
So, let's try it in the methods first.
And let's just call this search_by_keyword.
The name and the method is really just for us not for them.
Request and response, that's what we're going to pass in and let's just do this for a moment.
And search_by_director then movie_by_imdb.
Great, so these are the things that we're going to build.
Now we need, see what we want here.
So, we want /api/search, and we want to grab some data out of the route and we want to pass it through.
Well it turns out this is super nice.
We say api.route and we give it as a string of this bit right here and then that actually gets converted to a string and passed automatically.
So we just say that's a string right there.
And that's it.
That's easy, right?
Now, how do we show or return some sort of json data?
Well, it's going to be pretty easy.
We'll say response and you're going to say the media is equal to a dictionary.
So let's just say 'searching'.
I'll just put the keyword here.
So just have it echo it back.
Notice there's no return value.
This is mutable, these requests here or responses.
And you just set values like headers and media and content and so on.
So we should be able to call this already.
Let's try.
Go over and click this.
Look at that.
Searching for run.
And if you actually view the raw data that's the json value that was turned back.
Perfect!
So this is pretty easy.
Let's do the other two.
The route for this one is going to be api/director/{director_name}.
So @api.route.
Put this into a string.
This is a variable as a string.
And so we get better intellisense or autocomplete let's go ahead and decorate out our response object as well.
Okay and then this one is going to be somewhere.
We're going to pass in the variables from the route and that's always going to be a string.
It'll clean up and it looks like we're pretty much ready to go.
We're going to do some kind of response.
Let's just echo back the values here.
We're going to have director and this one will have imdb_number and let's just tell it that's spelled correctly.
Alright, we can test the other two real quick now.
Searching for run, great.
Now we're searching for Cameron by the director bit.
And here we're searching by the IMDB code for api/movie.
Perfect!
So we have our stubs pretty much built.
And to be honest, this is kind of it for our API.
What's left?
Well what we have to do is we have to implement some kind of data backend and some kind of searching mechanism to actually search for the keyword or the director or whatever.
It turns out that's pretty much pre-baked.
So we're going to do a little bit of work to fill out these methods and then we'll be done.
|
|
show
|
3:03 |
Now, in order to actually implement these methods we need some data so I'm going to give you the data that actually powers that search that movie service that I showed you at the beginning so I'm going to just drop that in here, going to be a data folder and in the data folder we're going to have a movie.csv super-exciting, right and we're going to have this DB, database.py and it's going to return this named tuple which looks like that so it could be a class but we just got this simple thing that we're reading from that CSV so the main important thing here is that we need to call global_init.
It's going to go find where the actual CSV file is.
It's going to iterate over the rows and convert them into these movie objects and then put them into a lookup, by IMDb code so we can kind of index into our in-memory database here so we can ask it things like search for them by title and get a list back search by keyword and get a list back or just get an individual movie out of our little fake database here.
Okay, so that's super-easy.
We come over here, and we're going to say from data import db.
Now this one, this one looks pretty easy.
Actually, let's do the IMDb one.
This one looks easiest, I think so we'll say movie equals db.find_by_imdb and we're going to give it IMDb number.
If this is none or it doesn't exist we're just getting None back for the movie so we could do something like check whether or not the movie's there, return a 404.
For now I'm just going to try to return the movie just the details of the movie.
I don't think it's going to work but let's find out what happens.
Oh, I think we forgot to call the global_init.
This is probably going to fail, but let's try.
Yep, it got us nothing back and it should have given us something.
It didn't crash, it just said there's no data found and the reason is somewhere along the way maybe in the startup here, I'm not sure we need to call db.global_init once.
Okay, try again, server error.
Okay, remember I told you I didn't think this was going to work.
What's wrong?
This object is not JSON serializable so the important thing to note here is the entire object graph like if it's the list, everything the list contains and the items within that list point to, and so on have to be JSON serializable.
This movie is a class.
It's not, so we need some way to convert it to JSON.
If we look over here actually wrote a method somewhere here at the top movie_to_dict, right, so it's going to create a dictionary and dictionaries long as their elements are serializable themselves, are so that'll be nice and easy so all we got to do is say db.movie_to_dict and then this should work because the important thing is that that's basically a Python dictionary or a list of dictionaries, or something along those lines.
All right, ready?
Boom, look at that.
The Abyss by James Cameron.
How cool is that?
So, we've already implemented our method, our first method.
We went to the database, found our movie converted our movie from a movie object into a dictionary set the response media.
Boom, already knows that's JSON.
Off it goes.
How cool is that?
This is pretty easy, right?
|
|
show
|
4:11 |
Let's implement search by keyword here.
We saw that it's pretty easy if we have our database.
We just got to make sure everything is a dictionary, and off it goes.
One other item I want to be careful about here is I want to make sure we don't have too many responses.
Right?
If you search for the letter A you might get basically the database back.
So up here I want to set some kind of max response count like to 10 or something along those lines.
So a little bit of a complicating detail but at the same time you don't want to dump your database back if they search for nothing or space or, you know, some weird thing like that.
Alright, so let's say we're going to get our movies and again we're going to go back to our database and say search by keyword this time.
And the keyword is already coming in.
That's cool, right?
So right away we get a list of movies back from the database, and then we'll say limited.
We want to know and report to the user whether or not there's more responses.
So we'll say is the len of movies greater than the max response count there.
I'll say, if it is limited like there's too many movies here what we're going to do is we're going to trim it down.
So we'll set the movies to just the first 10 using slicing.
Remember, this is just in memory.
It's kind of silly, but it works.
Now, what happens if we try to return a movie?
Well, we already saw down here is goes this is not JSON serializable.
It's not going to work.
So we have to do a little bit of magice right here.
We'll say movie dicts, because this is the list but the things in the list are not serializable.
So we're going to go and create a new list where the items in the list are, so we'll say db.movie_to_dict(m) for m in movies, and now here we're going to just return our movie dict along with a few other things.
So we want to say what the keyword was, we'll say hits that's what it says in the other api so it's going to say here it's going to be movie dict and then truncated results is going to be indicated by whether it was limited yes or no.
Alright so here's our search and we can even do a print statement searching, we'll do a print, get the results out scale one more time, click over here on search.
Hmm, look at that!
Our search for run returned The Rundown, The Runaway Bride Run All Night, Chicken Run, all sorts of stuff.
Cool, so what if we search for Superman.
Boom, Batman versus Superman, Superman Returns, just straight up Superman, Superman 2 Yeah, so it's working really well, it's pretty straight forward right.
We're going to do something super super similar with the other one.
So I'm just going to copy this down here, and I'm going to use director name and, instead of searching by keyword we'll search by director.
A little database thing, knows all about that.
So director will pass along the director name and the keyword is going to be director name.
Alright, let's run it again.
This time if we click, lets clean this up a little.
If we click right here on director, it shows us just Cameron, Avatar, Titanic and so on.
If we search for someone else like Berg, Peter Berg.
We get Battleship, Indiana Jones all these.
Great right.
Hancock, so we can search by whatever we want Cameron, here we go.
So I think that's it, we have them all implemented lets just double check, keyword, seems like that works.
Director, seems like that works.
And IMDB code where we get one back, well that one's been working for a while.
It was pretty quick right and look, this entire thing is implemented in PEP 8 style, 58 lines plus the static HTML and CSS, and I guess maybe the db as well.
But the API side of thing is really really quite simple one thing you might want to do, like in PyCharm saying this is not used in Python, a way to say, I have to pass a thing here but I don't want to use it, is put an _ So that might make you feel better if you want to put underscores, but then you also maybe don't remember what that's for.
So it's up to you, but I wouldn't put those there so it doesn't look like they're errors.
Here we go, so it's totally working.
Is it totally beautiful?
No, I hate having all this stuff crammed in this one file but these Flask like api's, because they allocate this thing and use it in, sort of nudge people down that path.
We're going to clean this up but I think this is working really really well.
|
|
show
|
4:28 |
The last thing we want to do is just reorganize this.
Now, if this was the entire application I'd be fine to leave it the way it is.
But I know how real web apps are.
They have hundreds or maybe thousands of these view methods, and templates and all sorts of things.
So you want to reorganize it and set yourself up for growing into a bigger app than this if that's at all possible.
So how are we going to do that?
Well, the data thing is fine, the templates you can see I've already organized them in a way that's pretty good.
Similarly, for the static files here.
So those three are going to be fine.
What we're going to focus on is just this file.
Now the one thing we need to do is this thing, you can see it's used here, and here, and here and it's an instance.
So it's a little silly, but what I'm going to do is I'm going to create just a file that basically has that one single line in here.
So I'll come up with something like api_instance and we'll import responder, and I'll say API equals responder.api, like that.
And that's it.
So over here, we're not going to do this.
Instead, we're going to say from api_instance import api and that puts us back.
But what that means is other files can also import this and share that instance.
If I put it here, and then this file has to import some other files, but those files need access to that instance, so they got to get back here first it gets really complicated.
So this kind of breaks that circular dependency.
The next thing i want to do is I want to have some views here.
Let's have a whatchacallit, like a home view hence the name home right there.
And, woops I didn't want that to be a directory.
I want that to be a file.
Have a home set of views, and I'm going to have API views.
You could just call it API but it's kind of highly confusing that this is also called API, so let's call it api_views.
So then we're just going to say well, this kind of stuff is what's going to go over in this part and we're going to have to say from api_instance import api and this one's done.
Now, again pretty simple, but in a real app you have tons of these and they'll build up.
So that'll be good to have that out of the way.
And then here's our API methods, these three.
Let's take those and put them here.
And again we need the api, you can see the arrow there from api_instance import api.
We're also going to need responder, and this thing really was only defined here for that purpose so I can put that up there.
We also need our db, so it looks like we have that all up there, everything's cleaned up.
Now if I try to run this, how well is this going to work?
Well, we initialize our database and we call run.
How's the responder going to know about these routes?
Probably not very well, let's try.
Yeah, not found.
Didn't know so well.
So what we need to do is basically let Python more importantly the decorator see these and the way you let that see it in Python is you just import it.
So we'll say this, from views.home import * we'll use star which is normally discouraged but we'll use it because as we add new ones it's just going to get everything.
And what else we want here?
api_views.
So we can go say, don't do this.
Don't tell us these are not used because they are used.
Alright, great.
Now if I run it, it's not looking great.
We still got one more thing to do, but it's getting there.
Back to work.
Woo hoo, everything's working again, see that?
But now if we want to go and add something we know where we go.
Here's more HTML template based views here's where we put some more API methods.
Those are all separated from say, the app start up like creating the global_init, importing the views creating the app sort of over there and then calling run.
So you might want to add a little bit of extra work here to make this, I don't know, look a little better.
We can put his into a main, or something like that and then use our Python convention one more time.
Here we go.
Alright, so I'm going to call this much more cleaned up and ready for big boy web application that actually does a whole bunch of stuff doesn't just cram everything into that app.py file like so many of the Flask apps do.
Alright, well that's Responder all put together for you.
It's a pretty cool little web app.
One of the important things we haven't spoken about is because it's an ASGI framework based on Starlette we could put async here and use say like await right here, if the database actually supported async behaviors.
It doesn't.
That's why I didn't talk very much about it.
But one of the big advantages here which some of the others do have as well is that we can use async on our view methods which is pretty awesome.
Alright, that's responder in a nutshell.
|
|
show
|
2:01 |
Let's close down our chapter on Responder by quickly looking at some of the core concepts.
Incredibly, what you see on the screen here is a complete Responder application assuming that you don't count that index file that's just the static HTML or dynamic HTML.
So, what are we going to do to get started with a templated HTML page-based view?
Come in here and create an API from responder.api similar to Flask's app.
We're going to add a route as a decorator through api.route and we saw that you can even use curly braces like f-string like syntax to define places where data is passed in the URL.
Then we're going to use api.template and pass the relative file name of the template we want to use.
It assumes that you're talking about the template's folder, so within there it's the home directory in the index.html file.
We're also here passing a user key which has the value u.
It didn't really say where u comes from but, you know, you get it from somewhere, right?
And you're passing along values like this that can be used inside that Jinja2 template.
And then, what we do is we just set the content of the response.
It's a mutable object, so we don't return values we just change response.
Gives us a bare one, we set some values in it uses that result to generate the page.
That was for a page backed by a template.
What if we want a JSON-based API view?
Well it's pretty similar.
We're going to have the route again and see we're passing the keyword this time.
And that key word appears in the search methods signature.
Then, we're just going to create a JSON serializable thing.
The simplest is probably a dictionary or list of dictionaries, things like that.
And we're going to set the media element right there.
And by setting media, we're telling it here is a JSON object.
I want you to serialize and send back as part of this API response with the content type being JSON.
That's it, that's Responder!
Remember, all the key features I told you about at the beginning, that are not shown or covered here.
Web sockets, async capabilities, background tasks.
All that kind of stuff is in there but we don't have time to cover it.
You can go explore it yourself, it looks really cool.
|
|
|
5:50 |
|
show
|
2:21 |
Now before we talk about Vue.js properly at least to quickly introduce the application that I'm going to let you have to play with the API that we'll be building here let's just talk about some ways we can call our API.
Now, in the beginning, we just clicked on it in PyCharm or opened a browser and typed in the address and we just went there.
And that's kind of okay for get requests sometimes unless you need to modify the header but it's really hard to test post and other types of verbs that way so let me show you something better.
Let's start by actually just getting our app to run again over here.
So this is a fresh copy we're going to work with so let's go over here and go to that directory and we're going to create a virtual environment by running Python3 -m venv venv.
Activate it and upgrade pip 'cause pip is always out of date for virtual environments, it seems like.
So with that in place we can come over here and open this in PyCharm.
All right, super.
That's all loaded up.
Let's go in here and let's mark this directory.
That's a sources route and we don't really have to mess with that.
That's just HTML and JavaScript, but I guess it won't hurt.
And mark it as a resource route so it doesn't think things like ../jsfile or whatever are missing.
Okay, so, also make sure that we have the right thing running.
Yes, our virtual environment is there so let's go into MovieDb Service.
Install our requirements, so this will run.
Great, looks like that worked.
Let's just go run our app.
We might need to change the directory and wait for this to finish, this indexing.
All right, let's go and run that, see how this works.
Click on this.
All right, beautiful.
It looks like our service is up and running here.
You've seen this from before.
So if we click here, we can test our little run but let's try something besides just calling it a browser.
Let's go open Postman.
You can go and search for Postman in this app.
It's really nice, it's free.
Come over here and we can enter the URL and send it and here we get, you can see a nice output.
We can, of course, tweak the body make this a POST or PUT or something like that.
So if you want to explore and interact with the service and test it a little bit better than with your browser I recommend using Postman for that.
Of course, it's not an app, it's not as much fun but it is a good way to explore your API as you're building it.
|
|
show
|
3:29 |
Now, keeping with our theme of a high speed fast mini course this is not a deep dive on Vue JS.
But, like I said, I did want to provide this app for you to play with, and so let me just give you a quick tour so it makes a little bit of sense.
You can see down here we have our movie service running.
I'm going to put that away, so we have room but it's going to be running down there the whole time.
Now, let's open up this Movie Explorer and notice it has a views, as in HTML it has JS and it has CSS.
CSS, we don't care too much about but let's look over here at the index.
Actually, let's start with the site.
So, here, you can see it's using the localhost API you can also use the public API that won't be a Responder that's Pyramid but it doesn't really matter if you just want to play with Vue you can use that without running the little app here.
But this will let you work with the API that we are building right there.
So what we do is we go and create a new Vue object we tell it where it's going to run we pass the data binding elements like the movies and the genres we give it methods like search and it's called a lot of movies, if we go down to movies.
You see this going against our URL here using a cool library called Axios.
All that stuff's included, I've committed all the stuff under node modules so you don't have to NPM initialize it to install the local stuff.
All right, you just check it out and run it.
So, anyway, this stuff here, is going to be bound over on this end, because we're saying, "Here's an ID." And here's like a search input and we're model binding the search text and if you hit enter it calls that search function.
And then here, we're looping over all the genres we're looping over all the movie results and putting them here.
So now that we have our movie service here running in PyCharm, I just minimize that.
Let's go over and run our Movie Explorer.
You can actually run that from PyCharm or we can just run it from the file system and I find that's a little simpler, so let's just do that.
Go over here to our index.html and, quote, "Run it," and we'll just open the HTML, it pulls in the JavaScript it's going to do its magic.
So here you you can see that it's hitting our API and I can show you that that is happening, right here you can see it's doing some get request of the API input there.
And we can do all sorts of cool stuff so I can see the top 10 movies, I can select a movie by genre, so let's go see the documentaries "Butteryfly Girl," and whatnot we can say show me the sports, then click on that.
Or you can show me the the drama, a very popular one.
Or you could even search for stuff that's just, you know, fun to watch.
"Funny People," "Fun with Dick and Jane." Apparently those are all in the comedy.
Okay, so this is the application and if you look at the network, we go to just XHR that's Ajax, basically.
You can see all those requests going back to our API input, here, so localhost, API, search test.
Test two.
If we go and click the top 10, there's the movie top 10.
Movies by genre, here we go, API movie genre, adventure.
So we're not going to go into lots of detail about Vue JS that's also covered in the Hundred Days of Web course in great detail, but not here because this is really not about Vue JS.
Nonetheless, hopefully, having this here to work with comparing how you might call the service and define it and then how you might interact with it from a rich frontend framework, like Vue JS.
Hopefully that's interesting and adds some value for you.
Either way, all this code is in the get it repository and you can go an play with it, as you like.
|
|
|
2:21 |
|
show
|
0:36 |
That's it!
You've done it, you have crossed the finish line.
In fact, we've only scratched the surface of what Responder can do.
Go check out some of the other tutorials that they have on their site.
Dig into the Background Worker stuff dig into the WebSockets.
There's all kinds of cool things that you can do that are way more advanced than what we've had a chance to dig into in this short course.
Before you do that, take a moment, get up put your arms up in a V, and say "Yes, I've made it!
"I've gone through this whole framework "and now I know something cool "that maybe I didn't at the beginning of today." That's it, you're done, congratulations.
|
|
show
|
0:41 |
We covered quite a bit actually in this course, We talked about Responder, a bunch of stuff with HTTP endpoints.
We talked about Mockeroo, and we even did a little bit of Vue JS.
But, it is nothing compared to what we cover in the 100 Days of Web in Python course.
This represents only 1/100th of what we're covering.
Eh, you throw in the Vue JS, maybe 1.5% of what is covered in the 100 Days of Web course.
So, if you want to go deeper, definitely be on the look-out for when we release this course, and maybe check out training.talkpython.fm to see if it's already released if you're watching this a little bit later after we've recorded this.
It's a super fun course and if you like these kind of things, you should definitely check out the full course.
|
|
show
|
0:34 |
Remember at the beginning when I told you there are two ways to follow along?
Well, you've gone through level one you've watched all the videos and maybe you followed along and built out that movie service as we did.
Well it's time to keep building and follow along.
Now it's your turn!
So visit the URL at the bottom or just go to the GitHub repo and go to Your Turn.
You'll see a bunch of steps on how you can explore create your own service using some Mockaroo fake data and build something uniquely yours and I'm sure you'll have a lot of fun.
So don't forget the step to go and do a Your Turn and explore the steps are right there.
|
|
show
|
0:30 |
Well, our time together is up, at least in this course.
I want to say thank you for taking our Responder Mini Course.
I hope you had a great time.
I hope you learn something fun and I really appreciate you spending this time together.
Go out there and build something really amazing with Responder or with Vue JS or with some other web framework.
And also, do consider taking other courses at training.talkpython.fm.
We have a bunch and we're always building more.
All right, goodbye and thank you.
|