1 00:00:00,000 --> 00:00:02,994 2 00:00:02,994 --> 00:00:04,990 [MUSIC PLAYING] 3 00:00:04,990 --> 00:01:12,920 4 00:01:12,920 --> 00:01:16,430 DAVID MALAN: All right, this is CS50, and this is already 5 00:01:16,430 --> 00:01:19,040 week nine, which is our second to last. 6 00:01:19,040 --> 00:01:22,460 Indeed, this is really the last week where you'll learn in this class 7 00:01:22,460 --> 00:01:23,450 how to program. 8 00:01:23,450 --> 00:01:25,370 But indeed, it's this week that's really meant 9 00:01:25,370 --> 00:01:29,210 to be the pedagogical climax of all of these various languages we've 10 00:01:29,210 --> 00:01:32,250 been looking at-- all of these various techniques, all of this syntax. 11 00:01:32,250 --> 00:01:34,670 So that at the end of CS50 in just a few weeks, 12 00:01:34,670 --> 00:01:37,070 you indeed feel that you didn't take a class on C, 13 00:01:37,070 --> 00:01:39,530 and you didn't take a class on Python, but you really more 14 00:01:39,530 --> 00:01:41,240 generally took a class on programming. 15 00:01:41,240 --> 00:01:43,670 Because indeed we know already about half of you 16 00:01:43,670 --> 00:01:46,880 will go on to study computer science further, but half of you will not. 17 00:01:46,880 --> 00:01:49,520 And indeed all of your programming chops here on out, 18 00:01:49,520 --> 00:01:51,470 theoretically, will have a foundation in what 19 00:01:51,470 --> 00:01:53,527 we've been doing these past many weeks. 20 00:01:53,527 --> 00:01:55,610 But here on out, it's really going to be up to you 21 00:01:55,610 --> 00:01:58,370 to learn some new fangled language when it comes out, 22 00:01:58,370 --> 00:02:00,830 or to follow some new trend when some language eclipses 23 00:02:00,830 --> 00:02:03,110 the ones we've been using as more popular, as 24 00:02:03,110 --> 00:02:05,640 more appropriate for problems you want to solve. 25 00:02:05,640 --> 00:02:08,090 And so today really is about synthesizing so many 26 00:02:08,090 --> 00:02:11,870 of the past few weeks, but doing it in the context of web programming, which 27 00:02:11,870 --> 00:02:14,150 for better or for worse, is so very much in vogue 28 00:02:14,150 --> 00:02:16,460 nowadays, both on our laptops and phones. 29 00:02:16,460 --> 00:02:19,040 And indeed the languages we looked at in recent weeks are 30 00:02:19,040 --> 00:02:23,300 used not only to make websites, but also full fledged applications, and app 31 00:02:23,300 --> 00:02:24,270 stores, and the like. 32 00:02:24,270 --> 00:02:27,350 So this really will be the culmination of those past several weeks. 33 00:02:27,350 --> 00:02:30,890 And indeed we'll even talk about some familiar concepts like shopping carts 34 00:02:30,890 --> 00:02:33,230 when you're on Amazon, and these things called cookies 35 00:02:33,230 --> 00:02:34,480 when you're visiting websites. 36 00:02:34,480 --> 00:02:36,500 All of those topics too will come into play 37 00:02:36,500 --> 00:02:39,810 and you'll have an understanding of what all that means from the ground up. 38 00:02:39,810 --> 00:02:41,220 So how did we get here? 39 00:02:41,220 --> 00:02:44,990 Well just last week, we focused on HTML and CSS 40 00:02:44,990 --> 00:02:47,000 primarily, which are not programming languages. 41 00:02:47,000 --> 00:02:49,520 They're just about aesthetics, structuring your data, 42 00:02:49,520 --> 00:02:51,780 presenting your data, and so forth. 43 00:02:51,780 --> 00:02:56,600 And we served the web pages we wrote using this program HTTP server. 44 00:02:56,600 --> 00:03:00,380 This is just one such program-- there's dozens, hundreds of different web 45 00:03:00,380 --> 00:03:02,130 servers that you can use out there. 46 00:03:02,130 --> 00:03:05,240 This is just a super simple one we preinstalled in your code space for you 47 00:03:05,240 --> 00:03:08,150 in VS code so that you can just serve up web pages. 48 00:03:08,150 --> 00:03:10,430 At the end of last week too, though, we teased 49 00:03:10,430 --> 00:03:12,980 JavaScript, a full fledged programming language 50 00:03:12,980 --> 00:03:17,300 that you can use to manipulate the user's experience for the better. 51 00:03:17,300 --> 00:03:20,750 To make things more dynamic and interactive by actually running code 52 00:03:20,750 --> 00:03:22,460 in the user's browser-- 53 00:03:22,460 --> 00:03:24,860 on their Mac, their PC, their phone-- as opposed 54 00:03:24,860 --> 00:03:28,730 to server side, which up until now is where all of our code and C and Python 55 00:03:28,730 --> 00:03:29,720 has been written. 56 00:03:29,720 --> 00:03:33,150 So you're writing code on a server, you're serving code from a server, 57 00:03:33,150 --> 00:03:37,910 but now with HTML, CSS, and JavaScript it's getting executed in a browser. 58 00:03:37,910 --> 00:03:41,210 But today we're going to be one final feature of Python-- 59 00:03:41,210 --> 00:03:44,690 or really languages like it-- that you can also use code on the server 60 00:03:44,690 --> 00:03:47,030 to generate automatically dynamically. 61 00:03:47,030 --> 00:03:51,860 The HTML, the JavaScript, the CSS that you actually want the user to receive. 62 00:03:51,860 --> 00:03:54,290 You don't have to hard code everything as you have when 63 00:03:54,290 --> 00:03:55,920 making your own home page. 64 00:03:55,920 --> 00:03:59,130 Well, let's consider what some of the building blocks were last week. 65 00:03:59,130 --> 00:04:02,165 So here's a sample URL, and over here slash 66 00:04:02,165 --> 00:04:04,910 is the default page on any web server. 67 00:04:04,910 --> 00:04:07,430 It might be index.html, it might be something else, 68 00:04:07,430 --> 00:04:08,480 that's just a convention. 69 00:04:08,480 --> 00:04:10,850 But it refers to whatever the default actually is. 70 00:04:10,850 --> 00:04:13,430 You can visit, of course, in any browser-- like a URL that 71 00:04:13,430 --> 00:04:17,089 ends in file.html, or something else dot HTML-- 72 00:04:17,089 --> 00:04:21,320 and that literally means your browser wants this file on this server. 73 00:04:21,320 --> 00:04:23,730 Or of course, we saw that it can be a folder. 74 00:04:23,730 --> 00:04:28,040 And inside of that folder is presumably some default file name, like again, 75 00:04:28,040 --> 00:04:32,360 index.html, or you can be more explicit like folder/file.html, 76 00:04:32,360 --> 00:04:34,460 and these more generally we just called paths. 77 00:04:34,460 --> 00:04:37,850 And indeed a path is just a location on your Mac, your PC, 78 00:04:37,850 --> 00:04:40,770 or on a server of some piece of information. 79 00:04:40,770 --> 00:04:43,010 But today we're just going to rename this only 80 00:04:43,010 --> 00:04:45,830 to use other common terminology, but they're really just synonyms. 81 00:04:45,830 --> 00:04:48,590 Today we're going to refer to those same things as routes 82 00:04:48,590 --> 00:04:52,430 because now today we're going to ultimately replace HTTP server, which 83 00:04:52,430 --> 00:04:56,750 just serves up static content that you all write with your own web server. 84 00:04:56,750 --> 00:04:59,090 Like now you will be the ones controlling 85 00:04:59,090 --> 00:05:02,900 what it is the server does in response to the user's request 86 00:05:02,900 --> 00:05:05,600 so that you can respond interactively and dynamically. 87 00:05:05,600 --> 00:05:08,030 But we're still going to see techniques like this. 88 00:05:08,030 --> 00:05:11,267 These were our so-called HTTP parameters. 89 00:05:11,267 --> 00:05:13,850 They are everything that comes after a question mark in a URL. 90 00:05:13,850 --> 00:05:15,870 And it can be key = value. 91 00:05:15,870 --> 00:05:17,030 An example was, what? 92 00:05:17,030 --> 00:05:19,610 When we played with Google, what was the key 93 00:05:19,610 --> 00:05:22,970 and what was the value that I first tried? 94 00:05:22,970 --> 00:05:24,020 Any recollection? 95 00:05:24,020 --> 00:05:26,550 96 00:05:26,550 --> 00:05:29,370 I was searching for cats and so the key I figured out 97 00:05:29,370 --> 00:05:32,880 was cue because that's what Larry and Sergey who created Google years ago 98 00:05:32,880 --> 00:05:38,160 decided the name would be of the HTML textbox that you type your query into. 99 00:05:38,160 --> 00:05:40,620 And if I type C-A-T for cat, the value of that 100 00:05:40,620 --> 00:05:44,428 would end up in the URL for Google as being a question mark cat = value. 101 00:05:44,428 --> 00:05:46,470 And I mentioned that it's often the case that you 102 00:05:46,470 --> 00:05:48,480 want to send two different inputs to a server. 103 00:05:48,480 --> 00:05:51,438 And this is why I propose that you just keep an eye out for ampersands. 104 00:05:51,438 --> 00:05:53,800 And ampersands separate these key value pairs. 105 00:05:53,800 --> 00:05:56,100 But again, this is the same darn paradigm as before, 106 00:05:56,100 --> 00:05:57,808 and we've seen this so many times, right? 107 00:05:57,808 --> 00:06:00,030 Key value pairs in dictionaries, in Python. 108 00:06:00,030 --> 00:06:03,690 We've seen HTML attributes and their values. 109 00:06:03,690 --> 00:06:06,480 We've seen CSS properties and their values. 110 00:06:06,480 --> 00:06:09,270 It's all the same thing, associating something with something. 111 00:06:09,270 --> 00:06:11,610 Else even though every language, every person 112 00:06:11,610 --> 00:06:15,910 seems to have their own vernacular for it, it really is just the same idea. 113 00:06:15,910 --> 00:06:19,440 This associating of something with something else we'll continue to see. 114 00:06:19,440 --> 00:06:24,600 And, here to be concrete, were the HTTP lines of text 115 00:06:24,600 --> 00:06:26,730 that were in those virtual envelopes, if you will. 116 00:06:26,730 --> 00:06:30,000 If I were indeed selecting-- trying to search for something like cats 117 00:06:30,000 --> 00:06:34,140 on Google, this, recall, was the message that got sent to the server 118 00:06:34,140 --> 00:06:37,020 by my browser in order to tell Google to please search 119 00:06:37,020 --> 00:06:39,900 for not dogs, but in this case cats. 120 00:06:39,900 --> 00:06:42,360 Now what has HTTP server been doing for us? 121 00:06:42,360 --> 00:06:45,900 Well it's just been serving up HTML file, CSS files, maybe some JS 122 00:06:45,900 --> 00:06:50,910 or JavaScript files, but it has been ignoring any HTTP parameters. 123 00:06:50,910 --> 00:06:53,430 Like HTTP server does not take user input. 124 00:06:53,430 --> 00:06:53,970 Why? 125 00:06:53,970 --> 00:06:55,270 Well what's it going to do with it? 126 00:06:55,270 --> 00:06:57,120 Because you already wrote the HTML, you already 127 00:06:57,120 --> 00:06:59,100 wrote the CSS, like there's no decisions to be 128 00:06:59,100 --> 00:07:03,090 made until we introduce a proper programming language on the server. 129 00:07:03,090 --> 00:07:06,540 And so we're going to move away now from this simple HTTP server program 130 00:07:06,540 --> 00:07:11,250 and introduce you to your own server that's going to handle the parsing, 131 00:07:11,250 --> 00:07:13,672 that is the extraction of these key value pairs, 132 00:07:13,672 --> 00:07:16,380 so that you and I don't have to write Python code all of a sudden 133 00:07:16,380 --> 00:07:18,570 that analyzes this stuff, figures out what 134 00:07:18,570 --> 00:07:20,280 pages requested the key value pairs. 135 00:07:20,280 --> 00:07:24,780 All of that we're still going to get for free by just using the right framework. 136 00:07:24,780 --> 00:07:29,310 And so today we revisit Python, which we've now used in some form 137 00:07:29,310 --> 00:07:30,180 the past few weeks. 138 00:07:30,180 --> 00:07:33,150 And indeed it's kind of been the glue that allows us to stitch together 139 00:07:33,150 --> 00:07:34,290 some of our own logic. 140 00:07:34,290 --> 00:07:37,810 We saw it with SQL, we're going to now see it with HTML, CSS, 141 00:07:37,810 --> 00:07:39,185 and even JavaScript if we want. 142 00:07:39,185 --> 00:07:42,060 And we're also going to see another language today, not a programming 143 00:07:42,060 --> 00:07:43,110 language, called Jinja. 144 00:07:43,110 --> 00:07:46,680 And this is going to be a common paradigm in the real world, whereby 145 00:07:46,680 --> 00:07:49,530 different languages, different libraries, different frameworks 146 00:07:49,530 --> 00:07:53,052 often borrow from each other, or they use technologies 147 00:07:53,052 --> 00:07:56,010 that someone else wrote just so they don't have to reinvent that wheel. 148 00:07:56,010 --> 00:07:57,870 So Flask is just a framework. 149 00:07:57,870 --> 00:08:00,720 That is a third party library, it's pretty popular nowadays, 150 00:08:00,720 --> 00:08:03,390 it's relatively simple, which is why we use it in CS50. 151 00:08:03,390 --> 00:08:05,700 If you've programmed before CS50, Django is 152 00:08:05,700 --> 00:08:09,172 another popular framework, or library, in the Python space, 153 00:08:09,172 --> 00:08:10,630 but it's a little more complicated. 154 00:08:10,630 --> 00:08:11,790 So we focus on Flask. 155 00:08:11,790 --> 00:08:14,640 And Jinja, we'll see, is not a programming language. 156 00:08:14,640 --> 00:08:16,560 It's just going to be some syntax-- 157 00:08:16,560 --> 00:08:18,930 thankfully familiar-- with curly braces that 158 00:08:18,930 --> 00:08:22,300 allow us to use placeholders in our actual web pages. 159 00:08:22,300 --> 00:08:24,810 So again, you'll wrap your minds all eventually 160 00:08:24,810 --> 00:08:27,313 around where the lines are among these various technologies, 161 00:08:27,313 --> 00:08:28,980 but these are not the interesting ideas. 162 00:08:28,980 --> 00:08:32,070 The interesting ideas are the ones will focus on in code. 163 00:08:32,070 --> 00:08:35,400 But starting today, instead of running HTTP server 164 00:08:35,400 --> 00:08:40,200 to serve up a static website, we'll have you start running literally Flask space 165 00:08:40,200 --> 00:08:45,750 run in your terminal window to run your own web server that's implemented 166 00:08:45,750 --> 00:08:48,300 in Python using this Flask framework. 167 00:08:48,300 --> 00:08:51,990 So bootstrap was a library for making your CSS 168 00:08:51,990 --> 00:08:54,510 and JavaScript prettier and more interactive. 169 00:08:54,510 --> 00:08:57,030 Flask is a framework, or library, for just 170 00:08:57,030 --> 00:09:00,750 making your Python code more pleasant to use since you're borrowing features 171 00:09:00,750 --> 00:09:02,100 from someone else. 172 00:09:02,100 --> 00:09:04,150 All right, so how can we go about doing this? 173 00:09:04,150 --> 00:09:08,430 Well, if you were to write your very own web application, your own amazon.com, 174 00:09:08,430 --> 00:09:11,670 your own google.com in Python using Flask, 175 00:09:11,670 --> 00:09:15,342 minimally, you need to have a file called app.py by convention, which 176 00:09:15,342 --> 00:09:16,800 is where all your Python code goes. 177 00:09:16,800 --> 00:09:19,810 And then a folder called templates, which is where all of your templates 178 00:09:19,810 --> 00:09:20,310 go. 179 00:09:20,310 --> 00:09:23,050 And for now your templates are just your HTML files. 180 00:09:23,050 --> 00:09:26,250 So if we're going to now start building more interesting interactive things 181 00:09:26,250 --> 00:09:29,760 like google.com or amazon.com, we need to be 182 00:09:29,760 --> 00:09:31,300 able to execute code on the server. 183 00:09:31,300 --> 00:09:32,550 And so this is the convention. 184 00:09:32,550 --> 00:09:34,500 It's not indexed at HTML anymore necessarily, 185 00:09:34,500 --> 00:09:36,750 it's these two things at the top level. 186 00:09:36,750 --> 00:09:39,840 With that said, we'll quickly see that there are some other conventions. 187 00:09:39,840 --> 00:09:43,170 And in my examples online, and in the problem set nine, 188 00:09:43,170 --> 00:09:46,170 you'll see another file called requirements.txt, 189 00:09:46,170 --> 00:09:48,150 which is just a text file that allows you 190 00:09:48,150 --> 00:09:51,690 to enumerate all of the third party libraries your application might 191 00:09:51,690 --> 00:09:52,530 want to use. 192 00:09:52,530 --> 00:09:56,148 It's a convention so that the server can automatically install things for you 193 00:09:56,148 --> 00:09:57,690 without you having to do it manually. 194 00:09:57,690 --> 00:10:01,350 And then static is going to be where literally your static content goes. 195 00:10:01,350 --> 00:10:03,420 So if you've got images for your web application, 196 00:10:03,420 --> 00:10:06,240 if you've got JavaScript files, CSS files, 197 00:10:06,240 --> 00:10:08,040 by convention that goes in static. 198 00:10:08,040 --> 00:10:10,470 These are just conventions, all of this can be changed. 199 00:10:10,470 --> 00:10:12,820 But this is the way to do things. 200 00:10:12,820 --> 00:10:14,890 So we'll introduce you to the defaults. 201 00:10:14,890 --> 00:10:16,660 All right so what does this mean? 202 00:10:16,660 --> 00:10:19,470 How, for instance, could I go about implementing my own web 203 00:10:19,470 --> 00:10:25,440 application using Python that somehow spits out a message like, hello, world? 204 00:10:25,440 --> 00:10:28,160 All right, well turns out, just this. 205 00:10:28,160 --> 00:10:30,150 Now we'll tease this apart in just a moment, 206 00:10:30,150 --> 00:10:35,300 but this is the contents of a sample app.py file that apparently uses some 207 00:10:35,300 --> 00:10:38,485 library stuff-- like familiar syntax from something, import-- 208 00:10:38,485 --> 00:10:39,110 something else. 209 00:10:39,110 --> 00:10:42,110 We've seen that before with CSVs and other libraries-- 210 00:10:42,110 --> 00:10:45,350 this is somewhat new syntax, but it's kind of copy paste for now. 211 00:10:45,350 --> 00:10:48,530 This is definitely new syntax, and kind of weird with the @ sign here. 212 00:10:48,530 --> 00:10:50,330 But we'll see this again and again today. 213 00:10:50,330 --> 00:10:53,820 And it's just copy paste initially until you understand what it's doing for you. 214 00:10:53,820 --> 00:10:56,120 But at least there's some familiar stuff here, 215 00:10:56,120 --> 00:11:00,530 like index.html is still going to be with us, but it's going to be up to us 216 00:11:00,530 --> 00:11:02,742 when and how to show it to the user. 217 00:11:02,742 --> 00:11:03,950 So let's make this more real. 218 00:11:03,950 --> 00:11:09,770 Let me go over to VS code here, and let me go ahead and create a-- 219 00:11:09,770 --> 00:11:11,990 how about we'll do this in Hello-- let me 220 00:11:11,990 --> 00:11:15,050 do mkdir Hello to make a new folder called Hello. 221 00:11:15,050 --> 00:11:17,660 And I'm going to CD into it just to isolate all of these files 222 00:11:17,660 --> 00:11:19,880 to the same directory, so that we have different apps today 223 00:11:19,880 --> 00:11:20,900 and different folders. 224 00:11:20,900 --> 00:11:23,540 And now I'm going to do code of-- 225 00:11:23,540 --> 00:11:24,980 let's do this actually. 226 00:11:24,980 --> 00:11:27,980 Let's do our mkdir templates.html-- 227 00:11:27,980 --> 00:11:29,840 sorry, not templates.html. 228 00:11:29,840 --> 00:11:32,875 Let me rename that to templates using the MV command. 229 00:11:32,875 --> 00:11:35,750 This has nothing to do with web programming, this is me making typos. 230 00:11:35,750 --> 00:11:39,110 So if I type LS now, I've got a folder called templates. 231 00:11:39,110 --> 00:11:43,550 All right, in there let's create a file called index.html 232 00:11:43,550 --> 00:11:47,030 that is going to be super simple and pretty much copy paste from last week. 233 00:11:47,030 --> 00:11:50,420 Let me hide my terminal window, and let me just very quickly whip up 234 00:11:50,420 --> 00:11:53,480 a simple Hello, world page using my HTML tag. 235 00:11:53,480 --> 00:11:59,060 Lang will = English, then inside of this, I'm going to have a head tag. 236 00:11:59,060 --> 00:12:01,160 Inside of this I'm going to have a title tag, 237 00:12:01,160 --> 00:12:03,380 and I'm just going to call this thing Hello. 238 00:12:03,380 --> 00:12:05,540 I'm going to then have a body, and in this I'm 239 00:12:05,540 --> 00:12:08,330 only going to say something simple like, Hello, world. 240 00:12:08,330 --> 00:12:10,400 And just so this is mobile friendly, recall 241 00:12:10,400 --> 00:12:11,900 that we touched on these meta tags. 242 00:12:11,900 --> 00:12:14,840 So just in case you after class play with your mobile device instead 243 00:12:14,840 --> 00:12:19,580 of your laptop, I'll do name = quote unquote "viewport". 244 00:12:19,580 --> 00:12:22,973 Viewport-- and then content = and I never remember this, 245 00:12:22,973 --> 00:12:24,890 I'm literally reading it off of a cheat sheet. 246 00:12:24,890 --> 00:12:27,740 Initial scale = 1. 247 00:12:27,740 --> 00:12:29,930 Width = device width. 248 00:12:29,930 --> 00:12:32,390 And this is just this magical incantation 249 00:12:32,390 --> 00:12:35,120 that says to the browser, size things appropriately 250 00:12:35,120 --> 00:12:37,010 for the size of the device. 251 00:12:37,010 --> 00:12:38,840 It blows up the font sizes a bit. 252 00:12:38,840 --> 00:12:41,090 All right, so that's what I would have done last week. 253 00:12:41,090 --> 00:12:43,180 And I would have served this web page by running 254 00:12:43,180 --> 00:12:46,730 HTTP server in the same directory, and boom, I would see that HTML. 255 00:12:46,730 --> 00:12:49,978 But let's now start to take some control over the user's experience. 256 00:12:49,978 --> 00:12:51,770 And for now it's going to be underwhelming. 257 00:12:51,770 --> 00:12:53,700 It's just going to always say Hello, world. 258 00:12:53,700 --> 00:12:56,690 But in a moment, version two is going to say Hello, David, 259 00:12:56,690 --> 00:12:59,120 or Hello, Carter, a bit more dynamically. 260 00:12:59,120 --> 00:13:02,998 And we'll quickly escalate from there to just more interesting applications as 261 00:13:02,998 --> 00:13:04,790 well, culminating with things like cookies, 262 00:13:04,790 --> 00:13:06,420 and shopping carts, and the like. 263 00:13:06,420 --> 00:13:08,820 So let me go back into my terminal window, 264 00:13:08,820 --> 00:13:13,100 and as promised, let me create another file called app.py. 265 00:13:13,100 --> 00:13:16,670 And this is where now I need to implement the web server I'm going 266 00:13:16,670 --> 00:13:18,622 to run using this Flask framework. 267 00:13:18,622 --> 00:13:20,330 And for now, I'm just going to kind of do 268 00:13:20,330 --> 00:13:24,110 some copy paste from what we saw on the slide a moment ago, 269 00:13:24,110 --> 00:13:25,760 from the Flask library-- 270 00:13:25,760 --> 00:13:27,530 which we've preinstalled for you-- 271 00:13:27,530 --> 00:13:33,470 I'm going to import a function called Flask capital F. It's subtle, 272 00:13:33,470 --> 00:13:34,770 but it's important there. 273 00:13:34,770 --> 00:13:37,970 And I'm also going to import a few other things-- a function called 274 00:13:37,970 --> 00:13:42,080 render template, and another variable called request. 275 00:13:42,080 --> 00:13:45,230 And the only way I know this is from having taught this before, 276 00:13:45,230 --> 00:13:47,797 read the documentation, followed a tutorial. 277 00:13:47,797 --> 00:13:50,880 You wouldn't know this unless someone told you or you read how to do this. 278 00:13:50,880 --> 00:13:52,838 But what this means is that this library called 279 00:13:52,838 --> 00:13:57,110 Flask has three things in it-- a function called Flask capital F, 280 00:13:57,110 --> 00:14:01,002 a function called render template, and a variable built into it called request. 281 00:14:01,002 --> 00:14:02,960 And this is going to be all the building blocks 282 00:14:02,960 --> 00:14:05,570 I need to implement my own web server. 283 00:14:05,570 --> 00:14:09,200 The convention in Flask, when you want to create a web app in Python is you 284 00:14:09,200 --> 00:14:11,420 create a variable by convention called app, 285 00:14:11,420 --> 00:14:16,070 and then you assign it the return value of that Flask function-- capital F-- 286 00:14:16,070 --> 00:14:23,000 and pass into it __name__, which is weird but we have seen this before. 287 00:14:23,000 --> 00:14:29,840 A few weeks ago anyone recall when and why we mention __name__? 288 00:14:29,840 --> 00:14:31,796 Yeah? 289 00:14:31,796 --> 00:14:35,660 AUDIENCE: [INAUDIBLE] 290 00:14:35,660 --> 00:14:41,030 DAVID MALAN: Yeah, if we wanted to check if the name of the file was itself main 291 00:14:41,030 --> 00:14:45,680 so that we avoided a situation where if you're writing your own library code, 292 00:14:45,680 --> 00:14:48,500 you don't want your code to be executed automatically. 293 00:14:48,500 --> 00:14:51,320 You want to potentially execute the main function. 294 00:14:51,320 --> 00:14:53,450 And that was a solution to that problem here. 295 00:14:53,450 --> 00:14:55,670 For today's purposes, this is just the way you do it, 296 00:14:55,670 --> 00:14:58,800 __name__ refers to the current file. 297 00:14:58,800 --> 00:15:02,450 And so this is just a little trick that says turn this file into a Flask 298 00:15:02,450 --> 00:15:03,110 application. 299 00:15:03,110 --> 00:15:06,950 That's all it is, and for now that line suffices. 300 00:15:06,950 --> 00:15:08,760 All right, what do I want to do after that? 301 00:15:08,760 --> 00:15:10,730 Well now I'm in charge of the web server. 302 00:15:10,730 --> 00:15:13,700 I need to write the code that decides, based 303 00:15:13,700 --> 00:15:18,650 on the browser's request, what file or files I'm going to send from the server 304 00:15:18,650 --> 00:15:19,430 to the browser. 305 00:15:19,430 --> 00:15:22,950 Last week HTTP server did all of this for us just based on the file name. 306 00:15:22,950 --> 00:15:25,730 But today I'm going to take over control over that process. 307 00:15:25,730 --> 00:15:27,600 And the way I do that is as follows. 308 00:15:27,600 --> 00:15:32,490 I say app.routh with, weirdly, in @ sign in front of it. 309 00:15:32,490 --> 00:15:34,610 This is known in Python as a decorator. 310 00:15:34,610 --> 00:15:36,800 And it's a feature of Python not of Flask 311 00:15:36,800 --> 00:15:39,950 that we just didn't introduce in weeks past, but it's a special-- 312 00:15:39,950 --> 00:15:42,770 it's a handy trick to do what we're about to do. 313 00:15:42,770 --> 00:15:46,610 The root I want to define is quote unquote "slash", so that is, 314 00:15:46,610 --> 00:15:51,200 here is code I want the server to execute whenever a user visits, 315 00:15:51,200 --> 00:15:53,960 /slash default page of the website. 316 00:15:53,960 --> 00:15:55,940 Well what code do I want them to execute? 317 00:15:55,940 --> 00:15:57,650 Well I want them to execute a function. 318 00:15:57,650 --> 00:16:00,050 And I can therefore define in Python a function. 319 00:16:00,050 --> 00:16:03,650 I can technically call this thing anything I want-- x, or y, or z. 320 00:16:03,650 --> 00:16:06,350 But because they're accessing the default page otherwise known 321 00:16:06,350 --> 00:16:09,770 as the index of the site, I'm going to just more reasonably call 322 00:16:09,770 --> 00:16:10,687 this function index. 323 00:16:10,687 --> 00:16:13,520 But just a convention, you could call it anything you want, but x,y, 324 00:16:13,520 --> 00:16:16,430 or z is probably a bad stylistic choice. 325 00:16:16,430 --> 00:16:18,690 It doesn't need to take any arguments in this case. 326 00:16:18,690 --> 00:16:20,330 And the only thing this code-- 327 00:16:20,330 --> 00:16:24,980 this function is going to do is, for now, let's go ahead 328 00:16:24,980 --> 00:16:29,190 and have it return "Hello, world" quote unquote. 329 00:16:29,190 --> 00:16:31,000 And that's it. 330 00:16:31,000 --> 00:16:35,080 All right now let me go into my terminal window, let me go ahead 331 00:16:35,080 --> 00:16:39,490 and do Flask run in the same directory that has app.py and hit Enter. 332 00:16:39,490 --> 00:16:43,180 I'm going to see some cryptic output, but including a URL of my code space, 333 00:16:43,180 --> 00:16:45,940 and if I open that URL after hovering over it, 334 00:16:45,940 --> 00:16:48,460 I'll indeed see Hello, world as you might hope. 335 00:16:48,460 --> 00:16:49,640 But let me do this. 336 00:16:49,640 --> 00:16:51,910 Let me go ahead and right click on the page 337 00:16:51,910 --> 00:16:55,000 and click View page source, which, if you haven't done before, 338 00:16:55,000 --> 00:16:58,930 shows you all of the HTML for a page, however pretty or messy it is. 339 00:16:58,930 --> 00:17:01,540 And that's it, there's no HTML that I've spit out, 340 00:17:01,540 --> 00:17:04,089 it's just quote unquote "Hello, world". 341 00:17:04,089 --> 00:17:07,569 Well if I actually want to spit out a full web page, which is not 342 00:17:07,569 --> 00:17:09,020 a big deal here because who cares? 343 00:17:09,020 --> 00:17:10,400 It's just the text anyway. 344 00:17:10,400 --> 00:17:14,510 But if I want to spit out a whole file, let me do this. 345 00:17:14,510 --> 00:17:18,190 I want to return, essentially, the contents of index.html, 346 00:17:18,190 --> 00:17:21,710 which have all of the tags I want-- the mobile friendly stuff and all of that. 347 00:17:21,710 --> 00:17:25,540 Well I can't just return index.html, but I can return this. 348 00:17:25,540 --> 00:17:30,190 Render template, quote unquote, "index.html". 349 00:17:30,190 --> 00:17:33,280 And per the documentation for Flask, this render template function 350 00:17:33,280 --> 00:17:36,670 will go find that file for me in my templates folder by convention. 351 00:17:36,670 --> 00:17:39,850 It will open it up and then it will spit the whole thing out 352 00:17:39,850 --> 00:17:43,420 to the browser for me, so I can keep all my HTML in one place, 353 00:17:43,420 --> 00:17:45,890 and all my Python code in this one place. 354 00:17:45,890 --> 00:17:49,540 So now if I go back to my browser and reload, 355 00:17:49,540 --> 00:17:51,340 I don't think I'll really see a difference, 356 00:17:51,340 --> 00:17:53,590 because it's the same text, ultimately. 357 00:17:53,590 --> 00:17:59,230 But if I view page source now, notice that, ah, there is all of the HTML 358 00:17:59,230 --> 00:18:01,430 that was just sent to the browser. 359 00:18:01,430 --> 00:18:04,270 So this is only to say, we have the building blocks-- the puzzle 360 00:18:04,270 --> 00:18:06,520 pieces, if you will-- via which to now store 361 00:18:06,520 --> 00:18:09,050 all of our HTML in one place-- and presumably CSS, 362 00:18:09,050 --> 00:18:12,700 JavaScript, and so forth-- but then serve up whatever we want, 363 00:18:12,700 --> 00:18:16,690 even though I'm just blindly spitting out index.html. 364 00:18:16,690 --> 00:18:20,620 So before we proceed, any questions on this, which again, I claim 365 00:18:20,620 --> 00:18:24,100 is like my manual version of what HTTP server was 366 00:18:24,100 --> 00:18:25,940 doing for us automatically last week. 367 00:18:25,940 --> 00:18:28,110 But this is how you do it yourself. 368 00:18:28,110 --> 00:18:30,620 Any questions? 369 00:18:30,620 --> 00:18:32,850 All right, well let's make it more interesting, 370 00:18:32,850 --> 00:18:36,770 which we could not do with HTTP server and HTML alone. 371 00:18:36,770 --> 00:18:39,750 Why don't we go ahead and do this. 372 00:18:39,750 --> 00:18:42,500 Let me visit the same URL, and I'm going to Zoom in. 373 00:18:42,500 --> 00:18:45,008 And your URL will differ from my code space, 374 00:18:45,008 --> 00:18:46,550 but it's going to end similarly here. 375 00:18:46,550 --> 00:18:51,560 I'm going to do /?name=David, for instance. 376 00:18:51,560 --> 00:18:55,920 Or q=cats, or name=Carter-- any key value pair I want, 377 00:18:55,920 --> 00:18:58,550 I'm going to append after and slash and a question mark, 378 00:18:58,550 --> 00:19:00,560 thereby providing user input to the server. 379 00:19:00,560 --> 00:19:02,443 Albeit in a very user unfriendly way. 380 00:19:02,443 --> 00:19:04,610 No one's going to normally do this in their browser. 381 00:19:04,610 --> 00:19:08,070 Enter-- nothing changes here, it just says Hello, world, 382 00:19:08,070 --> 00:19:10,070 but wouldn't it be nice if it says Hello, David? 383 00:19:10,070 --> 00:19:13,610 Or equivalently, if I Zoom in here again and change David to Carter 384 00:19:13,610 --> 00:19:17,520 and hit Enter, wouldn't it be nice if it says Hello, Carter instead? 385 00:19:17,520 --> 00:19:19,320 So we need some dynamism there. 386 00:19:19,320 --> 00:19:22,160 And here's where now Python is going to be our friend. 387 00:19:22,160 --> 00:19:29,120 If I want to access the HTTP parameters that the user has provided via 388 00:19:29,120 --> 00:19:31,970 the URL-- be it q=cats or name=David-- 389 00:19:31,970 --> 00:19:36,360 I can use this special variable I already preemptively imported earlier. 390 00:19:36,360 --> 00:19:37,650 And I can do this-- 391 00:19:37,650 --> 00:19:40,340 If there is an HTTP parameter called name 392 00:19:40,340 --> 00:19:43,820 in what I'm going to call request.args. 393 00:19:43,820 --> 00:19:47,390 Then I'm going to go ahead and create a variable called name, 394 00:19:47,390 --> 00:19:51,350 and I'm going to set it equal to request.args bracket name. 395 00:19:51,350 --> 00:19:54,290 Else-- if there is no, quote unquote, "name" 396 00:19:54,290 --> 00:19:57,200 key in this special variable called request.args, 397 00:19:57,200 --> 00:20:00,740 I'm going to just assume that the user's name is world by default. Now 398 00:20:00,740 --> 00:20:01,800 what's going on here? 399 00:20:01,800 --> 00:20:05,300 Well, it turns out that Flask provides us with this special variable called 400 00:20:05,300 --> 00:20:10,130 request.args, and in there is all of the key value pairs that 401 00:20:10,130 --> 00:20:12,470 might have come in via the URL. 402 00:20:12,470 --> 00:20:15,860 So if you had to guess what type of a-- 403 00:20:15,860 --> 00:20:19,160 or what data type is request.args? 404 00:20:19,160 --> 00:20:21,410 That's its name, and here is in context. 405 00:20:21,410 --> 00:20:23,750 Line nine might provide a clue. 406 00:20:23,750 --> 00:20:28,710 In Python what data type might request.args be? 407 00:20:28,710 --> 00:20:29,715 Yeah. 408 00:20:29,715 --> 00:20:30,590 AUDIENCE: [INAUDIBLE] 409 00:20:30,590 --> 00:20:33,340 DAVID MALAN: It's not going to be an array or a list because those 410 00:20:33,340 --> 00:20:35,940 are always, in every language we've seen, numerically indexed. 411 00:20:35,940 --> 00:20:38,580 But you're close. 412 00:20:38,580 --> 00:20:39,445 Someone else? 413 00:20:39,445 --> 00:20:40,320 AUDIENCE: [INAUDIBLE] 414 00:20:40,320 --> 00:20:41,612 DAVID MALAN: It's a dictionary. 415 00:20:41,612 --> 00:20:44,790 So a dictionary is similar syntactically to a list in Python, 416 00:20:44,790 --> 00:20:47,520 but instead of numeric indices like 0 1 2, 417 00:20:47,520 --> 00:20:50,373 you can literally use strings like, quote unquote, "name". 418 00:20:50,373 --> 00:20:52,540 Now that's a bit of a white lie, it is a dictionary. 419 00:20:52,540 --> 00:20:55,210 But it's Flasks special fancy version of a dictionary. 420 00:20:55,210 --> 00:20:58,757 But the syntax by which you can access it is exactly the same. 421 00:20:58,757 --> 00:21:00,090 And I actually-- this is a typo. 422 00:21:00,090 --> 00:21:01,780 I didn't mean to say names there. 423 00:21:01,780 --> 00:21:06,160 I meant to say name singular, but otherwise I think the code is correct. 424 00:21:06,160 --> 00:21:08,580 This is going to, on line eight, check if there 425 00:21:08,580 --> 00:21:11,670 is a key called name in request.args, and if so, 426 00:21:11,670 --> 00:21:13,860 it's going to set it equal to that value. 427 00:21:13,860 --> 00:21:15,900 Otherwise it's going to default to world. 428 00:21:15,900 --> 00:21:18,540 I deliberately did not do this. 429 00:21:18,540 --> 00:21:23,130 I added this if else and did not do this why? 430 00:21:23,130 --> 00:21:26,715 What error might happen if I just blindly grab name? 431 00:21:26,715 --> 00:21:30,645 AUDIENCE: [INAUDIBLE] 432 00:21:30,645 --> 00:21:31,520 DAVID MALAN: Exactly. 433 00:21:31,520 --> 00:21:36,680 If there was nothing at the end of the URL that was of the form ?name=someone, 434 00:21:36,680 --> 00:21:38,660 then there would be no name key. 435 00:21:38,660 --> 00:21:41,510 And this is a couple of weeks back, but this would give you 436 00:21:41,510 --> 00:21:43,340 one of those annoying key errors, when you 437 00:21:43,340 --> 00:21:45,110 get a traceback because you screwed up because you 438 00:21:45,110 --> 00:21:46,620 used a string that doesn't exist. 439 00:21:46,620 --> 00:21:49,850 That's why I'm just proactively trying to avoid that situation just like I 440 00:21:49,850 --> 00:21:51,330 might have a couple of weeks ago. 441 00:21:51,330 --> 00:21:55,170 So even though it's more verbose, this is just much more defensive 442 00:21:55,170 --> 00:21:59,090 so that I don't accidentally index into a dictionary where there is no key. 443 00:21:59,090 --> 00:22:02,150 But we'll see how we can tighten this up to be not four lines but one. 444 00:22:02,150 --> 00:22:04,290 But I think now I can do this. 445 00:22:04,290 --> 00:22:08,700 Wouldn't it be nice if now in my index.html file-- 446 00:22:08,700 --> 00:22:10,910 which recall is in my templates folder-- 447 00:22:10,910 --> 00:22:13,670 wouldn't it be nice if I could do the equivalent in C 448 00:22:13,670 --> 00:22:16,020 of like a person S here for instance? 449 00:22:16,020 --> 00:22:19,160 Or in Python, something like this name. 450 00:22:19,160 --> 00:22:22,520 Well it's close, and this is just because a few different humans 451 00:22:22,520 --> 00:22:25,730 invent different languages, invent different frameworks. 452 00:22:25,730 --> 00:22:29,420 The syntax for this in Flask is to actually 453 00:22:29,420 --> 00:22:35,540 do, whoops, two curly braces, and then name of the variable inside of it. 454 00:22:35,540 --> 00:22:36,470 Why? 455 00:22:36,470 --> 00:22:39,270 It's just probably someone figured, what are the odds 456 00:22:39,270 --> 00:22:42,020 that a normal person is ever going to use two curly braces at once 457 00:22:42,020 --> 00:22:42,983 versus just one? 458 00:22:42,983 --> 00:22:44,900 So this is probably decreasing the probability 459 00:22:44,900 --> 00:22:48,170 that people actually want to output literal curly braces like this. 460 00:22:48,170 --> 00:22:51,710 So it's similar in spirit to Python's f strings, it's similar in spirit 461 00:22:51,710 --> 00:22:55,040 to C's person S, It's similar in spirit to SQL's question marks. 462 00:22:55,040 --> 00:22:59,120 Same idea, slightly different syntax, and this there is Jinja. 463 00:22:59,120 --> 00:23:02,720 So it's not programming code per se, it's just a template. 464 00:23:02,720 --> 00:23:05,270 And indeed that's why this folder is called templates. 465 00:23:05,270 --> 00:23:09,410 It is sort of like a blueprint for what I want to be spit out to the user, 466 00:23:09,410 --> 00:23:11,840 but I've got these placeholders like this variable 467 00:23:11,840 --> 00:23:13,980 that I want to plug-in to that value. 468 00:23:13,980 --> 00:23:16,610 Now, this alone is not enough. 469 00:23:16,610 --> 00:23:20,270 Watch what happens if I go back to my other browser and I 470 00:23:20,270 --> 00:23:22,760 reload the page after changing up here. 471 00:23:22,760 --> 00:23:24,420 Let's do name=David again. 472 00:23:24,420 --> 00:23:28,970 Enter-- nothing outputs after the Hello comma. 473 00:23:28,970 --> 00:23:33,198 So it seems that the name variable doesn't exist yet. 474 00:23:33,198 --> 00:23:35,240 And that's why, indeed, if I do view page source, 475 00:23:35,240 --> 00:23:37,040 you can see what was sent to the browser, 476 00:23:37,040 --> 00:23:39,110 something's wrong with my placeholder. 477 00:23:39,110 --> 00:23:41,180 But I just need to be a little more explicit 478 00:23:41,180 --> 00:23:43,010 as to what I want to send where. 479 00:23:43,010 --> 00:23:47,592 So it turns out that the render template function takes not just one argument-- 480 00:23:47,592 --> 00:23:49,550 the name of the template you want to spit out-- 481 00:23:49,550 --> 00:23:53,810 but it takes after that, with commas, all of the placeholders 482 00:23:53,810 --> 00:23:55,020 you want to plug-in. 483 00:23:55,020 --> 00:23:59,510 So for instance, if you want the placeholder to be this-- literally 484 00:23:59,510 --> 00:24:02,310 placeholder inside of those curly braces, 485 00:24:02,310 --> 00:24:05,900 you can then specify as the second argument to render template, 486 00:24:05,900 --> 00:24:11,780 a placeholder named argument equals whatever the name is. 487 00:24:11,780 --> 00:24:15,470 So name is the variable in the lines above, placeholder 488 00:24:15,470 --> 00:24:18,620 is the name of my literal placeholder in the curly braces, 489 00:24:18,620 --> 00:24:22,700 and so now if I go back to my browser and reload this with still, 490 00:24:22,700 --> 00:24:23,450 quote unquote-- 491 00:24:23,450 --> 00:24:29,630 with still ?name=David in the URL, now I indeed see Hello, David. 492 00:24:29,630 --> 00:24:30,920 And if I Zoom in here-- 493 00:24:30,920 --> 00:24:32,330 and let me move over here. 494 00:24:32,330 --> 00:24:34,160 Let me type in Carter and hit Enter-- 495 00:24:34,160 --> 00:24:37,070 now I see Hello, Carter instead. 496 00:24:37,070 --> 00:24:40,518 Now this is a little unnecessary to explicitly call the placeholder 497 00:24:40,518 --> 00:24:43,310 "placeholder", especially if you want to have two or three of them. 498 00:24:43,310 --> 00:24:45,300 So you can actually call this anything you want. 499 00:24:45,300 --> 00:24:48,633 And I'm going to change it back to name, which is a little more straightforward. 500 00:24:48,633 --> 00:24:51,170 The only weird thing here is that now you'll 501 00:24:51,170 --> 00:24:52,910 see that you're writing code like this. 502 00:24:52,910 --> 00:24:56,210 And this is correct, and this is the norm, it just looks weird. 503 00:24:56,210 --> 00:24:58,730 But the thing on the left of the equal sign 504 00:24:58,730 --> 00:25:02,450 is the placeholder you're using in the template, the thing on the right 505 00:25:02,450 --> 00:25:05,610 can be any value you want, including a variable. 506 00:25:05,610 --> 00:25:08,750 So even though I'm naming them exactly the same-- which looks stupid, 507 00:25:08,750 --> 00:25:11,570 admittedly-- this is what people tend to do. 508 00:25:11,570 --> 00:25:13,910 Just because it's simpler than introducing 509 00:25:13,910 --> 00:25:15,470 another word like placeholder. 510 00:25:15,470 --> 00:25:20,140 Any questions now on this? 511 00:25:20,140 --> 00:25:22,710 Any questions on these placeholders? 512 00:25:22,710 --> 00:25:23,280 No? 513 00:25:23,280 --> 00:25:25,470 All right, well let's tighten this up a little bit 514 00:25:25,470 --> 00:25:28,890 and see if we can't get things to be more dynamic still. 515 00:25:28,890 --> 00:25:32,970 Let me propose now that instead of outputting-- 516 00:25:32,970 --> 00:25:36,630 instead of using this condition which made a very simple idea like very 517 00:25:36,630 --> 00:25:38,790 verbose with four different lines, it turns out 518 00:25:38,790 --> 00:25:40,510 there's an easier way to do this. 519 00:25:40,510 --> 00:25:43,410 You can actually still create a variable called name, 520 00:25:43,410 --> 00:25:46,320 and you can set it equal to request.args, 521 00:25:46,320 --> 00:25:50,850 but instead of just blindly indexing into that dictionary, 522 00:25:50,850 --> 00:25:57,150 it turns out that request.args comes with a function as well called GET. 523 00:25:57,150 --> 00:26:01,930 You can pass it an argument that tells you what value you want to get. 524 00:26:01,930 --> 00:26:07,470 And by default, if there is no key called name in that dictionary, 525 00:26:07,470 --> 00:26:10,650 this function will not throw a key error, it's just going to return none, 526 00:26:10,650 --> 00:26:13,470 N-O-N-E, the special variable-- the special value in Python. 527 00:26:13,470 --> 00:26:17,490 So it avoids a bug in your code, but it tightens up four lines into one. 528 00:26:17,490 --> 00:26:19,710 But even nicer, if you read the documentation, 529 00:26:19,710 --> 00:26:23,290 the GET function can also take a explicit default value. 530 00:26:23,290 --> 00:26:26,880 So if you don't want none to be on the screen, like Hello, blank, or-- 531 00:26:26,880 --> 00:26:28,290 I mean, that would be weird too. 532 00:26:28,290 --> 00:26:31,500 You can just put in a default value per the documentation 533 00:26:31,500 --> 00:26:33,460 of this function like world. 534 00:26:33,460 --> 00:26:36,160 So now we've gone from four lines to just one. 535 00:26:36,160 --> 00:26:37,590 So arguably it's better designed. 536 00:26:37,590 --> 00:26:39,690 And if I go back to the browser now still 537 00:26:39,690 --> 00:26:43,260 with Carter in the URL and hit reload, same thing happens, 538 00:26:43,260 --> 00:26:45,070 but we'll notice this. 539 00:26:45,070 --> 00:26:50,280 Suppose I get rid of the name parameter altogether and hit Enter, 540 00:26:50,280 --> 00:26:52,230 now it goes to the default instead-- 541 00:26:52,230 --> 00:26:52,780 world. 542 00:26:52,780 --> 00:26:57,430 So it's just a little better designed than doing it the other way instead. 543 00:26:57,430 --> 00:27:00,300 All right, how about we take things up one more notch. 544 00:27:00,300 --> 00:27:03,540 And how about we introduce multiple routes? 545 00:27:03,540 --> 00:27:06,420 And actually introduce, perhaps, a form to the mix. 546 00:27:06,420 --> 00:27:10,740 Because again, no normal person is going to visit a URL and add 547 00:27:10,740 --> 00:27:14,610 and a question mark and their name, that's not how browsers work. 548 00:27:14,610 --> 00:27:17,940 Well that's how browsers work, that's not how humans interact with browsers. 549 00:27:17,940 --> 00:27:20,320 You and I use a form, typically, instead. 550 00:27:20,320 --> 00:27:22,320 So now things can get a little more interesting 551 00:27:22,320 --> 00:27:25,530 when making our own web application because maybe we 552 00:27:25,530 --> 00:27:27,550 could do something like this. 553 00:27:27,550 --> 00:27:29,740 Let me go and Zoom out again. 554 00:27:29,740 --> 00:27:33,900 Let me go back to my code here, and let me move this around and focus now 555 00:27:33,900 --> 00:27:36,120 on the index.html file. 556 00:27:36,120 --> 00:27:38,850 Instead of just this placeholder, why don't we 557 00:27:38,850 --> 00:27:42,360 go ahead and give ourselves a form like we've played with a little bit 558 00:27:42,360 --> 00:27:44,820 in the past, be it for Google or something else. 559 00:27:44,820 --> 00:27:47,400 And let's do this form. 560 00:27:47,400 --> 00:27:50,160 And inside of this form, let's have an input. 561 00:27:50,160 --> 00:27:53,160 And the name of this input will be, quote unquote, "name". 562 00:27:53,160 --> 00:27:54,480 So that, too, is confusing. 563 00:27:54,480 --> 00:27:58,780 But inputs have name attributes, but this is a person's name. 564 00:27:58,780 --> 00:28:00,580 So I'm saying name=name here. 565 00:28:00,580 --> 00:28:03,120 So just a messy world of semantics. 566 00:28:03,120 --> 00:28:07,470 And let me go ahead and make this a text box by default. And then 567 00:28:07,470 --> 00:28:11,760 let me give myself a button whose default type will be submit. 568 00:28:11,760 --> 00:28:14,740 And the name of this button will be greet for instance. 569 00:28:14,740 --> 00:28:16,830 So let's see what happens here, but let me change 570 00:28:16,830 --> 00:28:18,750 app.py to just be the original simpler. 571 00:28:18,750 --> 00:28:22,110 I'm not passing in any placeholders now, and I'm going to even get rid of this. 572 00:28:22,110 --> 00:28:25,120 I'm just going to rewind to the first version of this for simplicity. 573 00:28:25,120 --> 00:28:28,990 Let's now change the URL to get rid of Carter and myself. 574 00:28:28,990 --> 00:28:33,990 So we just go to and hit Enter, and now we have a super simple form again. 575 00:28:33,990 --> 00:28:35,910 All right, this is not super user friendly, 576 00:28:35,910 --> 00:28:37,890 but there's some nice enhancements we can make. 577 00:28:37,890 --> 00:28:41,760 For instance, we can, for instance turn off autocomplete, 578 00:28:41,760 --> 00:28:44,010 especially if I want to type David and Carter manually 579 00:28:44,010 --> 00:28:46,470 and I don't want it finishing my thought during class. 580 00:28:46,470 --> 00:28:49,177 We can do auto focus which puts the cursor there blinking 581 00:28:49,177 --> 00:28:51,510 by default, which is nice because then the human doesn't 582 00:28:51,510 --> 00:28:52,870 have to deal with that. 583 00:28:52,870 --> 00:28:55,170 And then we can even have a placeholder attribute. 584 00:28:55,170 --> 00:28:59,320 Placeholder=name so that it's like built in instructions for this thing. 585 00:28:59,320 --> 00:29:01,440 And so now if I go back to the other tab, 586 00:29:01,440 --> 00:29:05,252 nothing's changed yet because I have to download the HTML again, reload-- 587 00:29:05,252 --> 00:29:06,960 OK, now it's a little more user friendly. 588 00:29:06,960 --> 00:29:08,580 It says name in light gray. 589 00:29:08,580 --> 00:29:11,410 The cursor is blinking and I'm sort of ready to go. 590 00:29:11,410 --> 00:29:16,300 But this form hasn't been wired up to go anywhere yet, and so let's do this. 591 00:29:16,300 --> 00:29:19,815 Let's, for instance, say that the action of this form 592 00:29:19,815 --> 00:29:21,690 is not going to be something like google.com, 593 00:29:21,690 --> 00:29:23,550 which we did last time with for cats. 594 00:29:23,550 --> 00:29:28,440 I am now going to be both the front end and the back end of this website. 595 00:29:28,440 --> 00:29:31,740 The front end is what the human sees-- the web page, the graphics, the forms. 596 00:29:31,740 --> 00:29:33,840 The back end is the stuff the human typically 597 00:29:33,840 --> 00:29:37,600 doesn't see-- the Python code, the SQL code, the server itself. 598 00:29:37,600 --> 00:29:42,390 But now I'm in control of both sides of the experience, the HTML and also 599 00:29:42,390 --> 00:29:43,300 the roots. 600 00:29:43,300 --> 00:29:46,530 So let's just propose that we invent our own route, 601 00:29:46,530 --> 00:29:51,030 and instead of calling it /search like Google does, let's call it /greet. 602 00:29:51,030 --> 00:29:54,070 And let me specify that the method this form will use, 603 00:29:54,070 --> 00:29:56,280 which is technically the default, will be gets. 604 00:29:56,280 --> 00:29:59,940 And confusingly, it is lowercase get even though in the envelope 605 00:29:59,940 --> 00:30:02,490 we keep talking about virtually, it's actually capitals. 606 00:30:02,490 --> 00:30:06,150 Again, left hand wasn't talking to right hand when these things were decided. 607 00:30:06,150 --> 00:30:10,740 All right, so all I've done is create a web form that's going to submit 608 00:30:10,740 --> 00:30:14,640 whatever the textbox value is to a route called /greet. 609 00:30:14,640 --> 00:30:19,020 By default, because there's no HTTP, or HTTPS, or no domain name, 610 00:30:19,020 --> 00:30:22,330 /greet is going to be assumed to be not a google.com, 611 00:30:22,330 --> 00:30:25,120 but whatever my own server's URL is. 612 00:30:25,120 --> 00:30:29,440 So whatever my code space's URL is, that's going to be the implicit prefix. 613 00:30:29,440 --> 00:30:31,940 This /greet is just the route. 614 00:30:31,940 --> 00:30:36,280 So now let's go back to VS codes app.py file. 615 00:30:36,280 --> 00:30:39,010 How do I now stitch this together? 616 00:30:39,010 --> 00:30:41,620 Well, I think we're good to go with index.html. 617 00:30:41,620 --> 00:30:45,070 If index.html's purpose in life is just to spit out this form, 618 00:30:45,070 --> 00:30:47,260 we're done with one of my routes. 619 00:30:47,260 --> 00:30:50,080 But if I want to have a second route-- greet-- 620 00:30:50,080 --> 00:30:54,310 that actually spits out some greeting to the user, 621 00:30:54,310 --> 00:30:56,350 well let's prepare that template too. 622 00:30:56,350 --> 00:30:58,990 Let me go ahead and highlight all of this HTML. 623 00:30:58,990 --> 00:31:04,690 Let me go back into my terminal window and into my Hello directory, 624 00:31:04,690 --> 00:31:06,880 and then into my templates directory. 625 00:31:06,880 --> 00:31:09,520 And let me create another template called greet. 626 00:31:09,520 --> 00:31:14,260 HTML whose purpose in life will not be to show a form but to greet the user 627 00:31:14,260 --> 00:31:15,640 with Hello so-and-so. 628 00:31:15,640 --> 00:31:19,030 So in this file I'm going to paste all that same HTML, 629 00:31:19,030 --> 00:31:21,670 but I'm going to get rid of the form and essentially revert 630 00:31:21,670 --> 00:31:22,750 to our previous version-- 631 00:31:22,750 --> 00:31:26,830 Hello comma-- and then using the Jinja syntax name. 632 00:31:26,830 --> 00:31:30,220 So one template-- index.html-- is for the form. 633 00:31:30,220 --> 00:31:34,150 The second template, now, is for the greeting of Hello comma so-and-so. 634 00:31:34,150 --> 00:31:37,730 But otherwise these files, notice, are almost the same, 635 00:31:37,730 --> 00:31:41,050 except one has the form, one has just the Hello. 636 00:31:41,050 --> 00:31:43,310 So now let's finish this up in app.py. 637 00:31:43,310 --> 00:31:46,960 Let me go down here after a couple of blank lines stylistically, 638 00:31:46,960 --> 00:31:51,107 let me do app.route, quote unquote, "/greet"-- 639 00:31:51,107 --> 00:31:52,940 but I could call this route anything I want. 640 00:31:52,940 --> 00:31:54,760 I'm just using a reasonable verb. 641 00:31:54,760 --> 00:31:56,380 Then let's define another function. 642 00:31:56,380 --> 00:31:58,930 I could call a function anything I want, X,Y, or Z. 643 00:31:58,930 --> 00:32:01,120 I'm going to call it more reasonably greet. 644 00:32:01,120 --> 00:32:02,260 No arguments. 645 00:32:02,260 --> 00:32:05,020 And then now is the code where I want to render the template. 646 00:32:05,020 --> 00:32:08,335 So I do return, render, template, greet. 647 00:32:08,335 --> 00:32:09,760 HTML. 648 00:32:09,760 --> 00:32:13,390 But I need to do one more thing. 649 00:32:13,390 --> 00:32:16,750 What else do I want to do if I want greet.html to have access 650 00:32:16,750 --> 00:32:18,760 to the human's name? 651 00:32:18,760 --> 00:32:21,250 Just to recap. 652 00:32:21,250 --> 00:32:23,500 I think we solved this already but I deleted it. 653 00:32:23,500 --> 00:32:26,930 But what do I have to add back? 654 00:32:26,930 --> 00:32:27,845 Yeah. 655 00:32:27,845 --> 00:32:28,720 AUDIENCE: [INAUDIBLE] 656 00:32:28,720 --> 00:32:31,540 DAVID MALAN: Yeah, so I got to pass in the placeholder somehow. 657 00:32:31,540 --> 00:32:33,412 So I can do this a couple of different ways. 658 00:32:33,412 --> 00:32:35,620 I'm going to keep it a little more elegant this time. 659 00:32:35,620 --> 00:32:38,290 I'm just going to put my name-- 660 00:32:38,290 --> 00:32:43,090 argument-- there, and I'm going to set it equal to request.args.GET, 661 00:32:43,090 --> 00:32:45,670 quote unquote, "name", "world". 662 00:32:45,670 --> 00:32:48,715 Before I used a separate variable, but I only used it in one place, 663 00:32:48,715 --> 00:32:50,090 so that's not strictly necessary. 664 00:32:50,090 --> 00:32:53,260 So this is fine too, but if this gets a little overwhelming, 665 00:32:53,260 --> 00:32:55,570 notice that I can alternatively do this. 666 00:32:55,570 --> 00:32:58,150 I can create an actual variable called name 667 00:32:58,150 --> 00:33:02,410 and then I can pass in an argument called name 668 00:33:02,410 --> 00:33:04,630 with a value that is that variable. 669 00:33:04,630 --> 00:33:06,790 But again, what's really the point here? 670 00:33:06,790 --> 00:33:08,530 It was kind of prettier all on one line. 671 00:33:08,530 --> 00:33:10,363 So these are the exact same things, I'm just 672 00:33:10,363 --> 00:33:12,705 trying to tighten things up further here. 673 00:33:12,705 --> 00:33:14,080 All right, so what just happened? 674 00:33:14,080 --> 00:33:17,470 If I go back to my form, this is still index.html. 675 00:33:17,470 --> 00:33:19,390 If I reload it, nothing has changed. 676 00:33:19,390 --> 00:33:21,830 If I type in my name to this form-- 677 00:33:21,830 --> 00:33:24,490 Notice again, the URL I'm currently at-- 678 00:33:24,490 --> 00:33:27,550 this is Chrome hiding things, it's technically / by default, 679 00:33:27,550 --> 00:33:31,180 even though many browsers are just hiding unnecessary characters 680 00:33:31,180 --> 00:33:31,870 these days. 681 00:33:31,870 --> 00:33:35,140 But watch what happens now if I scroll over here 682 00:33:35,140 --> 00:33:38,870 and I click greet on this new form. 683 00:33:38,870 --> 00:33:39,580 Notice? 684 00:33:39,580 --> 00:33:45,760 My URL, my route changed to /greet ?name=David. 685 00:33:45,760 --> 00:33:49,118 And the body of the page at top left says, Hello, David. 686 00:33:49,118 --> 00:33:51,160 So this is exactly how google.com works, and it's 687 00:33:51,160 --> 00:33:53,560 how we implemented HTML last time. 688 00:33:53,560 --> 00:33:58,360 But instead of submitting the form to Google via the form, 689 00:33:58,360 --> 00:34:00,910 I'm submitting it to myself, my very own route. 690 00:34:00,910 --> 00:34:05,570 So I'm implementing my own back end for this same front end. 691 00:34:05,570 --> 00:34:08,237 All right, any questions just yet? 692 00:34:08,237 --> 00:34:10,070 Much less interesting than Google certainly, 693 00:34:10,070 --> 00:34:15,380 but we kind of have all of the wiring now. 694 00:34:15,380 --> 00:34:17,929 Any questions? 695 00:34:17,929 --> 00:34:19,429 No? 696 00:34:19,429 --> 00:34:23,929 All right, so what can we do to further tighten this 697 00:34:23,929 --> 00:34:25,550 up and adhere to some conventions? 698 00:34:25,550 --> 00:34:30,179 Well let me propose that in this version we solve one problem. 699 00:34:30,179 --> 00:34:32,179 And even if you've never done this sort of thing 700 00:34:32,179 --> 00:34:35,000 before, I daresay we have enough weeks of CS50 where 701 00:34:35,000 --> 00:34:39,739 if I show you index.html again and greet.HTML again, 702 00:34:39,739 --> 00:34:46,070 odds are to someone's mind there's a opportunity for improvement. 703 00:34:46,070 --> 00:34:50,510 Why is this web app-- super simple though it is-- arguably poorly 704 00:34:50,510 --> 00:34:53,929 designed at the moment? 705 00:34:53,929 --> 00:34:57,200 And the answer lies somewhere in these two templates-- 706 00:34:57,200 --> 00:34:59,750 index.html and greet.HTML. 707 00:34:59,750 --> 00:35:01,658 AUDIENCE: [INAUDIBLE] 708 00:35:01,658 --> 00:35:03,950 DAVID MALAN: Yeah, they're almost the exact same except 709 00:35:03,950 --> 00:35:05,390 for the contents of the body. 710 00:35:05,390 --> 00:35:07,640 And it wasn't a big deal, there's only two pages. 711 00:35:07,640 --> 00:35:09,380 So what I copy pasted this once? 712 00:35:09,380 --> 00:35:11,810 But imagine, now, a normal website, or even your home 713 00:35:11,810 --> 00:35:14,690 pages which had three, four, or more pages. 714 00:35:14,690 --> 00:35:16,760 I mean at this point, you're just copying 715 00:35:16,760 --> 00:35:18,980 and pasting everything, honestly, as you probably 716 00:35:18,980 --> 00:35:21,240 did necessarily for your home page. 717 00:35:21,240 --> 00:35:21,740 Why? 718 00:35:21,740 --> 00:35:25,130 Because when you have HTML only, maybe CSS, and even JavaScript, 719 00:35:25,130 --> 00:35:28,070 that's all you can do is copy paste, copy paste, 720 00:35:28,070 --> 00:35:30,530 and just make sure that you have the same structure. 721 00:35:30,530 --> 00:35:33,150 Maybe you have the same CSS file, the same JavaScript file, 722 00:35:33,150 --> 00:35:35,400 the same third party libraries, but it makes it very, 723 00:35:35,400 --> 00:35:38,090 very annoying as you might have realized already to just make 724 00:35:38,090 --> 00:35:40,050 a change that affects everything. 725 00:35:40,050 --> 00:35:44,360 So wouldn't it be nice to factor out all of this and all of this 726 00:35:44,360 --> 00:35:46,290 and just let the body change? 727 00:35:46,290 --> 00:35:50,270 So here too is something that Flask and really other equivalent frameworks 728 00:35:50,270 --> 00:35:51,390 let us do. 729 00:35:51,390 --> 00:35:54,170 It allows us to create what we're going to call conventionally 730 00:35:54,170 --> 00:35:55,398 a layout instead. 731 00:35:55,398 --> 00:35:56,940 So I'm going to go ahead and do this. 732 00:35:56,940 --> 00:36:00,620 I'm going to copy one last time all of the same HTML. 733 00:36:00,620 --> 00:36:03,680 I'm going to go into my terminal window and I'm 734 00:36:03,680 --> 00:36:07,580 going to create by convention a file called layout.HTML. 735 00:36:07,580 --> 00:36:10,340 This is truly going to be a blueprint of sorts. 736 00:36:10,340 --> 00:36:14,000 And in layout.HTML, I'm going to paste all of that same code, 737 00:36:14,000 --> 00:36:17,180 but I'm going to use now some Jinja syntax 738 00:36:17,180 --> 00:36:22,220 to indicate that I don't want to plug-in just a variable like name here, 739 00:36:22,220 --> 00:36:26,220 I want to actually plug the contents of a whole other file. 740 00:36:26,220 --> 00:36:29,780 So instead of just using curly braces, two of them left and right, 741 00:36:29,780 --> 00:36:34,160 I have to use slightly different syntax to say I want a whole block of HTML 742 00:36:34,160 --> 00:36:35,790 here from some other file. 743 00:36:35,790 --> 00:36:39,830 And the way to do this, even though the syntax is a little non obvious, is you 744 00:36:39,830 --> 00:36:43,790 use open curly brace, percent sign, block, 745 00:36:43,790 --> 00:36:46,310 then you can call the next word anything you want. 746 00:36:46,310 --> 00:36:49,670 It just has to be a special type of placeholder for an actual file, 747 00:36:49,670 --> 00:36:51,480 not for just a variable. 748 00:36:51,480 --> 00:36:54,000 I'm going to call it body only because I'm in the body. 749 00:36:54,000 --> 00:36:56,670 So I want a placeholder to be the entire body. 750 00:36:56,670 --> 00:37:00,440 And then outside of this, you then say in one word, no space-- 751 00:37:00,440 --> 00:37:01,640 endblock. 752 00:37:01,640 --> 00:37:03,590 So it looks kind of stupid, honestly. 753 00:37:03,590 --> 00:37:05,450 And why do we have yet more ugly syntax? 754 00:37:05,450 --> 00:37:07,910 Again, just different software developers in the world 755 00:37:07,910 --> 00:37:10,340 are all choosing their own syntax for their own libraries. 756 00:37:10,340 --> 00:37:13,130 So they all kind of look different but are all kind of similar in spirit. 757 00:37:13,130 --> 00:37:15,410 And you just get used to seeing the different syntax. 758 00:37:15,410 --> 00:37:20,870 This now is not nearly as pretty as the pair of curly braces for variables, 759 00:37:20,870 --> 00:37:25,100 but this is how I can say plug the contents of an entire file here. 760 00:37:25,100 --> 00:37:27,290 And now what does this let me do? 761 00:37:27,290 --> 00:37:33,500 I can now go back into my index.html file, which at the moment 762 00:37:33,500 --> 00:37:36,740 still looks like this, but almost all of this is copy paste. 763 00:37:36,740 --> 00:37:39,920 The only lines that are interesting and different 764 00:37:39,920 --> 00:37:42,600 are these four lines here in the body. 765 00:37:42,600 --> 00:37:45,600 So what I can actually do now is I'm going to highlight that and cut it, 766 00:37:45,600 --> 00:37:47,558 and then I'm going to highlight everything else 767 00:37:47,558 --> 00:37:49,160 and just delete the entire file. 768 00:37:49,160 --> 00:37:52,190 And I'm going to use some of that same syntax and say 769 00:37:52,190 --> 00:38:02,030 [? %extends"layout.html"% ?] And then I close my thought with a % and closed 770 00:38:02,030 --> 00:38:03,090 curly brace. 771 00:38:03,090 --> 00:38:05,510 So this syntax as you might just be inferring 772 00:38:05,510 --> 00:38:10,760 is now saying, please extend whatever layout.HTML looks like. 773 00:38:10,760 --> 00:38:13,250 That's the original blueprint, the mold out 774 00:38:13,250 --> 00:38:15,020 of which I want to make this web page. 775 00:38:15,020 --> 00:38:18,480 And now here the syntax is a little weird too, but similar, 776 00:38:18,480 --> 00:38:19,520 at least from before. 777 00:38:19,520 --> 00:38:21,260 I can now say the block-- 778 00:38:21,260 --> 00:38:25,250 the body block that I want you to plug into that layout 779 00:38:25,250 --> 00:38:31,040 is going to be everything between these two tags, which we already saw earlier. 780 00:38:31,040 --> 00:38:35,150 But in layout.HTML, They're sort of giving a placeholder. 781 00:38:35,150 --> 00:38:39,830 In index.html, this is what I'm going to plug-in to those other placeholders 782 00:38:39,830 --> 00:38:40,530 as well. 783 00:38:40,530 --> 00:38:42,822 So I'm just going to give myself some extra whitespace. 784 00:38:42,822 --> 00:38:45,070 I'm going to paste the HTML that was there. 785 00:38:45,070 --> 00:38:46,820 If I want to make clear what's going on, I 786 00:38:46,820 --> 00:38:49,490 can indent it, although this has no functional impact. 787 00:38:49,490 --> 00:38:53,060 But it just makes clear that just like in HTML, you can open a Jinja tag 788 00:38:53,060 --> 00:38:53,930 and close it. 789 00:38:53,930 --> 00:38:57,740 But in Jinja here, we have this here-- 790 00:38:57,740 --> 00:39:00,420 hey Python, here comes the body of this page. 791 00:39:00,420 --> 00:39:03,170 Hey Python, that's it for the body of this page. 792 00:39:03,170 --> 00:39:08,630 And all of this stuff should be plugged into this main parent layout, 793 00:39:08,630 --> 00:39:09,510 if you will. 794 00:39:09,510 --> 00:39:12,230 So super ugly, admittedly, but now at least 795 00:39:12,230 --> 00:39:14,210 things get way less redundant because I'm going 796 00:39:14,210 --> 00:39:16,070 to do the exact same thing over here. 797 00:39:16,070 --> 00:39:18,710 In greet.HTML, it looks like this. 798 00:39:18,710 --> 00:39:25,580 But now I'm going to do this-- extends, layout.HTML also, just as before. 799 00:39:25,580 --> 00:39:31,310 The body that I want to plug-in is going to be everything inside of these tags 800 00:39:31,310 --> 00:39:31,880 here. 801 00:39:31,880 --> 00:39:38,190 And this body is just going to be Hello, name in curly braces like that. 802 00:39:38,190 --> 00:39:40,910 So again, ugly-- syntax got really ugly fast. 803 00:39:40,910 --> 00:39:43,437 But it's really just following these patterns now. 804 00:39:43,437 --> 00:39:45,020 And we have two types of placeholders. 805 00:39:45,020 --> 00:39:48,830 Two curly braces for variables, and now this kind 806 00:39:48,830 --> 00:39:51,500 of syntax with the percent signs and the single curly 807 00:39:51,500 --> 00:39:54,650 braces for contents of actual files. 808 00:39:54,650 --> 00:39:58,400 And so now in this world-- or in the world of a home page, 809 00:39:58,400 --> 00:40:01,310 if you were using Flask and Python to make your personal home 810 00:40:01,310 --> 00:40:04,100 page with all of those various pages, you would probably 811 00:40:04,100 --> 00:40:08,030 design one main layout with all of your pretty logos and colors and fonts 812 00:40:08,030 --> 00:40:09,920 and what you want the site to look like. 813 00:40:09,920 --> 00:40:12,290 And then each of your smaller pages would now 814 00:40:12,290 --> 00:40:15,260 be distilled into just these smaller fragments. 815 00:40:15,260 --> 00:40:19,490 And whether using Python, or Java, or JavaScript, or other languages too, 816 00:40:19,490 --> 00:40:22,340 all different programming languages have popular frameworks 817 00:40:22,340 --> 00:40:23,570 that do things like this. 818 00:40:23,570 --> 00:40:26,735 The idea is the same across all of them. 819 00:40:26,735 --> 00:40:28,110 All right, let's see if it works. 820 00:40:28,110 --> 00:40:29,700 Let's go back into the browser. 821 00:40:29,700 --> 00:40:32,780 Let me go back to my /route. 822 00:40:32,780 --> 00:40:34,160 There's that same form. 823 00:40:34,160 --> 00:40:37,310 Let me type in David and type-- and click greet. 824 00:40:37,310 --> 00:40:41,870 And indeed I see Hello, David, I see that greet was automatically 825 00:40:41,870 --> 00:40:44,690 added to the URL by the browser when I submitted the form, followed 826 00:40:44,690 --> 00:40:46,080 by the key value pairs. 827 00:40:46,080 --> 00:40:48,870 And if I view the page source as I did earlier, 828 00:40:48,870 --> 00:40:51,770 you'll see that you have the entirety of that layout 829 00:40:51,770 --> 00:40:54,030 with Hello, David plugged in. 830 00:40:54,030 --> 00:40:58,380 Meanwhile, if I go back to the form and view this page source, 831 00:40:58,380 --> 00:41:02,370 you'll see the exact same layout, but with the form tag plugged in. 832 00:41:02,370 --> 00:41:06,320 And here's where you can be a little less nitpicky with styling. 833 00:41:06,320 --> 00:41:09,170 OK, yes this isn't technically indented inside of the body. 834 00:41:09,170 --> 00:41:11,190 But it was relative to the original file. 835 00:41:11,190 --> 00:41:13,130 So at this point in the game, you don't need 836 00:41:13,130 --> 00:41:16,190 to worry about your outputted HTML looking super pretty. 837 00:41:16,190 --> 00:41:18,320 You want your source code that the humans 838 00:41:18,320 --> 00:41:20,430 see to be pretty, not the browser. 839 00:41:20,430 --> 00:41:23,000 This is not a stylistic concern. 840 00:41:23,000 --> 00:41:29,130 OK, questions on these capabilities then a Flask? 841 00:41:29,130 --> 00:41:31,830 Or problems that we've just solved and why? 842 00:41:31,830 --> 00:41:32,859 Yeah. 843 00:41:32,859 --> 00:41:37,573 AUDIENCE: [INAUDIBLE] 844 00:41:37,573 --> 00:41:38,240 DAVID MALAN: OK. 845 00:41:38,240 --> 00:41:41,420 So if the files in question are in different folders-- 846 00:41:41,420 --> 00:41:48,080 For instance, if I go back into my index page, which has the form, 847 00:41:48,080 --> 00:41:53,330 the roots here are entirely dependent on what is in app.py. 848 00:41:53,330 --> 00:41:57,500 There's no notion of a folder when it comes to implementing a web 849 00:41:57,500 --> 00:41:58,650 application anymore. 850 00:41:58,650 --> 00:42:00,140 They are more generically routes. 851 00:42:00,140 --> 00:42:02,480 However, and we've not done this yet, you 852 00:42:02,480 --> 00:42:05,780 can put your static content-- your images, your video files, 853 00:42:05,780 --> 00:42:07,880 your CSS files-- in a folder called static, 854 00:42:07,880 --> 00:42:09,870 and there can be subfolders they're in. 855 00:42:09,870 --> 00:42:14,060 And that would affect what you use as your source attributes for images, 856 00:42:14,060 --> 00:42:18,890 or your source tags for video, or any of those kinds of assets. 857 00:42:18,890 --> 00:42:22,730 And we'll see that eventually in the home-- in the problem set next. 858 00:42:22,730 --> 00:42:24,900 Other questions on what we've just done here? 859 00:42:24,900 --> 00:42:25,400 Yeah. 860 00:42:25,400 --> 00:42:27,170 AUDIENCE: [INAUDIBLE] 861 00:42:27,170 --> 00:42:28,920 DAVID MALAN: Good question, how do I-- how 862 00:42:28,920 --> 00:42:31,770 did I ensure that the web app starts on the form 863 00:42:31,770 --> 00:42:34,230 and then goes to the Hello page? 864 00:42:34,230 --> 00:42:38,370 So whatever you decide your default index route 865 00:42:38,370 --> 00:42:41,010 is, like the implicit slash, that is what 866 00:42:41,010 --> 00:42:44,520 is going to be pulled up when a user visits the domain name where 867 00:42:44,520 --> 00:42:45,880 your website is hosted. 868 00:42:45,880 --> 00:42:51,750 So if I go back over here to app.py, because my /route is designed to return 869 00:42:51,750 --> 00:42:56,460 index.html, that's exactly why that response came back. 870 00:42:56,460 --> 00:42:57,720 Good question. 871 00:42:57,720 --> 00:43:00,797 All right, so beyond this, let's consider, now, issues of privacy. 872 00:43:00,797 --> 00:43:03,630 And we'll touch on this too, as we get to issues like shopping carts 873 00:43:03,630 --> 00:43:06,610 and cookies, if I Zoom in on the URL here-- 874 00:43:06,610 --> 00:43:09,870 even though the URL itself is a little long and ugly and cryptic-- 875 00:43:09,870 --> 00:43:13,500 but when I type in my name and hit greet, 876 00:43:13,500 --> 00:43:18,060 of course we keep seeing name=David in the URL. 877 00:43:18,060 --> 00:43:22,010 In what sense might this be bad design? 878 00:43:22,010 --> 00:43:26,390 Or in what kinds of web apps might you not want the name 879 00:43:26,390 --> 00:43:28,010 to show up in the URL like that? 880 00:43:28,010 --> 00:43:31,920 Because this is what Google does, and this is what my app does. 881 00:43:31,920 --> 00:43:32,420 Yeah. 882 00:43:32,420 --> 00:43:33,360 AUDIENCE: [INAUDIBLE] 883 00:43:33,360 --> 00:43:34,110 DAVID MALAN: Yeah. 884 00:43:34,110 --> 00:43:36,540 So if I'm logging in with a username and password, 885 00:43:36,540 --> 00:43:40,710 I could imagine that they show up in the URL after the question mark where 886 00:43:40,710 --> 00:43:47,490 username= malan and password=12345, but then all my nosey siblings need to do 887 00:43:47,490 --> 00:43:49,440 is go through my browser history and boom, 888 00:43:49,440 --> 00:43:51,630 it's right there for them to copy paste. 889 00:43:51,630 --> 00:43:54,000 So that doesn't seem particularly secure. 890 00:43:54,000 --> 00:43:57,840 Or if someone's walking past you in a cafe, they can just look at your URL 891 00:43:57,840 --> 00:44:00,300 if it's revealed by the browser and they see it too. 892 00:44:00,300 --> 00:44:03,540 So GET is not necessarily the best verb to use 893 00:44:03,540 --> 00:44:05,880 even though it's the default when submitting forms. 894 00:44:05,880 --> 00:44:09,630 Typically, when you've got anything remotely sensitive, or anything large-- 895 00:44:09,630 --> 00:44:14,040 so be it a password, or credit card number, or an image or a video 896 00:44:14,040 --> 00:44:17,130 that you're uploading to Instagram, or to YouTube, 897 00:44:17,130 --> 00:44:21,720 or any such site like that-- you don't want the data going into the URL. 898 00:44:21,720 --> 00:44:25,260 And thankfully, there's actually an easy way to fix this. 899 00:44:25,260 --> 00:44:29,220 I can go into my form, which is currently an index.html, 900 00:44:29,220 --> 00:44:32,820 and I can just change the method from GET to post. 901 00:44:32,820 --> 00:44:36,960 In lowercase here, but the verb in the virtual envelope we discussed last week 902 00:44:36,960 --> 00:44:39,660 would itself be capital P-o-s-t. 903 00:44:39,660 --> 00:44:43,330 Now unfortunately, watch what happens here. 904 00:44:43,330 --> 00:44:48,240 Let me go over to my original form by going back to the /route-- 905 00:44:48,240 --> 00:44:51,870 and I'm reloading the page to make sure I get the latest, freshest HTML. 906 00:44:51,870 --> 00:44:55,200 And just to confirm here-- 907 00:44:55,200 --> 00:44:58,380 yep, if I view source, method is now POST. 908 00:44:58,380 --> 00:45:01,410 So let me go ahead and type in David now and click greet. 909 00:45:01,410 --> 00:45:03,210 And before we saw Hello, David. 910 00:45:03,210 --> 00:45:05,680 But now I get method not allowed. 911 00:45:05,680 --> 00:45:09,510 And this is somewhat subtle but in the title of the tab, notice 912 00:45:09,510 --> 00:45:12,720 that it's a 405 error, which is not familiar, probably. 913 00:45:12,720 --> 00:45:15,450 Almost all of us have seen 404 file not found. 914 00:45:15,450 --> 00:45:19,530 Turns out 405, a little more arcane, is the method. 915 00:45:19,530 --> 00:45:21,490 The HTTP verb is not allowed. 916 00:45:21,490 --> 00:45:21,990 Why? 917 00:45:21,990 --> 00:45:27,210 Because by default, my app.py only currently supports GET by default. 918 00:45:27,210 --> 00:45:28,910 How do I support POST? 919 00:45:28,910 --> 00:45:30,900 I just need a little bit more syntax. 920 00:45:30,900 --> 00:45:33,520 So let me go back into VS Code here. 921 00:45:33,520 --> 00:45:35,460 Let me go into app.py now. 922 00:45:35,460 --> 00:45:39,150 And after changing the form, I just need to inform Flask 923 00:45:39,150 --> 00:45:42,690 that what the method I want this great route to use 924 00:45:42,690 --> 00:45:47,010 should not be the default, which is only GET, I want it to use these methods. 925 00:45:47,010 --> 00:45:51,210 And it takes a second argument called methods, the value of which 926 00:45:51,210 --> 00:45:54,360 is a list, the default of which is, quote unquote, "GET". 927 00:45:54,360 --> 00:45:57,100 So that's the default. This has not made any changes. 928 00:45:57,100 --> 00:46:00,090 But if I want to support POST instead, I can explicitly 929 00:46:00,090 --> 00:46:03,120 pass a list with one string in it-- 930 00:46:03,120 --> 00:46:05,200 P-O-S-T instead. 931 00:46:05,200 --> 00:46:06,640 And now what does this mean? 932 00:46:06,640 --> 00:46:08,850 We didn't talk about this in any detail last week, 933 00:46:08,850 --> 00:46:11,550 but inside of this virtual envelope, typically, 934 00:46:11,550 --> 00:46:17,700 is that line like GET/search, queue=cats after the question mark. 935 00:46:17,700 --> 00:46:20,495 If you want to hide that kind of information for privacy's sake, 936 00:46:20,495 --> 00:46:23,370 or because you want to upload an image, which just doesn't make sense 937 00:46:23,370 --> 00:46:26,430 to put in the URL, essentially the part of the story would be, 938 00:46:26,430 --> 00:46:29,850 well the computer looks deeper inside of that virtual envelope. 939 00:46:29,850 --> 00:46:34,050 And anything submitted by a POST goes below the HTTP headers, 940 00:46:34,050 --> 00:46:35,490 like deeper in that envelope. 941 00:46:35,490 --> 00:46:36,550 So they're still there. 942 00:46:36,550 --> 00:46:41,500 They're just not obviously visible for prying eyes in the user's own browser. 943 00:46:41,500 --> 00:46:44,730 So just by making that change in the HTML, 944 00:46:44,730 --> 00:46:47,640 telling the browser to submit the data via POST, 945 00:46:47,640 --> 00:46:52,110 and changing app.py to tell the route to expect the data via POST, 946 00:46:52,110 --> 00:46:54,840 I can now go back to my other tab. 947 00:46:54,840 --> 00:46:56,520 Let me go back to the original page. 948 00:46:56,520 --> 00:46:59,460 Let me reload just so I've got the latest HTML. 949 00:46:59,460 --> 00:47:01,680 And indeed, view page source, it's still-- 950 00:47:01,680 --> 00:47:03,150 yep, it's still POST. 951 00:47:03,150 --> 00:47:08,010 But now when I type in D-A-V-I-D and click greet now it works. 952 00:47:08,010 --> 00:47:12,240 But, but, but, notice the privacy implication-- 953 00:47:12,240 --> 00:47:15,510 I'm at the greet route but where's my name? 954 00:47:15,510 --> 00:47:17,160 It's not actually there. 955 00:47:17,160 --> 00:47:19,140 It still went to the server, but it's not 956 00:47:19,140 --> 00:47:22,200 in your autocomplete or your history now for privacy's sake. 957 00:47:22,200 --> 00:47:26,630 Questions now on POST? 958 00:47:26,630 --> 00:47:27,210 Yeah. 959 00:47:27,210 --> 00:47:27,710 No? 960 00:47:27,710 --> 00:47:28,850 Just scratching. 961 00:47:28,850 --> 00:47:31,920 All right, can you, the programmer see this? 962 00:47:31,920 --> 00:47:35,030 Well, let me show you a couple of other features of Chrome's-- 963 00:47:35,030 --> 00:47:38,040 Chrome, and Safari, and other browsers as well. 964 00:47:38,040 --> 00:47:40,190 I keep going to view page source, which just shows 965 00:47:40,190 --> 00:47:42,290 you a read only version of your HTML. 966 00:47:42,290 --> 00:47:46,280 But recall that last time, I actually right clicked and went to inspect, 967 00:47:46,280 --> 00:47:47,690 or viewed developer tools. 968 00:47:47,690 --> 00:47:51,200 And this brings up a much fancier version of the developer tools. 969 00:47:51,200 --> 00:47:53,150 And under elements here, you see everything. 970 00:47:53,150 --> 00:47:55,400 And it's nice and pretty printed, it's hierarchical, , 971 00:47:55,400 --> 00:47:58,490 it collapses things into these clickable triangles but it's the exact same 972 00:47:58,490 --> 00:47:58,990 thing. 973 00:47:58,990 --> 00:48:00,440 It's just more interactive. 974 00:48:00,440 --> 00:48:02,700 But notice what I can do today is this-- 975 00:48:02,700 --> 00:48:06,630 If I go to the Network tab here, and let me Zoom out a little bit, 976 00:48:06,630 --> 00:48:12,890 Let me go ahead and re load the form here and type in David 977 00:48:12,890 --> 00:48:15,170 again and click greet. 978 00:48:15,170 --> 00:48:20,420 Notice now in the Network tab of Chrome's developer tools, 979 00:48:20,420 --> 00:48:22,770 I see a few things as we saw before. 980 00:48:22,770 --> 00:48:25,460 One, I see that the request method is POST. 981 00:48:25,460 --> 00:48:27,620 Two, I see that the server automatically, 982 00:48:27,620 --> 00:48:31,100 without me writing any code for this, returns 200 when it's successful. 983 00:48:31,100 --> 00:48:34,010 But I can scroll down, down, down, down, down, 984 00:48:34,010 --> 00:48:39,500 and you'll see that eventually after all these cookies-- more on those later. 985 00:48:39,500 --> 00:48:42,770 If I click on payload, the second tab next to headers, 986 00:48:42,770 --> 00:48:46,903 you can see as the developer what was actually sent to the server. 987 00:48:46,903 --> 00:48:47,570 So indeed, this. 988 00:48:47,570 --> 00:48:49,550 Is going to be super useful like when doing problem 989 00:48:49,550 --> 00:48:51,380 set nine, maybe your final projects, if you 990 00:48:51,380 --> 00:48:53,960 want to see what's going from browser to server, 991 00:48:53,960 --> 00:48:57,480 you have complete control over all of that information. 992 00:48:57,480 --> 00:49:00,090 Even if you're using HTTPS, because your browser and you, 993 00:49:00,090 --> 00:49:02,700 the developer can certainly see all of this. 994 00:49:02,700 --> 00:49:04,880 So again, these developer tools, even though there's 995 00:49:04,880 --> 00:49:07,610 a lot of tabs and buttons you probably won't need any time soon, 996 00:49:07,610 --> 00:49:11,720 some of them like elements, and network, and with JavaScript console 997 00:49:11,720 --> 00:49:16,430 are going to be super useful to start to get familiar with. 998 00:49:16,430 --> 00:49:24,980 All right, any questions now on this implication of POST? 999 00:49:24,980 --> 00:49:28,170 Anything at all? 1000 00:49:28,170 --> 00:49:28,950 No? 1001 00:49:28,950 --> 00:49:32,850 OK, how about one final Hello example that ties a few of these things 1002 00:49:32,850 --> 00:49:33,760 together. 1003 00:49:33,760 --> 00:49:38,130 How about now we try to tighten things up further only in anticipation 1004 00:49:38,130 --> 00:49:41,040 of something like problem set 9, or really more complicated 1005 00:49:41,040 --> 00:49:44,880 web apps where you might have not two, but 20 1006 00:49:44,880 --> 00:49:47,010 or maybe even more different routes. 1007 00:49:47,010 --> 00:49:51,100 It might be ideal to just minimize how many total routes we have. 1008 00:49:51,100 --> 00:49:52,860 So we don't get a little too overwhelmed. 1009 00:49:52,860 --> 00:49:56,250 And I daresay that these two routes are so short, 1010 00:49:56,250 --> 00:49:58,650 maybe I can combine them into one. 1011 00:49:58,650 --> 00:50:01,980 And maybe I can keep the user at what seems to be the same URL, 1012 00:50:01,980 --> 00:50:03,810 but just to kind of tidy things up. 1013 00:50:03,810 --> 00:50:06,390 So let me propose that we do this instead. 1014 00:50:06,390 --> 00:50:13,670 Let me get rid of my greet route and let me go into my form in index.html 1015 00:50:13,670 --> 00:50:18,560 and let me go ahead and just have the action of this form still be slash. 1016 00:50:18,560 --> 00:50:22,350 I want the form to be visible at the slash, the index of the site. 1017 00:50:22,350 --> 00:50:25,340 But I also want the form to submit to itself 1018 00:50:25,340 --> 00:50:28,940 if only because I don't want to introduce another route like greet 1019 00:50:28,940 --> 00:50:31,020 which eventually, indeed, will be compelling 1020 00:50:31,020 --> 00:50:34,130 so you don't have one root for everything you want your website to do. 1021 00:50:34,130 --> 00:50:37,400 So technically this is the default too, and if I omit action 1022 00:50:37,400 --> 00:50:39,150 the exact same thing would happen as well. 1023 00:50:39,150 --> 00:50:42,020 But let me rewind and let me now go into app.py 1024 00:50:42,020 --> 00:50:43,800 to see how we can make this happen. 1025 00:50:43,800 --> 00:50:47,720 Well, if I want my one and now only route to support both methods, 1026 00:50:47,720 --> 00:50:53,030 I can say methods=, and then a list with both GET and POST in any order 1027 00:50:53,030 --> 00:50:55,280 but I'll keep them alphabetical like this. 1028 00:50:55,280 --> 00:51:00,200 Now tells Python hey, this route should handle both GET and POST 1029 00:51:00,200 --> 00:51:02,340 requests at the same place. 1030 00:51:02,340 --> 00:51:04,520 Let's now go into this function. 1031 00:51:04,520 --> 00:51:07,400 I kind of want to say the equivalent of this-- 1032 00:51:07,400 --> 00:51:11,180 if GET, then I want to return the form. 1033 00:51:11,180 --> 00:51:15,230 Else if POST, I want to then return render template 1034 00:51:15,230 --> 00:51:18,860 of greet.HTML with the user's name. 1035 00:51:18,860 --> 00:51:22,260 But this is not yet complete code, but I think I can do this. 1036 00:51:22,260 --> 00:51:24,300 I'm going to go ahead and save the following. 1037 00:51:24,300 --> 00:51:30,850 I'm going to go ahead and say if request.method = = GET, 1038 00:51:30,850 --> 00:51:33,710 then indeed return index.html. 1039 00:51:33,710 --> 00:51:40,610 L if request.method = = POST, then go ahead and return greet.HTML. 1040 00:51:40,610 --> 00:51:44,120 This isn't quite enough though because I still want to pass in that placeholder. 1041 00:51:44,120 --> 00:51:50,120 So let me again add back name=request.args.GET, quote unquote, 1042 00:51:50,120 --> 00:51:53,510 "name", and then a default value of world. 1043 00:51:53,510 --> 00:51:55,910 What does this now do for me? 1044 00:51:55,910 --> 00:51:58,730 Well let me go back to my other tab here. 1045 00:51:58,730 --> 00:52:01,280 Let me close the developer tools, let me go back to the form 1046 00:52:01,280 --> 00:52:03,320 here, let me reload to make sure I have the latest. 1047 00:52:03,320 --> 00:52:06,237 Let me view page source just to make sure I have the latest-- and yep, 1048 00:52:06,237 --> 00:52:08,180 I have the latest because it still says POST. 1049 00:52:08,180 --> 00:52:09,810 But it now says slash. 1050 00:52:09,810 --> 00:52:11,300 And let's see what happens now. 1051 00:52:11,300 --> 00:52:14,930 If I type in my name David, previously this submitted via POST, 1052 00:52:14,930 --> 00:52:17,810 so I didn't see any name or value thereof in the URL, 1053 00:52:17,810 --> 00:52:19,520 but I did end up at /greet. 1054 00:52:19,520 --> 00:52:22,280 But if the action is now slash I click greet, 1055 00:52:22,280 --> 00:52:25,160 notice that it still kind of works. 1056 00:52:25,160 --> 00:52:27,695 I see Hello, world, although that didn't quite work. 1057 00:52:27,695 --> 00:52:29,570 So we'll come back to that issue in a moment. 1058 00:52:29,570 --> 00:52:31,903 But notice the URL ends in just slash. 1059 00:52:31,903 --> 00:52:34,820 And again, Chrome is hiding the slash because that's all that's there, 1060 00:52:34,820 --> 00:52:41,060 but it does not end in name=David in this case, or name=world. 1061 00:52:41,060 --> 00:52:42,500 Now notice this too-- 1062 00:52:42,500 --> 00:52:45,260 if I reload I'm going to get this warning. 1063 00:52:45,260 --> 00:52:47,537 Do you want to confirm form resubmission? 1064 00:52:47,537 --> 00:52:50,120 The page you're looking for used information that you entered. 1065 00:52:50,120 --> 00:52:52,760 Returning to that page might cause any action you took to be repeated. 1066 00:52:52,760 --> 00:52:53,760 Do you want to continue? 1067 00:52:53,760 --> 00:52:56,060 You might have seen this on websites you've actually visited, 1068 00:52:56,060 --> 00:52:58,520 where you hit reload and you're prompted-- wait a minute, 1069 00:52:58,520 --> 00:52:59,478 do you want to do that? 1070 00:52:59,478 --> 00:53:02,720 Odds are you've been prompted to reload explicitly because why? 1071 00:53:02,720 --> 00:53:06,500 Whatever you just did was POST instead of GET. 1072 00:53:06,500 --> 00:53:09,410 And by convention, besides POST being used for privacy 1073 00:53:09,410 --> 00:53:12,950 to hide your username, your password, your credit card number, or the like. 1074 00:53:12,950 --> 00:53:16,340 Besides being used to upload bigger files like images or videos, 1075 00:53:16,340 --> 00:53:20,570 POST is also used by convention to make changes to the server, 1076 00:53:20,570 --> 00:53:24,300 to add something to your shopping cart, to add something to the database. 1077 00:53:24,300 --> 00:53:26,270 Whereas GET, as the name suggests, is all 1078 00:53:26,270 --> 00:53:30,810 about getting information, not posting or sending information instead. 1079 00:53:30,810 --> 00:53:34,547 So this is Chrome being a little careful because if you just checked out 1080 00:53:34,547 --> 00:53:36,380 on Amazon and then you hit reload, you don't 1081 00:53:36,380 --> 00:53:39,710 want to accidentally buy the same book again, so to speak, 1082 00:53:39,710 --> 00:53:42,500 even though Amazon and fancy websites have other defenses 1083 00:53:42,500 --> 00:53:44,660 for this too to avoid this issue. 1084 00:53:44,660 --> 00:53:47,120 Now there is a bug, though, here. 1085 00:53:47,120 --> 00:53:50,630 It says Hello, world instead of Hello, David, and it 1086 00:53:50,630 --> 00:53:52,700 actually would have said the same a moment ago 1087 00:53:52,700 --> 00:53:56,030 and I just didn't retest the code and reveal as much to you. 1088 00:53:56,030 --> 00:53:59,720 Or if I did I didn't even notice it said Hello, world instead of Hello, David. 1089 00:53:59,720 --> 00:54:05,390 It turns out that request.args is only used for GET. 1090 00:54:05,390 --> 00:54:08,420 When using GET, request.args is a dictionary that 1091 00:54:08,420 --> 00:54:10,200 contains all of your key value pairs. 1092 00:54:10,200 --> 00:54:13,790 But somewhat confusingly, when using POST with Flask, 1093 00:54:13,790 --> 00:54:15,830 you have to go into request.form. 1094 00:54:15,830 --> 00:54:20,540 I have no idea why these are not more obvious opposites like request.GET, 1095 00:54:20,540 --> 00:54:22,520 request.form, and-- 1096 00:54:22,520 --> 00:54:26,300 sorry, request.GET and request.POST would be sensible names. 1097 00:54:26,300 --> 00:54:29,480 In this case, though, we have request.args for GET, 1098 00:54:29,480 --> 00:54:31,868 and request.form for POST. 1099 00:54:31,868 --> 00:54:33,410 All right, that's an easy fix though. 1100 00:54:33,410 --> 00:54:38,460 If I go back to VS Code here, let's change request.args to request.form. 1101 00:54:38,460 --> 00:54:40,280 Let's go back to my other tab. 1102 00:54:40,280 --> 00:54:42,050 Let me just reload, and you know what? 1103 00:54:42,050 --> 00:54:45,290 I'm going to say, OK, continue to resubmit the same form 1104 00:54:45,290 --> 00:54:48,530 because the form was OK, it was my Python code that was buggy. 1105 00:54:48,530 --> 00:54:51,950 Hitting Enter now-- it's accessing David OK. 1106 00:54:51,950 --> 00:54:55,550 But watch this-- again if I hit reload, Command R or Control R, 1107 00:54:55,550 --> 00:54:56,752 I get the same Warning. 1108 00:54:56,752 --> 00:54:58,460 Are you sure you want to submit the form? 1109 00:54:58,460 --> 00:54:58,960 Yes. 1110 00:54:58,960 --> 00:55:02,880 If I do it manually with the reload icon, I get the same Warning as before. 1111 00:55:02,880 --> 00:55:06,470 But if I want to manually induce a GET request, well that's fine. 1112 00:55:06,470 --> 00:55:08,860 Don't hit reload and send the same request. 1113 00:55:08,860 --> 00:55:13,750 Instead go up to your URL and just put the cursor up there and hit Enter. 1114 00:55:13,750 --> 00:55:17,270 And now notice, same URL is a GET by default. 1115 00:55:17,270 --> 00:55:19,960 So any time you and I have typed URLs into browsers, 1116 00:55:19,960 --> 00:55:23,650 GET is always the default. Only when you click on a button, 1117 00:55:23,650 --> 00:55:26,050 typically, that the programmer has configured 1118 00:55:26,050 --> 00:55:29,930 to use POST, are you actually adding things to your shopping cart, 1119 00:55:29,930 --> 00:55:30,890 or the like. 1120 00:55:30,890 --> 00:55:33,710 All right, so we are back. 1121 00:55:33,710 --> 00:55:38,260 And if I go way back in time myself, like this is actually 1122 00:55:38,260 --> 00:55:44,920 the first web application I made back in 1997 I believe. 1123 00:55:44,920 --> 00:55:48,790 So at the time this would have been, what, my sophomore or so year. 1124 00:55:48,790 --> 00:55:50,980 I had taken CS50, I took a follow on class 1125 00:55:50,980 --> 00:55:53,510 called CS51, which is a different type of programming. 1126 00:55:53,510 --> 00:55:56,470 And then I pretty much taught myself a language called Perl, which 1127 00:55:56,470 --> 00:55:58,210 is somewhat less popular nowadays. 1128 00:55:58,210 --> 00:56:01,540 But it's another language like Python, like Java, like JavaScript, 1129 00:56:01,540 --> 00:56:04,210 like others that can be used to make web based applications. 1130 00:56:04,210 --> 00:56:08,410 And the web was very young at the time and the process via which 1131 00:56:08,410 --> 00:56:11,710 students, my classmates, could register for the first year intramural 1132 00:56:11,710 --> 00:56:13,120 sports program-- a.k.a. 1133 00:56:13,120 --> 00:56:17,260 frosh IMs was to grab a piece of paper, and write your name and email 1134 00:56:17,260 --> 00:56:21,000 address on it, and walk it across the yard to Wigglesworth, I believe, 1135 00:56:21,000 --> 00:56:22,000 where the Proctor lived. 1136 00:56:22,000 --> 00:56:24,083 And you'd slide the piece of paper under the door, 1137 00:56:24,083 --> 00:56:26,780 and that was how we submitted forms in my day. 1138 00:56:26,780 --> 00:56:31,600 So this was an opportunity, even back in 1997-ish, to move things online. 1139 00:56:31,600 --> 00:56:34,690 And the website went on to live on until I think 2007. 1140 00:56:34,690 --> 00:56:38,470 I found this online and then it's become something else since. 1141 00:56:38,470 --> 00:56:41,440 But this was a website via which people could register for sports, 1142 00:56:41,440 --> 00:56:44,480 and people could log in the scores for various games and whatnot. 1143 00:56:44,480 --> 00:56:46,350 And so underneath the hood, I didn't even 1144 00:56:46,350 --> 00:56:48,100 know anything about databases at the time, 1145 00:56:48,100 --> 00:56:51,760 it was just CSV files that I was storing the data in. 1146 00:56:51,760 --> 00:56:53,590 But there were HTML forms. 1147 00:56:53,590 --> 00:56:56,350 And there was with Perl, the language at the time, the way 1148 00:56:56,350 --> 00:57:00,340 to do the exact kind of stuff that we've just been doing already with Flask. 1149 00:57:00,340 --> 00:57:04,780 And so what I thought we'd do is implement a slightly less ugly version 1150 00:57:04,780 --> 00:57:05,950 of this. 1151 00:57:05,950 --> 00:57:11,620 Repeating graphical backgrounds were in Vogue in 1997, as you can see here. 1152 00:57:11,620 --> 00:57:16,190 But these were the aesthetics of the day, including the so-called Blink tag. 1153 00:57:16,190 --> 00:57:18,775 So let's at least focus on the functionality of this website 1154 00:57:18,775 --> 00:57:20,650 and not so much the aesthetics, and see if we 1155 00:57:20,650 --> 00:57:23,830 can implement some of the plumbing for actually solving a real world 1156 00:57:23,830 --> 00:57:24,865 representative problem. 1157 00:57:24,865 --> 00:57:27,490 Be it for freshman intramural sports, or something else like it 1158 00:57:27,490 --> 00:57:30,520 where you're getting data from users, and processing it somehow. 1159 00:57:30,520 --> 00:57:32,770 So let me go over here to VS Code. 1160 00:57:32,770 --> 00:57:35,860 Let me create a new directory called frosh IMs, just so we can keep 1161 00:57:35,860 --> 00:57:38,140 all of this code in its own directory. 1162 00:57:38,140 --> 00:57:40,240 Let me CD into frosh IMs. 1163 00:57:40,240 --> 00:57:43,270 Let me proactively make another directory called templates, 1164 00:57:43,270 --> 00:57:45,850 in which our templates-- our .HTML files-- 1165 00:57:45,850 --> 00:57:47,110 do need to live. 1166 00:57:47,110 --> 00:57:50,800 And eventually I'm going to go ahead and create two 1167 00:57:50,800 --> 00:57:54,700 files minimally, app.py and index.html. 1168 00:57:54,700 --> 00:57:59,680 So let's do the first of those, app.py will live in my frosh IMs directory, 1169 00:57:59,680 --> 00:58:03,080 and I'm just going to recreate something very simple like we have previously. 1170 00:58:03,080 --> 00:58:09,400 So from flask in lowercase, import Flask capitalized, render template, and also 1171 00:58:09,400 --> 00:58:09,970 request. 1172 00:58:09,970 --> 00:58:11,710 So same first line as before. 1173 00:58:11,710 --> 00:58:13,870 Let me then give myself a variable called app, 1174 00:58:13,870 --> 00:58:19,660 set it equal to calling the Flask function, capital F, with __name__, 1175 00:58:19,660 --> 00:58:27,200 and then let me give myself a route for slash as before with an index function. 1176 00:58:27,200 --> 00:58:29,200 Though again, I could call that anything I want. 1177 00:58:29,200 --> 00:58:32,020 And just for now, let's return render template of, 1178 00:58:32,020 --> 00:58:34,760 quote unquote, "index.html" as though that exists. 1179 00:58:34,760 --> 00:58:37,780 So this is not really a web application as much as it is at the moment 1180 00:58:37,780 --> 00:58:41,570 just a recreation of HTTP server for one file. 1181 00:58:41,570 --> 00:58:48,250 Let's now in another tab create a templates file called index.html. 1182 00:58:48,250 --> 00:58:50,830 And I'm going to save myself a few keystrokes. 1183 00:58:50,830 --> 00:58:54,340 Let me copy paste from earlier almost all of the layout from before. 1184 00:58:54,340 --> 00:58:57,880 I've changed the title in advance to frosh IMs instead of Hello, 1185 00:58:57,880 --> 00:58:59,950 but this is essentially the same template. 1186 00:58:59,950 --> 00:59:02,890 And for now, though, because I'm in index.html, 1187 00:59:02,890 --> 00:59:06,560 I'm not going to use extends or any of that fancy block stuff yet. 1188 00:59:06,560 --> 00:59:09,340 I'm just going to go ahead and create a relatively simple form 1189 00:59:09,340 --> 00:59:11,530 via which back in the day my classmates could 1190 00:59:11,530 --> 00:59:14,210 have registered for intramural sports. 1191 00:59:14,210 --> 00:59:19,510 So let's go ahead here, and I'll propose that we do this. 1192 00:59:19,510 --> 00:59:24,625 In this page we'll have a form, the action of which will be a route called 1193 00:59:24,625 --> 00:59:27,940 /register, though I could call that anything I want. 1194 00:59:27,940 --> 00:59:30,970 It'll be somewhat private, so I'm going to use POST instead of GET, 1195 00:59:30,970 --> 00:59:34,360 just so that people don't accidentally maybe register twice 1196 00:59:34,360 --> 00:59:36,700 by hitting reload without warning. 1197 00:59:36,700 --> 00:59:39,880 Inside of this form, let's go ahead and give them 1198 00:59:39,880 --> 00:59:44,860 an input where autocomplete will be off, as always, for demonstration's sake. 1199 00:59:44,860 --> 00:59:47,950 Auto focus so the cursor goes there initially. 1200 00:59:47,950 --> 00:59:51,760 The name of this field will be literally name because I want my classmate's name 1201 00:59:51,760 --> 00:59:53,470 if they want to register for some sport. 1202 00:59:53,470 --> 00:59:55,840 The placeholder will again be, quote unquote, "name", 1203 00:59:55,840 --> 00:59:58,090 just so they see some gray instructions. 1204 00:59:58,090 --> 01:00:02,260 And the type of this field will indeed be text as before. 1205 01:00:02,260 --> 01:00:06,080 And then I need to give them the ability to register for a few sports. 1206 01:00:06,080 --> 01:00:09,193 Why don't we keep it simple, like back in the day basketball, soccer, 1207 01:00:09,193 --> 01:00:11,860 and ultimate Frisbee were three of the sports that we supported. 1208 01:00:11,860 --> 01:00:13,568 And so let me do this-- and you might not 1209 01:00:13,568 --> 01:00:17,650 have seen this before unless you dabbled further on with forms on your own. 1210 01:00:17,650 --> 01:00:21,280 But I can create a select menu-- otherwise known as a dropdown menu-- 1211 01:00:21,280 --> 01:00:25,100 in HTML, inside of which are a whole bunch of options. 1212 01:00:25,100 --> 01:00:27,610 And each option typically follows this paradigm-- 1213 01:00:27,610 --> 01:00:31,270 the value of the option, and then the actual text that the human sees. 1214 01:00:31,270 --> 01:00:37,810 So the value of these options will be-- how about we do basketball as one. 1215 01:00:37,810 --> 01:00:40,120 And I want the human to see literally the same thing. 1216 01:00:40,120 --> 01:00:42,790 Though just like with a link in HTML, they could be different, 1217 01:00:42,790 --> 01:00:44,320 but I'm going to keep them the same. 1218 01:00:44,320 --> 01:00:49,240 Another option will be, let's say soccer. 1219 01:00:49,240 --> 01:00:51,500 And-- oops, let me fix my quotes. 1220 01:00:51,500 --> 01:00:53,512 And this human will see the exact same thing, 1221 01:00:53,512 --> 01:00:54,970 though it could say something else. 1222 01:00:54,970 --> 01:00:59,470 And then lastly, the value will be, quote unquote, "ultimate Frisbee", 1223 01:00:59,470 --> 01:01:03,958 and the humans will see the same thing there-- ultimate Frisbee. 1224 01:01:03,958 --> 01:01:07,000 All right, so this is going to create, as we'll soon see, just a dropdown 1225 01:01:07,000 --> 01:01:08,770 menu with three separate options. 1226 01:01:08,770 --> 01:01:11,020 If I want the students to be able to submit this now, 1227 01:01:11,020 --> 01:01:13,810 let me give them a button, the type of which is submit. 1228 01:01:13,810 --> 01:01:17,330 And this button will be like the word register on it. 1229 01:01:17,330 --> 01:01:19,210 So I think we're pretty much good to go. 1230 01:01:19,210 --> 01:01:22,300 This is all just HTML-- no Python, no Flask per se, 1231 01:01:22,300 --> 01:01:24,770 except for the rendering of this same template. 1232 01:01:24,770 --> 01:01:26,770 So let me go into my terminal window. 1233 01:01:26,770 --> 01:01:29,800 Let me do Flask run inside of this directory 1234 01:01:29,800 --> 01:01:31,690 because I need to serve this app instead. 1235 01:01:31,690 --> 01:01:34,270 I'm going to see some ugly output, including my own URL. 1236 01:01:34,270 --> 01:01:36,820 And if I hover over that and then open that URL, 1237 01:01:36,820 --> 01:01:39,130 I should now see a more interesting form. 1238 01:01:39,130 --> 01:01:40,930 It's got not only a field for their name, 1239 01:01:40,930 --> 01:01:43,750 but also this dropdown menu with all three sports. 1240 01:01:43,750 --> 01:01:48,130 Now this isn't maybe the best user experience thus far 1241 01:01:48,130 --> 01:01:51,640 because I feel like I'm biasing people to registering for basketball 1242 01:01:51,640 --> 01:01:54,520 maybe because it's checked by default. I mean a lot of forms 1243 01:01:54,520 --> 01:01:57,410 nowadays have a blank placeholder for the form. 1244 01:01:57,410 --> 01:01:59,720 So this is just an aesthetic thing, but I can do this. 1245 01:01:59,720 --> 01:02:02,530 Let me go back to the same form and let me give myself 1246 01:02:02,530 --> 01:02:06,760 just a blank option at the top that in fact, I'm going to disable. 1247 01:02:06,760 --> 01:02:09,400 So you technically can't select it proactively, 1248 01:02:09,400 --> 01:02:11,740 but I am going to select it by default. And so 1249 01:02:11,740 --> 01:02:14,860 we probably haven't seen those HTML attributes before. 1250 01:02:14,860 --> 01:02:20,470 But if I want to create the equivalent of like a title for this dropdown, 1251 01:02:20,470 --> 01:02:24,070 I'm going to literally create a disabled option that's automatically 1252 01:02:24,070 --> 01:02:27,070 selected called Sport so that you can't select it per se, 1253 01:02:27,070 --> 01:02:28,700 but it is there at the top. 1254 01:02:28,700 --> 01:02:32,440 So if I go back now to my other tab, reload-- 1255 01:02:32,440 --> 01:02:34,270 just marginally prettier than before. 1256 01:02:34,270 --> 01:02:37,330 And I'm not biasing people toward accidentally registering for basketball 1257 01:02:37,330 --> 01:02:37,830 alone. 1258 01:02:37,830 --> 01:02:41,290 And if I click on this, you'll see that sport is grayed out and therefore not 1259 01:02:41,290 --> 01:02:45,010 manually selectable, but I can select any of these other three still. 1260 01:02:45,010 --> 01:02:48,610 All right, well unfortunately if I type in David and I try registering, 1261 01:02:48,610 --> 01:02:54,160 for instance, for soccer and click Register, I do end up at /register. 1262 01:02:54,160 --> 01:02:56,870 And there's no question mark, or name, or sport, 1263 01:02:56,870 --> 01:03:00,220 so it's probably indeed POST instead of GET-- those are hints-- 1264 01:03:00,220 --> 01:03:01,450 but not found. 1265 01:03:01,450 --> 01:03:07,510 Notice the tab here very succinctly says, 404 not found. 1266 01:03:07,510 --> 01:03:09,080 Well why is that? 1267 01:03:09,080 --> 01:03:12,690 Just to be clear, why did /register give me a 404? 1268 01:03:12,690 --> 01:03:16,240 1269 01:03:16,240 --> 01:03:19,170 What's the logic here? 1270 01:03:19,170 --> 01:03:23,260 Perhaps just state the obvious, or-- 1271 01:03:23,260 --> 01:03:24,260 It doesn't exist, right? 1272 01:03:24,260 --> 01:03:25,968 We haven't done that step yet, all right? 1273 01:03:25,968 --> 01:03:27,420 So something as simple as that. 1274 01:03:27,420 --> 01:03:30,620 And so I actually sort of belabor that point because as you're 1275 01:03:30,620 --> 01:03:33,680 learning a lot of these conventions and some of this new syntax, 1276 01:03:33,680 --> 01:03:35,270 honestly you're just going to make stupid mistakes. 1277 01:03:35,270 --> 01:03:36,520 Something's not going to work. 1278 01:03:36,520 --> 01:03:38,410 But again, go back to first principles. 1279 01:03:38,410 --> 01:03:39,830 Why is it not found? 1280 01:03:39,830 --> 01:03:43,490 All right, register should be a template maybe called register.HTML. 1281 01:03:43,490 --> 01:03:45,050 Oh, I forgot my app.route. 1282 01:03:45,050 --> 01:03:47,810 So that should be the kind of thinking as you try to diagnose 1283 01:03:47,810 --> 01:03:49,280 these problems moving forward. 1284 01:03:49,280 --> 01:03:54,480 All right, so let me go into app.py, and let me give myself a second route here. 1285 01:03:54,480 --> 01:03:57,920 So app.route, quote unquote, "/route". 1286 01:03:57,920 --> 01:04:00,510 Then let me define a function called anything I want, 1287 01:04:00,510 --> 01:04:04,310 but I'm going to call it-- sorry, not /route, /register. 1288 01:04:04,310 --> 01:04:07,280 Let me call the function, just to be consistent, register. 1289 01:04:07,280 --> 01:04:09,500 So-- but I could call that anything I want. 1290 01:04:09,500 --> 01:04:12,440 And just for now let's not do anything too interesting, 1291 01:04:12,440 --> 01:04:16,760 let's just return the rendering of a template called success.HTML. 1292 01:04:16,760 --> 01:04:19,190 Let's just pretend for now that registration is successful 1293 01:04:19,190 --> 01:04:21,170 no matter who you are or what you do. 1294 01:04:21,170 --> 01:04:25,380 Now I need that template and I only have index.html at this point. 1295 01:04:25,380 --> 01:04:27,470 So let me actually now do my best practices. 1296 01:04:27,470 --> 01:04:29,060 Let me copy all of that. 1297 01:04:29,060 --> 01:04:33,470 Let me-- in a separate terminal window, let me do code-- 1298 01:04:33,470 --> 01:04:36,110 let me go into my frosh IMs directory. 1299 01:04:36,110 --> 01:04:40,190 And let me create a new template called layout.HTML just like before. 1300 01:04:40,190 --> 01:04:42,320 Let me paste all that same code. 1301 01:04:42,320 --> 01:04:46,310 Let me delete the form and just put in that big placeholder, 1302 01:04:46,310 --> 01:04:52,010 so block body and then end block is all I did earlier. 1303 01:04:52,010 --> 01:04:54,260 This is just kind of boilerplate now convention. 1304 01:04:54,260 --> 01:04:55,620 Everything else I'm going to leave the same. 1305 01:04:55,620 --> 01:04:58,430 But if I wanted to make it prettier, I could add my CSS up top. 1306 01:04:58,430 --> 01:05:01,430 If I wanted to add this crazy repeating background, 1307 01:05:01,430 --> 01:05:03,110 I could probably do that up top too. 1308 01:05:03,110 --> 01:05:06,170 So I can make every page look as ugly as it did back in my day, 1309 01:05:06,170 --> 01:05:08,270 but we'll focus just today on the text. 1310 01:05:08,270 --> 01:05:13,820 All right, so add now that I have layout that HTML, let me clean up index.html. 1311 01:05:13,820 --> 01:05:15,740 I don't need all this redundancy. 1312 01:05:15,740 --> 01:05:17,930 I don't need all of these tags at the top. 1313 01:05:17,930 --> 01:05:23,000 Instead recall, I think I just need extends, quote unquote, 1314 01:05:23,000 --> 01:05:27,980 "layout.HTML" with the appropriate signs and curly braces. 1315 01:05:27,980 --> 01:05:30,500 I then have the appropriate block body, though I 1316 01:05:30,500 --> 01:05:31,950 could call body anything I want. 1317 01:05:31,950 --> 01:05:34,280 But I'm going to stick with my convention earlier. 1318 01:05:34,280 --> 01:05:37,610 And I'm going to delete the tags down here that I no longer need. 1319 01:05:37,610 --> 01:05:38,240 Why? 1320 01:05:38,240 --> 01:05:42,110 Because if I go into layout.HTML, I already have all my open tags, 1321 01:05:42,110 --> 01:05:43,280 all my close tags. 1322 01:05:43,280 --> 01:05:48,360 The only stuff I want in index.html is going to be which belongs in the body. 1323 01:05:48,360 --> 01:05:50,780 So end block down here. 1324 01:05:50,780 --> 01:05:53,990 And just to be pedantic, let me go ahead and highlight all that. 1325 01:05:53,990 --> 01:05:58,070 Hit Shift Tab and that will unindent it just to line things up. 1326 01:05:58,070 --> 01:05:59,123 Just to be tidy. 1327 01:05:59,123 --> 01:06:01,790 All right, so better, even though it looks a little cryptic now. 1328 01:06:01,790 --> 01:06:03,582 But now I've laid the foundation for making 1329 01:06:03,582 --> 01:06:07,430 a third page, a fourth page, that don't have all of that same copy paste. 1330 01:06:07,430 --> 01:06:09,920 All right, so now let's go back into app.py. 1331 01:06:09,920 --> 01:06:12,450 Success.HTML is where I left off. 1332 01:06:12,450 --> 01:06:14,630 So OK, let me open my terminal window. 1333 01:06:14,630 --> 01:06:19,280 Let me code up a template called success.HTML whose purpose in life 1334 01:06:19,280 --> 01:06:22,610 is literally just going to be to say, you are registered. 1335 01:06:22,610 --> 01:06:25,440 Just so that we see some informative message on the screen. 1336 01:06:25,440 --> 01:06:29,300 So this part I do still need extends layout.HTML. 1337 01:06:29,300 --> 01:06:33,020 So there's a little bit of copy paste still, which is a little ugly 1338 01:06:33,020 --> 01:06:34,160 but so be it. 1339 01:06:34,160 --> 01:06:40,130 Block body for this template, and I'm just going to say, you are registered! 1340 01:06:40,130 --> 01:06:41,810 All right, and then end block. 1341 01:06:41,810 --> 01:06:43,080 So super simple. 1342 01:06:43,080 --> 01:06:45,110 It's just an informative message claiming 1343 01:06:45,110 --> 01:06:47,300 that the student is registered. 1344 01:06:47,300 --> 01:06:50,430 All right, let's go back to the original form, which is this. 1345 01:06:50,430 --> 01:06:53,630 Let me reload to make sure my HTML has reloaded. 1346 01:06:53,630 --> 01:06:58,130 Type in David, I'm going to register again for soccer, and click Register. 1347 01:06:58,130 --> 01:07:01,680 And, oh, interesting-- method not allowed. 1348 01:07:01,680 --> 01:07:08,980 So I'm not getting a 404 anymore, I'm getting 405 at /register. 1349 01:07:08,980 --> 01:07:10,900 What's the deduction here? 1350 01:07:10,900 --> 01:07:12,250 How did I screw up this time? 1351 01:07:12,250 --> 01:07:15,130 1352 01:07:15,130 --> 01:07:16,280 405 is progress. 1353 01:07:16,280 --> 01:07:16,780 Yeah? 1354 01:07:16,780 --> 01:07:18,200 AUDIENCE: [INAUDIBLE] 1355 01:07:18,200 --> 01:07:21,260 DAVID MALAN: So it's not-- the placeholder I think is OK. 1356 01:07:21,260 --> 01:07:23,510 This is now about the underlying HTTP stuff. 1357 01:07:23,510 --> 01:07:26,270 The method was disallowed-- was not allowed. 1358 01:07:26,270 --> 01:07:27,942 AUDIENCE: [INAUDIBLE] 1359 01:07:27,942 --> 01:07:28,900 DAVID MALAN: Say again? 1360 01:07:28,900 --> 01:07:29,460 AUDIENCE: [INAUDIBLE] 1361 01:07:29,460 --> 01:07:31,220 DAVID MALAN: So GET versus POST thing too. 1362 01:07:31,220 --> 01:07:34,610 So by default, all of these routes in Flask just by default 1363 01:07:34,610 --> 01:07:35,930 assume GET because it's safe. 1364 01:07:35,930 --> 01:07:39,360 It doesn't allow you to send information to the server in quite the same way. 1365 01:07:39,360 --> 01:07:43,970 But if I do want to support POST, recall that we change this to be methods=, 1366 01:07:43,970 --> 01:07:46,680 and then a list with, quote unquote, "POST" in it. 1367 01:07:46,680 --> 01:07:51,290 So I just need to enable support for that method that is that HTTP verb. 1368 01:07:51,290 --> 01:07:52,883 All right, let's go back to the form. 1369 01:07:52,883 --> 01:07:54,800 Reload just to make sure I haven't screwed up. 1370 01:07:54,800 --> 01:07:58,580 Type in my name David, select soccer from the dropdown, click Register. 1371 01:07:58,580 --> 01:08:02,480 And now I'm not only at /register in the URL, 1372 01:08:02,480 --> 01:08:04,432 it claims that I am indeed registered. 1373 01:08:04,432 --> 01:08:05,390 Now of course I'm not-- 1374 01:08:05,390 --> 01:08:06,640 I've done nothing interesting. 1375 01:08:06,640 --> 01:08:09,540 There's no database, there's no CSV file, we'll get to that in a bit. 1376 01:08:09,540 --> 01:08:11,720 But at least I now have the plumbing in place 1377 01:08:11,720 --> 01:08:15,230 to do something dynamic based on that sport. 1378 01:08:15,230 --> 01:08:18,510 All right, well how can I now improve upon this? 1379 01:08:18,510 --> 01:08:22,850 How about we go ahead and implement-- store the actual registrants 1380 01:08:22,850 --> 01:08:24,840 in a dictionary in the computer's memory. 1381 01:08:24,840 --> 01:08:27,007 So instead of just claiming that they're registered, 1382 01:08:27,007 --> 01:08:28,310 let's actually make a notation. 1383 01:08:28,310 --> 01:08:30,649 And the simplest way as we did weeks ago in Python, 1384 01:08:30,649 --> 01:08:32,840 is just store things in a variable in memory. 1385 01:08:32,840 --> 01:08:36,500 Like a list, or dictionary, a set, anything like that. 1386 01:08:36,500 --> 01:08:39,349 All right, well let me go back into VS Code and in app.py, 1387 01:08:39,349 --> 01:08:43,399 and I think what I'm going to have to do here is change my register route 1388 01:08:43,399 --> 01:08:46,710 to actually do some useful information. 1389 01:08:46,710 --> 01:08:49,910 But before I register the user, let's consider 1390 01:08:49,910 --> 01:08:51,750 where I want to actually put them. 1391 01:08:51,750 --> 01:08:57,020 And so let me propose that how about we do this. 1392 01:08:57,020 --> 01:08:59,899 At the top of my file, let me go ahead and declare 1393 01:08:59,899 --> 01:09:03,439 a global variable called registrants, and set 1394 01:09:03,439 --> 01:09:06,510 that equal to an empty dictionary. 1395 01:09:06,510 --> 01:09:09,229 So we've done this before when we were playing around previously 1396 01:09:09,229 --> 01:09:11,330 with using dictionaries to store key value pairs. 1397 01:09:11,330 --> 01:09:14,210 And I'm going to propose that we store the registrants as a dictionary why? 1398 01:09:14,210 --> 01:09:15,710 Because I'm going to keep it simple. 1399 01:09:15,710 --> 01:09:18,430 Like the name is going to be the student's name-- or sorry, 1400 01:09:18,430 --> 01:09:20,180 the key is going to be the student's name. 1401 01:09:20,180 --> 01:09:22,847 And the value is going to be whatever sport they registered for. 1402 01:09:22,847 --> 01:09:26,149 So David and soccer, and Carter and basketball, and so it's kind 1403 01:09:26,149 --> 01:09:28,910 of make sense for a two column dictionary, so to speak, 1404 01:09:28,910 --> 01:09:30,890 as we often depict it on screen. 1405 01:09:30,890 --> 01:09:32,750 So how can I use this dictionary? 1406 01:09:32,750 --> 01:09:34,220 Well let me go ahead and do this. 1407 01:09:34,220 --> 01:09:40,319 Down here under /register, let me go ahead and initially do this. 1408 01:09:40,319 --> 01:09:44,720 How about we get the user's name from request.form.GET 1409 01:09:44,720 --> 01:09:46,803 and set it equal to whatever the value of name is. 1410 01:09:46,803 --> 01:09:48,678 And I'm not going to give a default value now 1411 01:09:48,678 --> 01:09:52,187 because I don't want to call the student world or something strange like that. 1412 01:09:52,187 --> 01:09:54,229 I'm just going to assume for now that it's there. 1413 01:09:54,229 --> 01:09:56,540 Let's then create another variable called sport, and do 1414 01:09:56,540 --> 01:10:01,700 request.form.GET, quote unquote, "sport" to get these students' sports. 1415 01:10:01,700 --> 01:10:07,100 And then let's go ahead and do this-- in the registrant's dictionary, let's 1416 01:10:07,100 --> 01:10:09,920 index into it using the student's name, and let's 1417 01:10:09,920 --> 01:10:12,720 set it equal to whatever the sport is. 1418 01:10:12,720 --> 01:10:14,990 So I've got these variables just to keep my code tidy, 1419 01:10:14,990 --> 01:10:19,850 and I'm now putting a key value pair in that-- 1420 01:10:19,850 --> 01:10:21,740 into that dictionary. 1421 01:10:21,740 --> 01:10:24,510 All right, well what do I want to now do? 1422 01:10:24,510 --> 01:10:27,795 And so I'll go ahead and say success.HTML, sure. 1423 01:10:27,795 --> 01:10:28,920 Let's go ahead and do that. 1424 01:10:28,920 --> 01:10:31,200 But now I think success.HTML means that. 1425 01:10:31,200 --> 01:10:33,680 So let me go back to the form-- reload. 1426 01:10:33,680 --> 01:10:37,010 Let me type in David and soccer-- 1427 01:10:37,010 --> 01:10:39,290 register. 1428 01:10:39,290 --> 01:10:43,910 Let me go back and say Carter and basketball-- 1429 01:10:43,910 --> 01:10:45,570 register. 1430 01:10:45,570 --> 01:10:46,310 OK. 1431 01:10:46,310 --> 01:10:48,630 Now let's see what I want to do next. 1432 01:10:48,630 --> 01:10:52,430 How about I go into-- 1433 01:10:52,430 --> 01:10:54,960 let me give myself another route and let's play around here. 1434 01:10:54,960 --> 01:10:59,300 So app.route, let's give myself another third route 1435 01:10:59,300 --> 01:11:02,420 called registrants, whose purpose in life is just to show me 1436 01:11:02,420 --> 01:11:03,800 who all of those registrants are. 1437 01:11:03,800 --> 01:11:06,060 Just like you would expect from a website like this. 1438 01:11:06,060 --> 01:11:09,780 And then let me define a function called registrants or anything else. 1439 01:11:09,780 --> 01:11:16,280 And then let me return the rendering of a template called registrants.HTML. 1440 01:11:16,280 --> 01:11:18,410 And let me pass in-- 1441 01:11:18,410 --> 01:11:19,320 this is kind of neat. 1442 01:11:19,320 --> 01:11:21,470 I can do registrants=registrants. 1443 01:11:21,470 --> 01:11:23,760 Which again looks weird, but what am I doing? 1444 01:11:23,760 --> 01:11:26,480 I'm presuming to pass in a placeholder called 1445 01:11:26,480 --> 01:11:30,620 registrants, the value of which is this dictionary that I've been 1446 01:11:30,620 --> 01:11:32,870 collecting all of the registrations in. 1447 01:11:32,870 --> 01:11:34,882 So similar to the name placeholder before, 1448 01:11:34,882 --> 01:11:38,090 but it's a little more powerful because now it's a whole dictionary, not just 1449 01:11:38,090 --> 01:11:39,140 a single string. 1450 01:11:39,140 --> 01:11:40,910 So I think now-- 1451 01:11:40,910 --> 01:11:42,360 let me be creative here. 1452 01:11:42,360 --> 01:11:49,950 Let me go into my templates under my templates folder and let's do this. 1453 01:11:49,950 --> 01:11:53,450 Let's go into my terminal window, let's create 1454 01:11:53,450 --> 01:11:56,780 another template called registrants.HTML that's 1455 01:11:56,780 --> 01:12:00,600 actually going to do this displaying of all of the registrants for us. 1456 01:12:00,600 --> 01:12:06,170 So extends layout.HTML just so I can borrow all of the same HTML as before. 1457 01:12:06,170 --> 01:12:09,620 And let's define block body just like before. 1458 01:12:09,620 --> 01:12:12,890 And inside of this end block I want to put, 1459 01:12:12,890 --> 01:12:16,670 I don't know, a bolded list, or an ordered list of all of the registrants. 1460 01:12:16,670 --> 01:12:18,000 So how can I do this? 1461 01:12:18,000 --> 01:12:21,620 Well, let's do an unordered list, UL. 1462 01:12:21,620 --> 01:12:27,080 And here's where Jinja and Flask more generally get kind of interesting. 1463 01:12:27,080 --> 01:12:34,570 I want there to be something like this-- an li and then the student's name, 1464 01:12:34,570 --> 01:12:36,250 and then an L-- 1465 01:12:36,250 --> 01:12:38,200 maybe-- li, yeah, like that. 1466 01:12:38,200 --> 01:12:39,910 And then maybe sport? 1467 01:12:39,910 --> 01:12:41,140 Something like this? 1468 01:12:41,140 --> 01:12:44,380 But I didn't pass in a name, I didn't pass in a sport, 1469 01:12:44,380 --> 01:12:47,263 I passed in the entire dictionary of registrants. 1470 01:12:47,263 --> 01:12:49,180 Now in Python, if we were just doing something 1471 01:12:49,180 --> 01:12:53,180 at the black and white terminal window and doing a command line program, 1472 01:12:53,180 --> 01:12:55,840 you know I'd probably have some kind of for loop in Python. 1473 01:12:55,840 --> 01:12:58,030 Jinja does allow you to do this. 1474 01:12:58,030 --> 01:13:01,300 So a templating language tends to come with very lightweight mechanisms 1475 01:13:01,300 --> 01:13:05,180 for doing placeholders, doing simple loops, doing simple conditions. 1476 01:13:05,180 --> 01:13:08,270 So Python like syntax, and it's almost identical. 1477 01:13:08,270 --> 01:13:09,760 So watch what I can do. 1478 01:13:09,760 --> 01:13:12,040 Inside of this unordered list, let me not 1479 01:13:12,040 --> 01:13:17,150 start to manually output a single li, let me use this syntax. 1480 01:13:17,150 --> 01:13:21,640 The same Jinja syntax that I used for block, so curly brace percent sign. 1481 01:13:21,640 --> 01:13:25,330 And I'm going to say this-- for name in registrants. 1482 01:13:25,330 --> 01:13:29,390 So this is just like Python syntax for iterating over a dictionary. 1483 01:13:29,390 --> 01:13:33,100 And now this is going to look stupid, but the opposite of that is end for. 1484 01:13:33,100 --> 01:13:35,140 So in HTML, you use the slash. 1485 01:13:35,140 --> 01:13:35,650 In Jinja. 1486 01:13:35,650 --> 01:13:37,845 You literally use the word end, no space, 1487 01:13:37,845 --> 01:13:39,220 and then the name of the keyword. 1488 01:13:39,220 --> 01:13:41,350 So end for is how you close this. 1489 01:13:41,350 --> 01:13:44,080 But this is where templating gets really cool. 1490 01:13:44,080 --> 01:13:50,800 You can now do li, and in here I can do something like that student's name. 1491 01:13:50,800 --> 01:13:51,470 And that's it. 1492 01:13:51,470 --> 01:13:52,880 I'm going to leave it like that. 1493 01:13:52,880 --> 01:13:58,000 And what I'm doing here is using really a template as templates are intended. 1494 01:13:58,000 --> 01:14:00,730 I've got the basic building blocks of what 1495 01:14:00,730 --> 01:14:04,480 I want this output to look like, but thanks to this little for loop here, 1496 01:14:04,480 --> 01:14:05,890 thanks to Jinja syntax-- 1497 01:14:05,890 --> 01:14:08,110 the curly brace and the percent sign, I'm 1498 01:14:08,110 --> 01:14:11,810 going to iterate over every dictionary printing out name, name, name, name. 1499 01:14:11,810 --> 01:14:14,980 And so if I've got two kids registered now, I'm going to see two li's. 1500 01:14:14,980 --> 01:14:17,420 David and Carter respectively. 1501 01:14:17,420 --> 01:14:23,860 So let's see, let me go back to my frosh IMs tab here. 1502 01:14:23,860 --> 01:14:27,370 And I don't have a link yet, so I've got to do this manually 1503 01:14:27,370 --> 01:14:28,810 like a developer would. 1504 01:14:28,810 --> 01:14:34,570 Let me go to /registrants and I'll Zoom out and hit Enter. 1505 01:14:34,570 --> 01:14:37,690 And you'll see what you'll probably see too when making mistakes 1506 01:14:37,690 --> 01:14:39,200 for the first time in this world. 1507 01:14:39,200 --> 01:14:40,930 So where is the error message? 1508 01:14:40,930 --> 01:14:44,480 Unfortunately internal server error is not all that useful. 1509 01:14:44,480 --> 01:14:46,490 But we do tell you see terminal window. 1510 01:14:46,490 --> 01:14:49,783 So if I go to the terminal window, I haven't been paying attention 1511 01:14:49,783 --> 01:14:50,950 to this for quite some time. 1512 01:14:50,950 --> 01:14:52,950 And in fact, I have two terminal Windows open so 1513 01:14:52,950 --> 01:14:54,950 that I can still use commands at the prompt. 1514 01:14:54,950 --> 01:14:58,510 But if I go back to my first terminal window, a.k.a. bash there, 1515 01:14:58,510 --> 01:15:01,330 you'll see in your terminal window when developing 1516 01:15:01,330 --> 01:15:05,622 web applications, all of the mistakes you made in the terminal itself. 1517 01:15:05,622 --> 01:15:08,830 This is one of those Python tracebacks that's related to me screwing up here. 1518 01:15:08,830 --> 01:15:10,460 Now let me go ahead here. 1519 01:15:10,460 --> 01:15:15,490 And let's see-- type error-- function is not iterable. 1520 01:15:15,490 --> 01:15:21,440 End block-- for name function is not iterable. 1521 01:15:21,440 --> 01:15:23,750 All right, so what mistake did I make? 1522 01:15:23,750 --> 01:15:26,390 Well this is what happens when I don't follow my notes 1523 01:15:26,390 --> 01:15:27,960 and make changes on the fly. 1524 01:15:27,960 --> 01:15:31,850 So I have this variable on line five called registrants and all lowercase. 1525 01:15:31,850 --> 01:15:35,195 But what did I then do on the fly here in line 22? 1526 01:15:35,195 --> 01:15:38,220 1527 01:15:38,220 --> 01:15:40,600 I defined a function called registrants. 1528 01:15:40,600 --> 01:15:42,888 So newbie mistake, I shouldn't have done this. 1529 01:15:42,888 --> 01:15:45,180 I can't have a variable and a function of the same name 1530 01:15:45,180 --> 01:15:47,170 because the symbols are literally identical. 1531 01:15:47,170 --> 01:15:50,430 So just to make clear that this variable up here is actually global, 1532 01:15:50,430 --> 01:15:55,260 we'll use our convention like we did in C often, when we had a global variable. 1533 01:15:55,260 --> 01:15:59,220 We'll capitalize it all just to make it stand out like a constant value 1534 01:15:59,220 --> 01:15:59,860 up there. 1535 01:15:59,860 --> 01:16:04,170 And so down here, what I'm going to do is pass in registrants in all caps. 1536 01:16:04,170 --> 01:16:06,550 So that was stupid, didn't mean to confuse there. 1537 01:16:06,550 --> 01:16:08,400 But the reason for that error, to be clear, 1538 01:16:08,400 --> 01:16:11,370 is that you can't have a function that's the same name as a variable. 1539 01:16:11,370 --> 01:16:12,990 I could just change the variable name altogether. 1540 01:16:12,990 --> 01:16:14,698 I'm going to go ahead and just capitalize 1541 01:16:14,698 --> 01:16:18,240 it to make it really stand out that this is, in fact, a global variable up top. 1542 01:16:18,240 --> 01:16:20,910 All right, now I'm going to go back to my browser. 1543 01:16:20,910 --> 01:16:23,025 Let's do David and soccer. 1544 01:16:23,025 --> 01:16:26,640 1545 01:16:26,640 --> 01:16:29,200 All right, but there's going to be some other mistakes here. 1546 01:16:29,200 --> 01:16:32,760 So on line 17, let me go ahead and change this variable 1547 01:16:32,760 --> 01:16:36,750 to be capitalized there because indeed I want to put the key and the value 1548 01:16:36,750 --> 01:16:40,170 in this newly named variable as all capitals registrants. 1549 01:16:40,170 --> 01:16:42,370 Let me now go back to VS Code here. 1550 01:16:42,370 --> 01:16:45,900 Let me go back to the form and let me start adding some data fresh. 1551 01:16:45,900 --> 01:16:48,540 Let me register David for soccer. 1552 01:16:48,540 --> 01:16:49,927 Clicking register now. 1553 01:16:49,927 --> 01:16:51,510 And we should see, you are registered. 1554 01:16:51,510 --> 01:16:54,210 But, hopefully, now it's indeed in the computer's memory. 1555 01:16:54,210 --> 01:16:58,650 Let me go back and register now Carter for basketball. 1556 01:16:58,650 --> 01:17:00,120 Clicking register again. 1557 01:17:00,120 --> 01:17:01,740 And hopefully it's now registered. 1558 01:17:01,740 --> 01:17:06,210 If I now change my route manually to be /registrants, 1559 01:17:06,210 --> 01:17:10,260 which is this newly added route that I made, and hit Enter, now I see-- 1560 01:17:10,260 --> 01:17:10,770 thank God. 1561 01:17:10,770 --> 01:17:15,790 Now I see the unordered list containing everything in the computer's memory. 1562 01:17:15,790 --> 01:17:17,760 So when I say, you are registered, I kind of 1563 01:17:17,760 --> 01:17:20,220 mean it now because the server is still running. 1564 01:17:20,220 --> 01:17:24,330 And in the computer's memory is, in this registrant global variable, 1565 01:17:24,330 --> 01:17:26,460 a dictionary of key value pairs. 1566 01:17:26,460 --> 01:17:29,080 Of course, we're only seeing the keys at the moment. 1567 01:17:29,080 --> 01:17:32,770 So it might be nice to actually see the values as well. 1568 01:17:32,770 --> 01:17:38,600 So let me go back to VS code and let me go into registrants HTML. 1569 01:17:38,600 --> 01:17:40,350 And I'll just do something a little messy. 1570 01:17:40,350 --> 01:17:42,640 I'll just say-- how about-- 1571 01:17:42,640 --> 01:17:46,380 just to make it a sentence, is registered for. 1572 01:17:46,380 --> 01:17:51,660 And now another placeholder, I'm going to say registrants bracket name. 1573 01:17:51,660 --> 01:17:55,050 So just like in Python, if registrants is itself 1574 01:17:55,050 --> 01:18:00,090 a dictionary, registrants bracket and then the key you want to index into 1575 01:18:00,090 --> 01:18:02,560 is perfectly valid syntax as well. 1576 01:18:02,560 --> 01:18:08,020 So now let me go back to /registrants, let me click reload again. 1577 01:18:08,020 --> 01:18:09,900 So why isn't it working everyone? 1578 01:18:09,900 --> 01:18:12,480 What's the bug that I introduced earlier? 1579 01:18:12,480 --> 01:18:15,510 If David is registered for none, and Carter is registered for none, 1580 01:18:15,510 --> 01:18:19,330 but David and Carter are in the dictionary, that's a good thing. 1581 01:18:19,330 --> 01:18:21,100 So some of the data is in there. 1582 01:18:21,100 --> 01:18:23,605 So why are there no sports associated? 1583 01:18:23,605 --> 01:18:25,980 Well the first thing I literally just did in front of you 1584 01:18:25,980 --> 01:18:30,000 all was I went to app.py and I stared at line 17 thinking, 1585 01:18:30,000 --> 01:18:31,480 how did I screw this up? 1586 01:18:31,480 --> 01:18:35,610 I'm putting sport as the value of the key which is the student's name. 1587 01:18:35,610 --> 01:18:38,230 All right, line 17 looked fine to me a few seconds ago. 1588 01:18:38,230 --> 01:18:41,940 So I look then with my eyes at line 16, and this, too, looked OK. 1589 01:18:41,940 --> 01:18:46,450 My first thought was, oh did I use request.args instead of request.form 1590 01:18:46,450 --> 01:18:46,950 instead? 1591 01:18:46,950 --> 01:18:49,117 Because that would have assumed GET instead of POST. 1592 01:18:49,117 --> 01:18:51,330 But no, that looks OK too. 1593 01:18:51,330 --> 01:18:55,690 So then my final instinct was. oh my God, did I screw up the HTML form? 1594 01:18:55,690 --> 01:18:58,080 And so that's why I went back over to my tab here. 1595 01:18:58,080 --> 01:19:03,060 I went to the original form here, I then view page source. 1596 01:19:03,060 --> 01:19:05,790 And this might not be as obvious to you if you've never 1597 01:19:05,790 --> 01:19:07,650 seen the Select menu before-- 1598 01:19:07,650 --> 01:19:13,045 what is apparently missing here that might explain my mistake? 1599 01:19:13,045 --> 01:19:13,545 Yeah. 1600 01:19:13,545 --> 01:19:15,060 AUDIENCE: The name is form. 1601 01:19:15,060 --> 01:19:18,988 DAVID MALAN: Yeah, I didn't name this form field, quote unquote, "sport". 1602 01:19:18,988 --> 01:19:21,780 Now to be fair, you haven't seen me do this as a select menu before 1603 01:19:21,780 --> 01:19:23,340 and it's different from this input. 1604 01:19:23,340 --> 01:19:26,970 When you have an input tag, you literally say name= whatever 1605 01:19:26,970 --> 01:19:28,248 on the input tag. 1606 01:19:28,248 --> 01:19:30,540 It turns out-- I don't know why I skipped this earlier. 1607 01:19:30,540 --> 01:19:33,030 I probably meant to come back to it-- the select tag also 1608 01:19:33,030 --> 01:19:34,900 can take a name parameter. 1609 01:19:34,900 --> 01:19:38,820 So if I go back to the name parameter here and go back 1610 01:19:38,820 --> 01:19:42,420 and add the name parameter, let me go into that template, which 1611 01:19:42,420 --> 01:19:44,010 is index.html. 1612 01:19:44,010 --> 01:19:48,090 Let me add name= quote unquote, "sport" in all lowercase, 1613 01:19:48,090 --> 01:19:52,560 which is different from the visual aesthetic of this temporary disabled 1614 01:19:52,560 --> 01:19:55,320 option that's just there to make things prettier for the human. 1615 01:19:55,320 --> 01:20:01,680 Now let me go ahead here, and first I'm going to go into my terminal window, 1616 01:20:01,680 --> 01:20:04,920 and I'm actually going to hit Control C to stop the server altogether 1617 01:20:04,920 --> 01:20:07,197 because I want to throw away the contents of memory 1618 01:20:07,197 --> 01:20:10,530 and therefore get rid of that dictionary that had David and Carter and those non 1619 01:20:10,530 --> 01:20:11,110 values. 1620 01:20:11,110 --> 01:20:13,620 So this is sort of me clearing the computer's memory. 1621 01:20:13,620 --> 01:20:16,110 I'm going to rerun Flask run. 1622 01:20:16,110 --> 01:20:18,012 I get that same URL as before. 1623 01:20:18,012 --> 01:20:20,220 So I'm going to hover over that and open the new tab. 1624 01:20:20,220 --> 01:20:22,680 And just to be sure, I'm going to do view page source. 1625 01:20:22,680 --> 01:20:28,230 And here I see now, OK, now the form has both a name and a sport in it. 1626 01:20:28,230 --> 01:20:30,420 All right, now I'm really going to cross my fingers 1627 01:20:30,420 --> 01:20:32,520 because I intend for this now to work. 1628 01:20:32,520 --> 01:20:35,130 David will register again for soccer. 1629 01:20:35,130 --> 01:20:37,380 Register-- claims we are registered. 1630 01:20:37,380 --> 01:20:40,920 I'm going to go back and do it again for Carter and basketball. 1631 01:20:40,920 --> 01:20:44,580 Register-- we still don't have a link, so I'm going to manually go up 1632 01:20:44,580 --> 01:20:49,830 to the URL and change /register to registrants as before. 1633 01:20:49,830 --> 01:20:51,690 Zooming out and hit Enter. 1634 01:20:51,690 --> 01:20:52,740 And thank God. 1635 01:20:52,740 --> 01:20:55,650 Now I'm actually registered properly for this. 1636 01:20:55,650 --> 01:20:56,910 So-- oh, thank you. 1637 01:20:56,910 --> 01:21:01,075 1638 01:21:01,075 --> 01:21:02,950 So what is it, like 20 years later, I'm still 1639 01:21:02,950 --> 01:21:04,367 struggling to implement this site? 1640 01:21:04,367 --> 01:21:09,610 OK, so here now we have for the first time in Python and web stuff, 1641 01:21:09,610 --> 01:21:11,250 now we have a proper web application. 1642 01:21:11,250 --> 01:21:13,750 And it's not just echoing back Hello, David, Hello, Carter-- 1643 01:21:13,750 --> 01:21:15,670 this could now work for any of you. 1644 01:21:15,670 --> 01:21:18,580 And it's currently served privately, but if I made this URL public, 1645 01:21:18,580 --> 01:21:22,180 I could put this on the web now and let anyone in the world register. 1646 01:21:22,180 --> 01:21:25,010 But there's some issues here. 1647 01:21:25,010 --> 01:21:27,770 There's some security flaws potentially. 1648 01:21:27,770 --> 01:21:30,580 And so for instance, let me go back to the web form here. 1649 01:21:30,580 --> 01:21:34,510 And let me open up the inspect tab-- the developer tools-- 1650 01:21:34,510 --> 01:21:38,110 and just remind you that anyone on the internet, not only you, the developer, 1651 01:21:38,110 --> 01:21:42,340 but an adversary can see all of your HTML, see all of your CSS, 1652 01:21:42,340 --> 01:21:43,510 see all of your JavaScript. 1653 01:21:43,510 --> 01:21:47,380 But more importantly, because this is all client side in the browser, 1654 01:21:47,380 --> 01:21:50,050 there is literally nothing technically stopping them 1655 01:21:50,050 --> 01:21:53,542 from changing the HTML, or at least their copy of it. 1656 01:21:53,542 --> 01:21:55,000 And I did that last week with Yale. 1657 01:21:55,000 --> 01:21:56,200 I changed their website. 1658 01:21:56,200 --> 01:21:58,370 But no, I changed my copy of their website. 1659 01:21:58,370 --> 01:22:02,530 But when forms get involved, you could maybe be actually malicious now. 1660 01:22:02,530 --> 01:22:05,500 Because even though this dropdown menu only 1661 01:22:05,500 --> 01:22:09,610 has basketball, soccer, and ultimate Frisbee, suppose 1662 01:22:09,610 --> 01:22:12,370 I really want to register for-- 1663 01:22:12,370 --> 01:22:15,513 how about let's say-- 1664 01:22:15,513 --> 01:22:16,555 name your favorite sport. 1665 01:22:16,555 --> 01:22:17,560 AUDIENCE: Volleyball. 1666 01:22:17,560 --> 01:22:18,250 DAVID MALAN: Volleyball. 1667 01:22:18,250 --> 01:22:20,170 We really want to register for volleyball, 1668 01:22:20,170 --> 01:22:22,630 but this website won't let me. 1669 01:22:22,630 --> 01:22:25,720 Well there's nothing stopping me from going under the Elements tab 1670 01:22:25,720 --> 01:22:28,990 in my browser, going into the Select menu here, 1671 01:22:28,990 --> 01:22:31,720 and you know what, no one [INAUDIBLE] ultimate Frisbee. 1672 01:22:31,720 --> 01:22:33,790 Let's change this to volleyball. 1673 01:22:33,790 --> 01:22:36,580 And let's change this to volleyball-- 1674 01:22:36,580 --> 01:22:37,510 Enter. 1675 01:22:37,510 --> 01:22:39,970 I'm going to close the inspector now. 1676 01:22:39,970 --> 01:22:43,960 And as requested, now we support volleyball in the form. 1677 01:22:43,960 --> 01:22:47,410 Now it's not changed on the server, to be fair, 1678 01:22:47,410 --> 01:22:49,330 but think about how HTTP works. 1679 01:22:49,330 --> 01:22:53,050 When I fill out this with say, let's see, Bernie's name-- 1680 01:22:53,050 --> 01:22:55,990 Bernie really wants to register for volleyball as well. 1681 01:22:55,990 --> 01:23:00,280 At the moment, my code is just going to trust that what's in request form 1682 01:23:00,280 --> 01:23:04,240 is what was in the original form itself, no matter 1683 01:23:04,240 --> 01:23:07,310 whether the human adversarially actually changed it. 1684 01:23:07,310 --> 01:23:09,580 So if I actually submit this form and click 1685 01:23:09,580 --> 01:23:12,670 Register for Bernie and volleyball, even though that's not 1686 01:23:12,670 --> 01:23:16,720 one of the supported available sports, if I now go to registrants, 1687 01:23:16,720 --> 01:23:20,050 my website nonetheless has trusted that Bernie 1688 01:23:20,050 --> 01:23:22,510 and perhaps you are registered for volleyball. 1689 01:23:22,510 --> 01:23:24,130 So what's the implication of this? 1690 01:23:24,130 --> 01:23:27,250 Is surely happened in the past when really poorly implemented 1691 01:23:27,250 --> 01:23:32,123 websites allow you to specify the price of an item, for instance, 1692 01:23:32,123 --> 01:23:33,040 in your shopping cart. 1693 01:23:33,040 --> 01:23:35,890 And they just trust that when you click Submit or add to cart 1694 01:23:35,890 --> 01:23:39,220 it adds the price to the back end server. 1695 01:23:39,220 --> 01:23:42,640 If you're not validating the price and making sure, as with a database that, 1696 01:23:42,640 --> 01:23:44,410 wait a minute, that price is valid. 1697 01:23:44,410 --> 01:23:46,630 Or wait a minute, those sports are valid. 1698 01:23:46,630 --> 01:23:48,850 Who knows what people are going to do to your site? 1699 01:23:48,850 --> 01:23:53,090 And it's that simple to actually hack a website accordingly. 1700 01:23:53,090 --> 01:23:57,820 Now, we can very easily fix this with some week six style Python. 1701 01:23:57,820 --> 01:24:00,080 We really just need to do a bit of logic here. 1702 01:24:00,080 --> 01:24:01,430 And so let me propose this. 1703 01:24:01,430 --> 01:24:03,710 Let me go into app.py here. 1704 01:24:03,710 --> 01:24:09,610 And at the very top let me also create how about a global variable called 1705 01:24:09,610 --> 01:24:10,960 sports in all caps. 1706 01:24:10,960 --> 01:24:13,660 And I'm going to set that equal to in square brackets 1707 01:24:13,660 --> 01:24:16,010 the list of sports I actually want to support. 1708 01:24:16,010 --> 01:24:20,110 So I'm going to put in basketball here, I'm going to put in soccer here, and-- 1709 01:24:20,110 --> 01:24:21,700 I'm sorry, no volleyball officially. 1710 01:24:21,700 --> 01:24:24,140 I'm going to put in ultimate Frisbee here. 1711 01:24:24,140 --> 01:24:26,800 So I've got this global list of supported sports. 1712 01:24:26,800 --> 01:24:29,650 Now think about how I made this form a while ago. 1713 01:24:29,650 --> 01:24:31,670 I just hardcoded these sports here. 1714 01:24:31,670 --> 01:24:36,280 Well I don't have to do that, I can draw upon my own official list of sports 1715 01:24:36,280 --> 01:24:37,070 instead. 1716 01:24:37,070 --> 01:24:41,740 So let me scroll down to my index.HTML rendering template here. 1717 01:24:41,740 --> 01:24:44,530 Let me say that the sports I want to support are these. 1718 01:24:44,530 --> 01:24:47,630 So just using the same placeholder trick as before, 1719 01:24:47,630 --> 01:24:51,190 but I'm now telling the template what sports we currently support. 1720 01:24:51,190 --> 01:24:56,480 Now if I go back into index.HTML, I don't have to manually do any of this. 1721 01:24:56,480 --> 01:24:59,500 Let me get rid of all three of those options, which I manually 1722 01:24:59,500 --> 01:25:03,100 inputted earlier, let me use my new trick with Jinja syntax 1723 01:25:03,100 --> 01:25:06,040 and say for sports in sports. 1724 01:25:06,040 --> 01:25:09,400 Then let me proactively say end for, just to finish that thought. 1725 01:25:09,400 --> 01:25:12,640 And then in here let me do option value=value=[? sports ?].. 1726 01:25:12,640 --> 01:25:15,280 1727 01:25:15,280 --> 01:25:17,980 And then so that the human also sees the same words, 1728 01:25:17,980 --> 01:25:19,640 I'm going to say sport out here. 1729 01:25:19,640 --> 01:25:22,690 So I've completely changed what was hardcoded-- 1730 01:25:22,690 --> 01:25:25,780 manually typed-- to something now that's completely dynamic. 1731 01:25:25,780 --> 01:25:28,750 So now it's not going to stop someone adversarially like me 1732 01:25:28,750 --> 01:25:31,150 from changing the HTML, but watch this. 1733 01:25:31,150 --> 01:25:35,350 The behavior on the form if we go back is still now 1734 01:25:35,350 --> 01:25:37,190 the same dropdown as before. 1735 01:25:37,190 --> 01:25:39,110 So aesthetically, it looks the same. 1736 01:25:39,110 --> 01:25:39,860 But you know what? 1737 01:25:39,860 --> 01:25:40,985 Why don't we be clever now. 1738 01:25:40,985 --> 01:25:44,290 And let's go into app.py and the /register route, 1739 01:25:44,290 --> 01:25:46,450 and why don't we say this. 1740 01:25:46,450 --> 01:25:53,920 If-- how about sport not in sports, Then let's return render 1741 01:25:53,920 --> 01:25:57,460 template failure.HTML. 1742 01:25:57,460 --> 01:25:59,210 Now this template doesn't exist yet. 1743 01:25:59,210 --> 01:26:01,040 So let me just quickly make this real fast. 1744 01:26:01,040 --> 01:26:03,040 I'm going to copy that code from before. 1745 01:26:03,040 --> 01:26:08,383 Let me create a code file in failure.HTML. 1746 01:26:08,383 --> 01:26:09,800 I'm just going to paste this here. 1747 01:26:09,800 --> 01:26:12,383 So we have a super simple error message, and I'm going to say, 1748 01:26:12,383 --> 01:26:13,750 you are not registered. 1749 01:26:13,750 --> 01:26:15,610 That's what we mean by failure. 1750 01:26:15,610 --> 01:26:18,790 And now in app.py, consider what logic I've added. 1751 01:26:18,790 --> 01:26:23,320 SPORTS in all caps on line 22 is that same global list 1752 01:26:23,320 --> 01:26:27,160 as before by asking [? Pythonically, ?] if sport not 1753 01:26:27,160 --> 01:26:29,320 in sports, well then you hacked me. 1754 01:26:29,320 --> 01:26:34,460 Like you tried to inject volleyball or some other sport into request.form. 1755 01:26:34,460 --> 01:26:37,990 So I'm just going to say, no failure, not letting you register. 1756 01:26:37,990 --> 01:26:42,280 And I can do this a little more verbosely too. 1757 01:26:42,280 --> 01:26:43,780 Why don't I also say this. 1758 01:26:43,780 --> 01:26:47,680 If not name-- so if the name is blank, let's similarly return 1759 01:26:47,680 --> 01:26:50,785 a render template of failure.HTML. 1760 01:26:50,785 --> 01:26:52,660 In other words, if you didn't give me a name, 1761 01:26:52,660 --> 01:26:55,760 you left it blank, that's not useful for me running the sports program. 1762 01:26:55,760 --> 01:26:57,950 Let's also consider that to be a failure. 1763 01:26:57,950 --> 01:27:00,220 So if I go back to this tab now, I'm going 1764 01:27:00,220 --> 01:27:03,700 to reload just to make sure I have the latest client side, let me be lazy 1765 01:27:03,700 --> 01:27:04,960 and just click Register. 1766 01:27:04,960 --> 01:27:06,100 Enter. 1767 01:27:06,100 --> 01:27:08,920 You are not registered because I didn't give it an actual name. 1768 01:27:08,920 --> 01:27:10,370 All right, well let's go back. 1769 01:27:10,370 --> 01:27:13,480 How about I now type David but no, I'm not going to choose a sport. 1770 01:27:13,480 --> 01:27:15,500 I just want to register myself. 1771 01:27:15,500 --> 01:27:17,060 Nope, that did not work. 1772 01:27:17,060 --> 01:27:20,220 Now let me go ahead here and choose soccer. 1773 01:27:20,220 --> 01:27:22,770 This, I think, does work. 1774 01:27:22,770 --> 01:27:27,810 Let me go back now and try this hacker trick whereby I go into the dropdown 1775 01:27:27,810 --> 01:27:31,050 menu, I go into the Select menu. 1776 01:27:31,050 --> 01:27:34,830 I change, as before, ultimate Frisbee to volleyball, 1777 01:27:34,830 --> 01:27:38,100 and I'll change this one here to volleyball. 1778 01:27:38,100 --> 01:27:40,110 Let me close the tab now. 1779 01:27:40,110 --> 01:27:44,850 This looks like it's available now, but when I click Register this time, 1780 01:27:44,850 --> 01:27:47,040 it says you are not registered. 1781 01:27:47,040 --> 01:27:50,250 And this is much better than relying on other techniques you 1782 01:27:50,250 --> 01:27:53,850 might see or have seen online with regard to HTML because there's also 1783 01:27:53,850 --> 01:27:54,640 this trick. 1784 01:27:54,640 --> 01:27:56,410 Let me go back to the screen here. 1785 01:27:56,410 --> 01:27:59,272 Let me go back to index.html, and you might have seen online, 1786 01:27:59,272 --> 01:28:01,230 or you might eventually see online that there's 1787 01:28:01,230 --> 01:28:03,570 other attributes you can use like required. 1788 01:28:03,570 --> 01:28:06,760 You can literally tell the browser, uh-uh, this field is required. 1789 01:28:06,760 --> 01:28:08,100 You cannot leave it blank. 1790 01:28:08,100 --> 01:28:12,480 If I go back to the browser now, reload, and I again presume to be lazy 1791 01:28:12,480 --> 01:28:15,360 and I don't type in any name and click Register-- 1792 01:28:15,360 --> 01:28:16,500 So that's kind of nice. 1793 01:28:16,500 --> 01:28:20,970 Now the browser is being a little more helpful for me, saying no, no, no. 1794 01:28:20,970 --> 01:28:21,940 This is required. 1795 01:28:21,940 --> 01:28:23,192 You have to fill this out. 1796 01:28:23,192 --> 01:28:24,900 But again, if you know what you're doing. 1797 01:28:24,900 --> 01:28:28,080 OK, well I disagree with your requiring a name of me. 1798 01:28:28,080 --> 01:28:29,440 Let me go in here. 1799 01:28:29,440 --> 01:28:33,930 Let me go over to this tag, let me delete the required attribute, 1800 01:28:33,930 --> 01:28:36,880 and now I slip through. 1801 01:28:36,880 --> 01:28:38,680 But I didn't slip through on the server. 1802 01:28:38,680 --> 01:28:40,710 And so there's a difference here and an important distinction, 1803 01:28:40,710 --> 01:28:43,330 and so many people in the real world still screw this up. 1804 01:28:43,330 --> 01:28:46,200 There's client side validation, like actually checking 1805 01:28:46,200 --> 01:28:48,960 that the data is as you expect on the client side, the browser. 1806 01:28:48,960 --> 01:28:50,730 And there's server side validation. 1807 01:28:50,730 --> 01:28:53,785 And even though client side validation, adding that required attribute 1808 01:28:53,785 --> 01:28:55,410 makes things more user friendly, right? 1809 01:28:55,410 --> 01:28:56,790 Like that was a pretty little pop up. 1810 01:28:56,790 --> 01:28:58,082 It tells me that it's required. 1811 01:28:58,082 --> 01:29:00,210 It just looks better than the previous version. 1812 01:29:00,210 --> 01:29:01,920 It is not trustable. 1813 01:29:01,920 --> 01:29:06,390 You cannot trust any input that ever comes from the user because clearly 1814 01:29:06,390 --> 01:29:11,120 with an hour or so of CS50, they can learn how to turn all of these defenses 1815 01:29:11,120 --> 01:29:11,620 off. 1816 01:29:11,620 --> 01:29:14,700 So even if you like the user interface better client side, 1817 01:29:14,700 --> 01:29:18,630 you have to, have to, have to do server side validation always. 1818 01:29:18,630 --> 01:29:20,290 Users are not to be trusted. 1819 01:29:20,290 --> 01:29:23,100 And as soon as any app or website you make becomes popular, 1820 01:29:23,100 --> 01:29:27,205 unfortunately then you have to deal with all of the adversarial possibilities 1821 01:29:27,205 --> 01:29:27,705 as well. 1822 01:29:27,705 --> 01:29:31,680 AUDIENCE: Is there any way you can hack inside the server side 1823 01:29:31,680 --> 01:29:34,480 information or potentially hack [INAUDIBLE] or something like that? 1824 01:29:34,480 --> 01:29:35,688 DAVID MALAN: A good question. 1825 01:29:35,688 --> 01:29:38,930 Could the adversary potentially access things sensitive like app.py? 1826 01:29:38,930 --> 01:29:40,520 Theoretically no. 1827 01:29:40,520 --> 01:29:43,100 If Flask itself is buggy, then sure, maybe. 1828 01:29:43,100 --> 01:29:46,580 If you're running some other software on your server on your laptop then sure, 1829 01:29:46,580 --> 01:29:47,820 it's possible. 1830 01:29:47,820 --> 01:29:49,850 However, if your server is properly configured, 1831 01:29:49,850 --> 01:29:52,580 theoretically they should not be able to get access to that. 1832 01:29:52,580 --> 01:29:54,680 With that said, we'll soon see, or you might 1833 01:29:54,680 --> 01:29:56,930 with your final project if you do something web based, 1834 01:29:56,930 --> 01:29:59,690 you're never going to want to write usernames 1835 01:29:59,690 --> 01:30:01,993 and passwords in your actual code. 1836 01:30:01,993 --> 01:30:04,410 You can put them in what are called environment variables. 1837 01:30:04,410 --> 01:30:06,243 So sort of in the computer's memory, but not 1838 01:30:06,243 --> 01:30:09,110 in your code just in case you or someone screws up, 1839 01:30:09,110 --> 01:30:13,520 there are still ways to defend against those kinds of possibilities, 1840 01:30:13,520 --> 01:30:14,325 however slim. 1841 01:30:14,325 --> 01:30:14,825 Yeah. 1842 01:30:14,825 --> 01:30:19,006 AUDIENCE: [INAUDIBLE] making sure volleyball didn't get registered. 1843 01:30:19,006 --> 01:30:21,872 1844 01:30:21,872 --> 01:30:23,080 DAVID MALAN: A good question. 1845 01:30:23,080 --> 01:30:26,080 And this comes back to first principles, just like in C and in Python, 1846 01:30:26,080 --> 01:30:29,110 as soon as you return from a function, that's it. 1847 01:30:29,110 --> 01:30:31,540 Nothing below that line of code executes. 1848 01:30:31,540 --> 01:30:34,480 And so to summarize the question, even though I'm 1849 01:30:34,480 --> 01:30:37,360 returning this failure.HTML template, how 1850 01:30:37,360 --> 01:30:40,270 am I making sure we still don't accidentally put volleyball 1851 01:30:40,270 --> 01:30:41,770 in that global dictionary? 1852 01:30:41,770 --> 01:30:44,470 It's because, for instance, if you don't give me a name, 1853 01:30:44,470 --> 01:30:48,190 on line 22 at the moment, I'm returning the failure template and that's it. 1854 01:30:48,190 --> 01:30:51,940 Lines 23, 24, 25, 26, 27 never execute. 1855 01:30:51,940 --> 01:30:54,820 In particular, 26 never executes, and that's 1856 01:30:54,820 --> 01:30:56,680 where I would have been saving the name. 1857 01:30:56,680 --> 01:31:02,200 Similarly, if we do we get an invalid sport that is either blank or not 1858 01:31:02,200 --> 01:31:06,280 in the original authoritative list, we return failure.HTML 1859 01:31:06,280 --> 01:31:07,510 as a template in line 25. 1860 01:31:07,510 --> 01:31:09,950 We never get to line 26. 1861 01:31:09,950 --> 01:31:13,300 So it just boils down to return and what that means in Python too. 1862 01:31:13,300 --> 01:31:15,020 Good question. 1863 01:31:15,020 --> 01:31:17,970 Other questions as well? 1864 01:31:17,970 --> 01:31:18,470 No? 1865 01:31:18,470 --> 01:31:23,150 All right, how about we make one more enhancement here or so. 1866 01:31:23,150 --> 01:31:27,740 Because the problem with storing everything in this global dictionary 1867 01:31:27,740 --> 01:31:29,930 might be what? 1868 01:31:29,930 --> 01:31:32,900 We've got it all working, finally, but why 1869 01:31:32,900 --> 01:31:35,900 is probably a global dictionary not the place 1870 01:31:35,900 --> 01:31:39,760 to store frosh IMs registration data? 1871 01:31:39,760 --> 01:31:41,335 What's the implication of this? 1872 01:31:41,335 --> 01:31:43,870 AUDIENCE: Might slow the whole process. 1873 01:31:43,870 --> 01:31:45,170 DAVID MALAN: OK, it might slow the whole process down. 1874 01:31:45,170 --> 01:31:46,878 But that actually-- RAM is actually good. 1875 01:31:46,878 --> 01:31:48,710 Memory is actually generally a good thing. 1876 01:31:48,710 --> 01:31:51,065 So not going to be a dealbreaker here. 1877 01:31:51,065 --> 01:31:53,815 Why might I not want to store that data, though, in that variable? 1878 01:31:53,815 --> 01:31:57,040 1879 01:31:57,040 --> 01:32:01,500 You can perhaps infer how I fixed something earlier. 1880 01:32:01,500 --> 01:32:02,430 Yeah, in the back. 1881 01:32:02,430 --> 01:32:04,330 AUDIENCE: [INAUDIBLE] 1882 01:32:04,330 --> 01:32:07,330 DAVID MALAN: Yeah, it gets-- it's-- the memory gets deleted. 1883 01:32:07,330 --> 01:32:10,460 Garbage collected, if you will, as soon as Flask stops running. 1884 01:32:10,460 --> 01:32:14,650 So if you so much as hit Control C, you've just lost all of your freshmen 1885 01:32:14,650 --> 01:32:16,060 who registered for the sport. 1886 01:32:16,060 --> 01:32:17,570 Probably not a good thing. 1887 01:32:17,570 --> 01:32:20,770 I did this deliberately a moment ago and I hit Control C because I did 1888 01:32:20,770 --> 01:32:24,670 want to clear the dictionary, but trusting that your server will never 1889 01:32:24,670 --> 01:32:27,978 crash, and your code will always work, and the power will never go out, 1890 01:32:27,978 --> 01:32:30,520 that's not the right way to build any kind of web application 1891 01:32:30,520 --> 01:32:31,580 with persistent data. 1892 01:32:31,580 --> 01:32:34,030 So what we probably want to do is reintroduce CSVs 1893 01:32:34,030 --> 01:32:36,100 and we've played with those in C and in Python. 1894 01:32:36,100 --> 01:32:40,960 Could totally use CSVs, but we also now have SQL at our disposal. 1895 01:32:40,960 --> 01:32:43,820 And let me propose that we do this in SQL instead. 1896 01:32:43,820 --> 01:32:46,570 And for this, let me go ahead and open up a version of the program 1897 01:32:46,570 --> 01:32:47,797 that I wrote in advance. 1898 01:32:47,797 --> 01:32:49,630 So let me go ahead and close these templates 1899 01:32:49,630 --> 01:32:52,180 which will look very similar but a little different 1900 01:32:52,180 --> 01:32:54,160 from the ones I wrote in advance. 1901 01:32:54,160 --> 01:32:57,880 And let me go ahead and open up in today's-- 1902 01:32:57,880 --> 01:33:02,950 let me go into source nine, let me go into frosh IMs how about-- 1903 01:33:02,950 --> 01:33:05,800 version four, technically, in the versions online. 1904 01:33:05,800 --> 01:33:08,870 And let me go ahead and open up app.py as follows. 1905 01:33:08,870 --> 01:33:12,370 So here is an already made version that does just a little something different. 1906 01:33:12,370 --> 01:33:15,110 At the very top, I'm importing CS50 SQL library, 1907 01:33:15,110 --> 01:33:17,110 which you might recall we used a couple of weeks 1908 01:33:17,110 --> 01:33:19,930 pass just to write Python that talks to a SQL database. 1909 01:33:19,930 --> 01:33:22,660 And this feels like an opportune moment to bring that idea back. 1910 01:33:22,660 --> 01:33:25,330 Down here on line eight, I'm creating a DB variable 1911 01:33:25,330 --> 01:33:30,280 that opens up a file called frosh IMs.db using syntax that we've seen before. 1912 01:33:30,280 --> 01:33:33,758 I did create this frosh IMsdb file in advance of class 1913 01:33:33,758 --> 01:33:35,800 just so that we have a couple of columns in which 1914 01:33:35,800 --> 01:33:37,730 to store names and sports and such. 1915 01:33:37,730 --> 01:33:41,200 Here's that same global array a global list called sports, 1916 01:33:41,200 --> 01:33:44,470 and let's just see what's going on down below. 1917 01:33:44,470 --> 01:33:47,230 If I scroll down to index, this is the same 1918 01:33:47,230 --> 01:33:49,960 as before as we wrote together on the fly. 1919 01:33:49,960 --> 01:33:53,050 Let's skip de-register for a moment and go now into register. 1920 01:33:53,050 --> 01:33:55,888 So this one's a little different, but let's see what I've done. 1921 01:33:55,888 --> 01:33:58,430 I've got some comments in here because I wrote it in advance. 1922 01:33:58,430 --> 01:34:01,472 And I think this logic is pretty much the same, though I tightened it up. 1923 01:34:01,472 --> 01:34:05,770 And I'm asking two questions at once using on line 38, the or keyword here. 1924 01:34:05,770 --> 01:34:07,810 Just to say, if there's not a name, or the sport 1925 01:34:07,810 --> 01:34:10,540 is not in sports, that is what we'll call, now, a failure. 1926 01:34:10,540 --> 01:34:15,280 But what's fun now is that on line 42, I'm using the CS50 SQL 1927 01:34:15,280 --> 01:34:18,130 library to execute some actual SQL. 1928 01:34:18,130 --> 01:34:22,630 And I'm going to insert into a table called registrants two columns-- 1929 01:34:22,630 --> 01:34:23,620 name and sport. 1930 01:34:23,620 --> 01:34:24,970 What names and sport? 1931 01:34:24,970 --> 01:34:28,720 Well these two values with placeholders, plugging in name and sport. 1932 01:34:28,720 --> 01:34:30,220 Notice I'm using the question marks. 1933 01:34:30,220 --> 01:34:33,400 Absolutely necessary so we don't get one of those SQL injection 1934 01:34:33,400 --> 01:34:35,410 attacks because that too could be possible 1935 01:34:35,410 --> 01:34:38,380 if someone typed in some dangerous words or keywords like delete, 1936 01:34:38,380 --> 01:34:40,720 or single quotes, or semicolons in the form. 1937 01:34:40,720 --> 01:34:43,690 Here I'm letting the library sanitize the data. 1938 01:34:43,690 --> 01:34:45,730 And then this is a trick we haven't yet seen, 1939 01:34:45,730 --> 01:34:48,190 and it's really going to start tying things together. 1940 01:34:48,190 --> 01:34:52,960 I can also use a redirect function in Flask that has the effect of doing 1941 01:34:52,960 --> 01:34:56,710 the, if you will, safetyschool.org trick again, 1942 01:34:56,710 --> 01:35:01,630 whereby after the user registers, if I want to automatically show them now 1943 01:35:01,630 --> 01:35:04,217 everyone who is registered at /registrants, 1944 01:35:04,217 --> 01:35:07,300 I don't have to manually expect that they'll change the URL like I've been 1945 01:35:07,300 --> 01:35:08,680 doing for the past few minutes. 1946 01:35:08,680 --> 01:35:11,920 I can just redirect them anywhere I want on my app. 1947 01:35:11,920 --> 01:35:15,740 Or heck, I could redirect them to any URL on the internet using this function 1948 01:35:15,740 --> 01:35:16,240 call. 1949 01:35:16,240 --> 01:35:18,670 And it's just a nice way to send them to a different route 1950 01:35:18,670 --> 01:35:21,580 if you want them to see, in this case, those registrants. 1951 01:35:21,580 --> 01:35:22,630 So let me do this. 1952 01:35:22,630 --> 01:35:26,470 In the same directory, let me increase my terminal window size. 1953 01:35:26,470 --> 01:35:32,380 Let me do SQLite three of frosh IMs.db, and let me type .schema. 1954 01:35:32,380 --> 01:35:34,840 And you can indeed see it wraps onto two lines 1955 01:35:34,840 --> 01:35:38,600 here that each registrant has an ID-- 1956 01:35:38,600 --> 01:35:40,460 which will be automatically assigned 1, 2, 1957 01:35:40,460 --> 01:35:43,210 3, on up-- a name which is not null text, 1958 01:35:43,210 --> 01:35:45,025 and a sport which is also the same. 1959 01:35:45,025 --> 01:35:47,650 And the primary key is just going to be this unique identifier. 1960 01:35:47,650 --> 01:35:49,300 So that I made in advance. 1961 01:35:49,300 --> 01:35:52,990 But if I do select star from registrants semicolon, 1962 01:35:52,990 --> 01:35:56,140 there's no one currently registered for any sports. 1963 01:35:56,140 --> 01:35:58,250 But let's try now running this. 1964 01:35:58,250 --> 01:36:02,350 Let me go ahead and close my old version, which we wrote together. 1965 01:36:02,350 --> 01:36:03,550 And I'll close that tab. 1966 01:36:03,550 --> 01:36:07,630 Let me do Flask run in this version four here. 1967 01:36:07,630 --> 01:36:09,910 All right, I'm going to see some similar output. 1968 01:36:09,910 --> 01:36:11,530 I'm going to open the URL now. 1969 01:36:11,530 --> 01:36:14,230 And you'll see that I made a couple of changes before. 1970 01:36:14,230 --> 01:36:18,740 Instead of using a select menu, I used what are called radio buttons now, 1971 01:36:18,740 --> 01:36:20,740 which is a reference to old school radio buttons 1972 01:36:20,740 --> 01:36:23,112 that were mutually exclusive in cars back in the day. 1973 01:36:23,112 --> 01:36:24,320 And we'll see how to do this. 1974 01:36:24,320 --> 01:36:26,440 But it's just an alternative to a select menu. 1975 01:36:26,440 --> 01:36:30,200 And I'm going to go ahead and type in my name again here. 1976 01:36:30,200 --> 01:36:34,150 So I'll do David, I'll do soccer by selecting this radio button, 1977 01:36:34,150 --> 01:36:36,310 and I'm going to click Register now. 1978 01:36:36,310 --> 01:36:37,630 And notice what happened. 1979 01:36:37,630 --> 01:36:42,070 It's a little ugly the formatting, but so again was this 20 years ago. 1980 01:36:42,070 --> 01:36:47,470 Here I have now at the /registrants route, instead of an unordered list, 1981 01:36:47,470 --> 01:36:49,450 I'm just using a simple HTML table. 1982 01:36:49,450 --> 01:36:51,980 So I'll show you what this looks like in just a moment too. 1983 01:36:51,980 --> 01:36:53,960 And I'll show you this deregister button, 1984 01:36:53,960 --> 01:36:55,870 which is sort of unnecessarily large. 1985 01:36:55,870 --> 01:36:58,090 I also have functionality, we'll soon see, 1986 01:36:58,090 --> 01:37:01,370 for how you can unregister someone from a sport as well. 1987 01:37:01,370 --> 01:37:03,790 So take your name out of contention. 1988 01:37:03,790 --> 01:37:06,090 Well, let me go back to my terminal window here. 1989 01:37:06,090 --> 01:37:10,110 And I'm going to click the plus to give myself a second terminal so I can go 1990 01:37:10,110 --> 01:37:12,870 back into source nine frosh IMs four. 1991 01:37:12,870 --> 01:37:16,440 I'm going to do SQLite of frosh IMs.db. 1992 01:37:16,440 --> 01:37:19,830 I'm going to do select star from registrants now, 1993 01:37:19,830 --> 01:37:24,720 and now you'll see that indeed there's David registered for soccer. 1994 01:37:24,720 --> 01:37:29,670 And in fact, if I quit the Flask program with Control C and rerun it again, 1995 01:37:29,670 --> 01:37:32,820 no big deal because that next version of Flask 1996 01:37:32,820 --> 01:37:34,480 will just use the database as well. 1997 01:37:34,480 --> 01:37:37,740 So I'm persisting keeping the data in SQLite, 1998 01:37:37,740 --> 01:37:41,850 whereas I'm actually grabbing it using my Python code in Flask. 1999 01:37:41,850 --> 01:37:45,540 All right let's put one more person in here so we can delete one of us too. 2000 01:37:45,540 --> 01:37:49,823 Carter for basketball, register, and now we see both of us here. 2001 01:37:49,823 --> 01:37:51,490 All right, so let's see how we did this. 2002 01:37:51,490 --> 01:37:55,230 Let's go back over to VS Code, let me shrink down my terminal window. 2003 01:37:55,230 --> 01:37:58,470 Let me go into the-- 2004 01:37:58,470 --> 01:38:02,100 actually let's go into the templates directory, 2005 01:38:02,100 --> 01:38:05,880 and let's look at, for instance, index.html. 2006 01:38:05,880 --> 01:38:08,610 So previously we were using a select menu. 2007 01:38:08,610 --> 01:38:11,790 Turns out radio buttons use the input tag, 2008 01:38:11,790 --> 01:38:16,980 but instead of having an input of type=text, like for the human's name, 2009 01:38:16,980 --> 01:38:18,600 you have type=radio. 2010 01:38:18,600 --> 01:38:20,790 And so long as each of your radio buttons 2011 01:38:20,790 --> 01:38:23,190 has the same name, the same name, the same name, 2012 01:38:23,190 --> 01:38:25,210 that's what makes them mutually exclusive. 2013 01:38:25,210 --> 01:38:27,840 So checking one radio button turns off the others 2014 01:38:27,840 --> 01:38:29,370 because they have the same name. 2015 01:38:29,370 --> 01:38:31,980 The value I want to assign to each of these radio buttons 2016 01:38:31,980 --> 01:38:33,970 is just the sport placeholder. 2017 01:38:33,970 --> 01:38:35,720 This is what the human sees on the screen. 2018 01:38:35,720 --> 01:38:37,512 So it's almost the same as the Select menu, 2019 01:38:37,512 --> 01:38:39,180 it just looks aesthetically different. 2020 01:38:39,180 --> 01:38:40,530 But there's my same button. 2021 01:38:40,530 --> 01:38:42,450 So that's all the difference I made there. 2022 01:38:42,450 --> 01:38:46,350 And I added a heading tag, H1, just to say register to make clear what it is. 2023 01:38:46,350 --> 01:38:50,100 But let's take a look at another file. 2024 01:38:50,100 --> 01:38:54,930 This one now being, how about the /registrants route. 2025 01:38:54,930 --> 01:38:58,770 So if I open up registrants.HTML here now, 2026 01:38:58,770 --> 01:39:01,320 it's way more verbose than my unordered list. 2027 01:39:01,320 --> 01:39:03,180 But this is just kind of boring HTML. 2028 01:39:03,180 --> 01:39:07,410 Here's my table tag, table head, table row, table heading. 2029 01:39:07,410 --> 01:39:10,560 This makes things bold as the first row of the table. 2030 01:39:10,560 --> 01:39:12,290 Name, sport, are my two columns. 2031 01:39:12,290 --> 01:39:14,790 I've got a third empty column just so I can fit that button, 2032 01:39:14,790 --> 01:39:16,170 as we'll soon see again. 2033 01:39:16,170 --> 01:39:18,070 T body for table body. 2034 01:39:18,070 --> 01:39:21,180 Here's the same for loop trick again so that I can output 2035 01:39:21,180 --> 01:39:23,640 for every registrant a whole table row. 2036 01:39:23,640 --> 01:39:26,610 And there's this weird form in there, but we'll come back to that. 2037 01:39:26,610 --> 01:39:30,870 But there's the registrant's name, there's the registrant's sports. 2038 01:39:30,870 --> 01:39:34,140 But notice the slightly different syntax here. 2039 01:39:34,140 --> 01:39:37,410 Recall that CS50's select-- 2040 01:39:37,410 --> 01:39:42,060 CS50's execute function, when it returns to you a list of dictionaries, 2041 01:39:42,060 --> 01:39:46,000 you can then get at the individual columns by way of those keys. 2042 01:39:46,000 --> 01:39:48,060 So let's go to the /registrants route. 2043 01:39:48,060 --> 01:39:52,440 Let me go back to app.py, scroll down here, and it's actually super simple. 2044 01:39:52,440 --> 01:39:57,790 Here I have a /registrants route that first executes select star from 2045 01:39:57,790 --> 01:39:58,290 registrants. 2046 01:39:58,290 --> 01:39:59,550 So just old SQL stuff. 2047 01:39:59,550 --> 01:40:01,650 Give me every one from the registrants table, 2048 01:40:01,650 --> 01:40:04,650 let me then render the template called registrants.HTML 2049 01:40:04,650 --> 01:40:07,950 and just pass in this list of dictionaries. 2050 01:40:07,950 --> 01:40:10,200 And we haven't quite done this yet, but if you go back 2051 01:40:10,200 --> 01:40:16,300 to registrants.HTML, how do you iterate over each dictionary in that list? 2052 01:40:16,300 --> 01:40:19,230 Well the syntax is just for registrant and registrants. 2053 01:40:19,230 --> 01:40:24,570 That makes this a dictionary one at a time in the list, just like in Python. 2054 01:40:24,570 --> 01:40:28,590 So registrant.name and registrant.sport is just another syntax 2055 01:40:28,590 --> 01:40:31,560 for using the square bracket notation. 2056 01:40:31,560 --> 01:40:34,350 It's just a little cleaner and slightly more 2057 01:40:34,350 --> 01:40:37,170 succinct than having quotes and square brackets everywhere. 2058 01:40:37,170 --> 01:40:40,340 And then the rest of this is just HTML. 2059 01:40:40,340 --> 01:40:43,670 So what happens now if I want to-- 2060 01:40:43,670 --> 01:40:46,440 Carter been cut from the basketball team, if you will. 2061 01:40:46,440 --> 01:40:48,030 So how do we do that? 2062 01:40:48,030 --> 01:40:51,830 Well, we want to click this button, deregister, next to Carter's name. 2063 01:40:51,830 --> 01:40:53,330 But how does this work? 2064 01:40:53,330 --> 01:40:55,400 And think about now any website you visited 2065 01:40:55,400 --> 01:40:59,030 that has something like a shopping cart where you can remove things 2066 01:40:59,030 --> 01:41:02,780 from your cart, or update quantities, or add more quantities to your shopping 2067 01:41:02,780 --> 01:41:04,710 cart on Amazon or anything else. 2068 01:41:04,710 --> 01:41:08,450 Well, let's actually look at the HTML that my app has spit out. 2069 01:41:08,450 --> 01:41:10,700 Let's actually look at this here and we'll 2070 01:41:10,700 --> 01:41:15,050 see the following-- we'll see that we have here in the HTML 2071 01:41:15,050 --> 01:41:19,280 that reached the user, not only is David in the first column, soccer 2072 01:41:19,280 --> 01:41:23,810 and the second, notice that my registrants.HTML form is also spitting 2073 01:41:23,810 --> 01:41:26,660 out a tiny little web form of its own. 2074 01:41:26,660 --> 01:41:30,080 It's ugly but I only care about its functionality for now. 2075 01:41:30,080 --> 01:41:32,090 And notice what I'm doing here. 2076 01:41:32,090 --> 01:41:36,950 Every registrant in this database gets their very own deregister button. 2077 01:41:36,950 --> 01:41:40,220 And that form has a button that says deregister. 2078 01:41:40,220 --> 01:41:42,710 But notice what else each of those forms have. 2079 01:41:42,710 --> 01:41:46,130 There's no text box, there's no dropdown menu, there's no radio buttons. 2080 01:41:46,130 --> 01:41:51,300 Rather you have a hidden input field here. 2081 01:41:51,300 --> 01:41:56,330 So there is a way with HTML to have a form that will submit information, 2082 01:41:56,330 --> 01:42:00,320 but you don't have to give the user the ability to change that information. 2083 01:42:00,320 --> 01:42:04,400 You can just go ahead and tuck it inside of the form invisibly, if you will. 2084 01:42:04,400 --> 01:42:05,960 Hidden in fashion. 2085 01:42:05,960 --> 01:42:09,170 And so what's going to happen is if I click the deregister button 2086 01:42:09,170 --> 01:42:12,950 next to Carter, his primary key is two. 2087 01:42:12,950 --> 01:42:15,230 Mine is instead one. 2088 01:42:15,230 --> 01:42:18,380 So what's going to happen if I click his deregister button? 2089 01:42:18,380 --> 01:42:25,850 It submits a form with a ID parameter whose value is two, 2090 01:42:25,850 --> 01:42:28,010 and it submits it to the de-register route. 2091 01:42:28,010 --> 01:42:29,160 So what does that mean? 2092 01:42:29,160 --> 01:42:31,910 Well, if I go to VS Code and I go to app.py let's 2093 01:42:31,910 --> 01:42:35,390 look at the de-register root that I skipped over. 2094 01:42:35,390 --> 01:42:40,880 So if you access the deregister route via POST, this code gets called. 2095 01:42:40,880 --> 01:42:46,010 I grab from request.form the ID that was submitted in hidden fashion. 2096 01:42:46,010 --> 01:42:49,010 If there's indeed an ID, that is it's not blank, it's not zero, 2097 01:42:49,010 --> 01:42:51,650 it's an actual number like 1, 2, 3, or more, 2098 01:42:51,650 --> 01:42:57,440 I execute delete from registrants where ID = that value 2099 01:42:57,440 --> 01:42:58,880 with a question mark placeholder. 2100 01:42:58,880 --> 01:43:02,120 And then I redirect the user back to registrants. 2101 01:43:02,120 --> 01:43:05,600 Now if I go back to this form here, I click deregister, 2102 01:43:05,600 --> 01:43:07,250 we'll see that in action. 2103 01:43:07,250 --> 01:43:08,960 Gone is now Carter. 2104 01:43:08,960 --> 01:43:11,990 And in fact, if I go back to my terminal window here, 2105 01:43:11,990 --> 01:43:17,990 I open up SQLite three of frosh IMs.db and rerun select star from registrants, 2106 01:43:17,990 --> 01:43:20,010 Carter is now gone. 2107 01:43:20,010 --> 01:43:23,330 So again using very simple HTML forms, you 2108 01:43:23,330 --> 01:43:26,420 can get buttons, and links, and other such UI mechanisms 2109 01:43:26,420 --> 01:43:28,830 to do things on the server that you want. 2110 01:43:28,830 --> 01:43:30,590 But there is a danger here. 2111 01:43:30,590 --> 01:43:34,760 This now is really meant-- this example as an administrative website 2112 01:43:34,760 --> 01:43:39,710 like it was some 20 years ago just for us internal staff to be doing things. 2113 01:43:39,710 --> 01:43:44,820 Technically this is dangerous, what I've just done, too. 2114 01:43:44,820 --> 01:43:49,740 Even though Carter's ID is two and hidden, and mine is one and hidden, 2115 01:43:49,740 --> 01:43:52,170 what could this allow an adversary to do if they 2116 01:43:52,170 --> 01:43:53,970 had admin access to the same site? 2117 01:43:53,970 --> 01:43:57,470 2118 01:43:57,470 --> 01:43:58,175 Any thoughts? 2119 01:43:58,175 --> 01:44:01,775 2120 01:44:01,775 --> 01:44:02,275 Yeah. 2121 01:44:02,275 --> 01:44:04,140 AUDIENCE: Could they change the value and then deregister? 2122 01:44:04,140 --> 01:44:04,650 DAVID MALAN: Yeah. 2123 01:44:04,650 --> 01:44:06,817 They could change the value of that hidden attribute 2124 01:44:06,817 --> 01:44:10,200 by opening up Chrome's, developer tools, change the number in the HTML. 2125 01:44:10,200 --> 01:44:13,540 They could delete anyone, de-register anyone they want from the database. 2126 01:44:13,540 --> 01:44:16,980 Now in this case, I claim this is fine because this is only 2127 01:44:16,980 --> 01:44:19,620 meant for us staff who were running sports back in the day. 2128 01:44:19,620 --> 01:44:21,190 But it's indeed a risk. 2129 01:44:21,190 --> 01:44:23,250 So wouldn't it be nice if we could actually 2130 01:44:23,250 --> 01:44:26,850 ensure that only those users who are authorized 2131 01:44:26,850 --> 01:44:29,370 are allowed to execute certain actions? 2132 01:44:29,370 --> 01:44:32,130 I think for this capability we're actually 2133 01:44:32,130 --> 01:44:35,350 going to need to introduce something a bit more. 2134 01:44:35,350 --> 01:44:37,590 And so here, of course, is an opportunity 2135 01:44:37,590 --> 01:44:41,010 to talk briefly about, really, what you and I do all day long every day. 2136 01:44:41,010 --> 01:44:43,260 We log in to one or more websites or apps, 2137 01:44:43,260 --> 01:44:45,990 or at least until you're logged out automatically 2138 01:44:45,990 --> 01:44:47,260 and you have to do it again. 2139 01:44:47,260 --> 01:44:49,290 So here for instance, is a screenshot of Gmail. 2140 01:44:49,290 --> 01:44:51,957 When you type in your username, you type in your password, maybe 2141 01:44:51,957 --> 01:44:54,900 your two factor code that gets texted or sent to your phone, 2142 01:44:54,900 --> 01:44:55,980 then you're logged in. 2143 01:44:55,980 --> 01:44:58,830 And thankfully you're not prompted to log in again, typically, 2144 01:44:58,830 --> 01:45:02,880 for a number of hours, or days, or weeks, depending on the website. 2145 01:45:02,880 --> 01:45:04,860 Like Gmail keeps you logged in for ages. 2146 01:45:04,860 --> 01:45:08,700 Your bank probably logs you out within an hour or so for safety's sake. 2147 01:45:08,700 --> 01:45:11,220 So that is completely configurable on the server. 2148 01:45:11,220 --> 01:45:14,340 But how does Gmail know, how does Google know 2149 01:45:14,340 --> 01:45:17,130 that even as you're checking different mails again, and again, 2150 01:45:17,130 --> 01:45:20,940 and again, how do they know that you're still the same person who logged in? 2151 01:45:20,940 --> 01:45:24,600 Well it turns out that using these same building blocks as today-- 2152 01:45:24,600 --> 01:45:27,190 HTTP and HTML and more-- 2153 01:45:27,190 --> 01:45:30,660 you can actually implement the notion of a login feature 2154 01:45:30,660 --> 01:45:34,988 by doing the equivalent of something with something called cookies. 2155 01:45:34,988 --> 01:45:36,780 Essentially what happens when you first log 2156 01:45:36,780 --> 01:45:39,210 into a website for the very first time successfully 2157 01:45:39,210 --> 01:45:42,030 with your username and password, a cookie, so to speak, 2158 01:45:42,030 --> 01:45:43,260 is planted on your computer. 2159 01:45:43,260 --> 01:45:46,020 And metaphorically, this is kind of like taking a hand stamp, 2160 01:45:46,020 --> 01:45:48,240 and your hand is now stamped-- in this case, 2161 01:45:48,240 --> 01:45:51,030 a smiley face-- so that every other time you 2162 01:45:51,030 --> 01:45:53,580 click on a link on that same website-- google.com, 2163 01:45:53,580 --> 01:45:55,800 gmail.com, whatever-- unbeknownst to you, 2164 01:45:55,800 --> 01:45:58,710 your browser is constantly presenting that hand stamp. 2165 01:45:58,710 --> 01:46:01,368 Just like going into a club, or an amusement park, or something 2166 01:46:01,368 --> 01:46:03,660 like that where they don't want to check your ID again. 2167 01:46:03,660 --> 01:46:04,860 They don't want to check your ticket again, 2168 01:46:04,860 --> 01:46:07,440 they just want to quickly see the same hand stamp. 2169 01:46:07,440 --> 01:46:10,350 And so that is one of the things that a browser is always 2170 01:46:10,350 --> 01:46:12,000 doing for you once you're logged in. 2171 01:46:12,000 --> 01:46:16,350 Any cookies that have been planted, so to speak, in your Mac, or PC, or phone, 2172 01:46:16,350 --> 01:46:20,190 are constantly represented to the site every time you click a link 2173 01:46:20,190 --> 01:46:22,590 or make another request to that website. 2174 01:46:22,590 --> 01:46:26,100 And mechanically how this works, not just metaphorically in ink, 2175 01:46:26,100 --> 01:46:27,840 essentially this is what happens. 2176 01:46:27,840 --> 01:46:32,160 Here is an example of an HTTP request to something like Gmail. 2177 01:46:32,160 --> 01:46:34,560 And suppose, for instance, that you've logged in. 2178 01:46:34,560 --> 01:46:38,460 Typically, as of last week, we said that coming back from the server 2179 01:46:38,460 --> 01:46:42,780 would be another virtual envelope containing a 200 OK message, and then 2180 01:46:42,780 --> 01:46:46,440 the actual web page, or the picture of a cat, or whatever it may be. 2181 01:46:46,440 --> 01:46:50,250 But Google can also, if they verified that you have some username 2182 01:46:50,250 --> 01:46:52,500 and password correctly inputted, they can do 2183 01:46:52,500 --> 01:46:54,570 the equivalent of stamping your hand. 2184 01:46:54,570 --> 01:46:57,570 And the way they do this is they send an additional line 2185 01:46:57,570 --> 01:47:01,380 of text in that virtual envelope from the server to your browser, 2186 01:47:01,380 --> 01:47:04,860 literally using another HTTP header. 2187 01:47:04,860 --> 01:47:08,700 Not content type-- which just mundane tells you what kind of content 2188 01:47:08,700 --> 01:47:14,640 has come back-- they literally send an HTTP header called set-cookie. 2189 01:47:14,640 --> 01:47:18,540 And then they set a key value pair on your Mac or PC. 2190 01:47:18,540 --> 01:47:21,840 This is the technical equivalent of this smiley face hand stamp. 2191 01:47:21,840 --> 01:47:24,510 And what your computer is designed to do-- 2192 01:47:24,510 --> 01:47:27,990 because your computer and internet browser are supposed to implement 2193 01:47:27,990 --> 01:47:29,160 HTTP-- 2194 01:47:29,160 --> 01:47:32,745 any time you click another link on Gmail, or click on another mail, 2195 01:47:32,745 --> 01:47:36,690 or the like, your browser unbeknownst to you, presents that hand stamp. 2196 01:47:36,690 --> 01:47:39,600 And how it does it technically is in the envelope it 2197 01:47:39,600 --> 01:47:42,570 sends to Google from your browser, it doesn't 2198 01:47:42,570 --> 01:47:47,860 send set-cookie it just sends cookie: and the exact same thing. 2199 01:47:47,860 --> 01:47:51,540 And so long as Google is smart and they have a database or something 2200 01:47:51,540 --> 01:47:54,210 of all of the session values-- 2201 01:47:54,210 --> 01:47:58,800 session is the technical term for this maintenance of information across HTTP. 2202 01:47:58,800 --> 01:48:00,720 So long as Google has a big database that 2203 01:48:00,720 --> 01:48:05,010 knows that my cookie value is 1, 2, 3, and your cookie value is 4, 5, 6, 2204 01:48:05,010 --> 01:48:08,970 they can infer from this virtual hand stamp 2205 01:48:08,970 --> 01:48:11,190 whose emails they should be showing. 2206 01:48:11,190 --> 01:48:13,330 Mine or yours or the like. 2207 01:48:13,330 --> 01:48:14,980 So this is just scratching the surface. 2208 01:48:14,980 --> 01:48:19,620 But if I really want it to enable only Carter to deregister himself, 2209 01:48:19,620 --> 01:48:22,320 I just have to make sure that I log him in somehow-- 2210 01:48:22,320 --> 01:48:24,000 username, password, all of that. 2211 01:48:24,000 --> 01:48:27,390 I stamp his hand, or really, put a cookie on his computer. 2212 01:48:27,390 --> 01:48:30,720 And only if his cookie lines up with the user 2213 01:48:30,720 --> 01:48:36,100 ID he's trying to deregister should he be allowed to in fact do so. 2214 01:48:36,100 --> 01:48:37,930 So all of this is quite possible. 2215 01:48:37,930 --> 01:48:40,027 And indeed the technical term for this is session. 2216 01:48:40,027 --> 01:48:42,360 And what we thought we'd do in our remaining time today, 2217 01:48:42,360 --> 01:48:46,620 show you some examples of exactly how some of the most familiar web 2218 01:48:46,620 --> 01:48:49,020 functionality is implemented today, some of which 2219 01:48:49,020 --> 01:48:53,220 you'll use in your own problem set nine, which itself will be a web 2220 01:48:53,220 --> 01:48:55,330 app or perhaps even your final project. 2221 01:48:55,330 --> 01:48:57,010 So let me go ahead and do this. 2222 01:48:57,010 --> 01:49:00,930 Let me close my previous tabs and all things frosh IMs, and let's move 2223 01:49:00,930 --> 01:49:03,840 on to implementing some notion of login. 2224 01:49:03,840 --> 01:49:06,630 So in just a moment, I'll switch over here to VS Code, 2225 01:49:06,630 --> 01:49:10,620 and what I'm going to do is indeed in my source nine directory, 2226 01:49:10,620 --> 01:49:12,730 I'm going to go into a login directory. 2227 01:49:12,730 --> 01:49:15,630 And if I type ls here, you'll see app.py, 2228 01:49:15,630 --> 01:49:18,600 requirements.txt, which just refers to libraries I 2229 01:49:18,600 --> 01:49:21,887 want to automatically install, and a templates folder as well. 2230 01:49:21,887 --> 01:49:23,970 I'm going to go ahead and stop the previous server 2231 01:49:23,970 --> 01:49:25,860 and close that terminal window, and I'm going 2232 01:49:25,860 --> 01:49:28,440 to open up this version of app.py. 2233 01:49:28,440 --> 01:49:30,540 So there's a few new lines here. 2234 01:49:30,540 --> 01:49:33,030 And we'll give you these lines for problem set nine, 2235 01:49:33,030 --> 01:49:36,480 but I've got some of the familiar stuff up here, including this new redirect 2236 01:49:36,480 --> 01:49:37,590 function we just used. 2237 01:49:37,590 --> 01:49:41,130 And I have a session variable that comes with Flask too. 2238 01:49:41,130 --> 01:49:43,380 So what's nice again about Flask is that it deals 2239 01:49:43,380 --> 01:49:45,150 with all of this cookie stuff for you. 2240 01:49:45,150 --> 01:49:46,450 It sets the cookie. 2241 01:49:46,450 --> 01:49:47,520 It checks the cookie. 2242 01:49:47,520 --> 01:49:50,370 And what Flask does for you is it gives you 2243 01:49:50,370 --> 01:49:54,690 the abstraction of a variable called session so that anything 2244 01:49:54,690 --> 01:49:57,870 you put in the session variable, which itself is a dictionary, 2245 01:49:57,870 --> 01:50:00,210 will be there again, and again, and again 2246 01:50:00,210 --> 01:50:02,070 whenever that same user comes back. 2247 01:50:02,070 --> 01:50:04,590 A session is how you implement, essentially, 2248 01:50:04,590 --> 01:50:07,140 the proverbial shopping cart. 2249 01:50:07,140 --> 01:50:10,170 If I'm logged into Amazon, you're logged into Amazon, 2250 01:50:10,170 --> 01:50:13,590 Amazon knows which of us is which by way of that cookie. 2251 01:50:13,590 --> 01:50:17,460 And Amazon, if they're using Flask, provides the programmer 2252 01:50:17,460 --> 01:50:19,050 with a dictionary called session. 2253 01:50:19,050 --> 01:50:22,020 And flasks make sure that when Carter is visiting the site, 2254 01:50:22,020 --> 01:50:24,510 the code uses his session object. 2255 01:50:24,510 --> 01:50:27,660 When I'm visiting the site, it uses my session object. 2256 01:50:27,660 --> 01:50:29,760 But it's all implemented with those same cookies. 2257 01:50:29,760 --> 01:50:31,677 This is the same as before. 2258 01:50:31,677 --> 01:50:34,260 These lines are new, and you'll see these in problem set nine. 2259 01:50:34,260 --> 01:50:37,770 This is how we enable sessions in a web application. 2260 01:50:37,770 --> 01:50:39,690 And I'll just wave my hands at the detail. 2261 01:50:39,690 --> 01:50:41,940 There's different ways to implement sessions, 2262 01:50:41,940 --> 01:50:44,730 whether you use cookies on the server, cookies on the browser, 2263 01:50:44,730 --> 01:50:45,630 or other things. 2264 01:50:45,630 --> 01:50:49,440 These just ensure that we're storing the session information 2265 01:50:49,440 --> 01:50:52,090 the shopping cart on the server itself. 2266 01:50:52,090 --> 01:50:54,640 Now down here, let's go ahead and do this. 2267 01:50:54,640 --> 01:50:56,700 Let's go ahead and run Flask. 2268 01:50:56,700 --> 01:51:00,060 Run so I can see what this app does. 2269 01:51:00,060 --> 01:51:03,270 If I do this and visit the URL that gets outputted, 2270 01:51:03,270 --> 01:51:05,800 you'll see a very simple web page here. 2271 01:51:05,800 --> 01:51:07,620 And if I type in, for instance, my name-- 2272 01:51:07,620 --> 01:51:10,530 I'm not going to bother with a password-- and click Log In, 2273 01:51:10,530 --> 01:51:13,300 you'll see that you are logged in as David. 2274 01:51:13,300 --> 01:51:14,710 And now I can log out. 2275 01:51:14,710 --> 01:51:16,950 So I'm going to go ahead and click Log Out. 2276 01:51:16,950 --> 01:51:19,925 And now it seems to know that I'm not logged in again. 2277 01:51:19,925 --> 01:51:22,800 I can log in as Carter because I didn't bother implementing passwords 2278 01:51:22,800 --> 01:51:25,860 for simplicity, but now the site knows I'm logged in as Carter. 2279 01:51:25,860 --> 01:51:29,970 Better yet, if I reload, reload, reload, or click this button again, 2280 01:51:29,970 --> 01:51:34,920 and again, notice it still knows that I'm Carter until such time 2281 01:51:34,920 --> 01:51:36,510 as I log out. 2282 01:51:36,510 --> 01:51:38,070 All right, well how is this working? 2283 01:51:38,070 --> 01:51:40,410 Well let's go back to VS Code here and let 2284 01:51:40,410 --> 01:51:43,020 me scroll down to, first, this route. 2285 01:51:43,020 --> 01:51:45,780 This is a very common paradigm here whereby 2286 01:51:45,780 --> 01:51:48,000 I'm checking for the index route. 2287 01:51:48,000 --> 01:51:53,970 If there is not a name in the session, redirect the user to /login. 2288 01:51:53,970 --> 01:51:54,970 Now what does that mean? 2289 01:51:54,970 --> 01:51:57,280 Well, let me go back to VS Code here. 2290 01:51:57,280 --> 01:51:59,627 Let me go to the /route. 2291 01:51:59,627 --> 01:52:01,710 So again, your URL will be different, but I'm just 2292 01:52:01,710 --> 01:52:03,390 going to go to slash and hit Enter. 2293 01:52:03,390 --> 01:52:06,550 Notice that I got automatically redirected to log in. 2294 01:52:06,550 --> 01:52:07,862 And so many websites do this. 2295 01:52:07,862 --> 01:52:11,070 If you go to a website and you're not logged in, you're very often redirected 2296 01:52:11,070 --> 01:52:15,330 to /login, or /account, or something like that, where you're prompted. 2297 01:52:15,330 --> 01:52:17,980 The code for doing that is right here. 2298 01:52:17,980 --> 01:52:21,150 If there's no name in the session, if there's no name in the shopping cart, 2299 01:52:21,150 --> 01:52:25,560 if you will, go ahead and return the user to log in, that route. 2300 01:52:25,560 --> 01:52:29,843 Otherwise, , implicitly if they are logged in, show them index.html. 2301 01:52:29,843 --> 01:52:31,260 So let's go down that rabbit hole. 2302 01:52:31,260 --> 01:52:34,650 Let me open up in VS Code a second terminal window. 2303 01:52:34,650 --> 01:52:39,690 Let me go into source nine and go into this same login demonstration, 2304 01:52:39,690 --> 01:52:43,920 and let me open up the template called index.html. 2305 01:52:43,920 --> 01:52:45,360 And here's all this is. 2306 01:52:45,360 --> 01:52:47,350 There some layout, but who cares at this point, 2307 01:52:47,350 --> 01:52:49,680 it's just the boilerplate generic HTML. 2308 01:52:49,680 --> 01:52:51,300 Here is the body block. 2309 01:52:51,300 --> 01:52:52,350 I have this. 2310 01:52:52,350 --> 01:52:57,450 And this, too, is Jinja because of the curly brace and the sign. percent sign. 2311 01:52:57,450 --> 01:53:01,290 If there's a name in the session-- this is just Python syntax-- 2312 01:53:01,290 --> 01:53:02,700 then say this sentence. 2313 01:53:02,700 --> 01:53:03,990 You are logged in as-- 2314 01:53:03,990 --> 01:53:07,350 whatever name is in the session, in the shopping cart, if you will. 2315 01:53:07,350 --> 01:53:10,950 And then I just have this HTML link for logging the user out. 2316 01:53:10,950 --> 01:53:14,130 Else if there is no name in the session, logically, 2317 01:53:14,130 --> 01:53:15,570 just say you are not logged in. 2318 01:53:15,570 --> 01:53:18,490 And give them a manual link for logging in instead. 2319 01:53:18,490 --> 01:53:23,700 So that's all this particular template does, but how does the /login work? 2320 01:53:23,700 --> 01:53:27,450 Well let's go into this other template, code of login.HTML, 2321 01:53:27,450 --> 01:53:28,740 to which I'm redirected. 2322 01:53:28,740 --> 01:53:29,950 Super simple. 2323 01:53:29,950 --> 01:53:32,160 This is just copy paste from HTML before. 2324 01:53:32,160 --> 01:53:35,520 I've got a login form that's going to have an action of /login, 2325 01:53:35,520 --> 01:53:40,470 submits for privacy sake just by a POST, and then the rest of this is just 2326 01:53:40,470 --> 01:53:41,190 a simple form. 2327 01:53:41,190 --> 01:53:44,670 And I'm using an input type=submit instead of button=type=submit, 2328 01:53:44,670 --> 01:53:46,140 but same idea here too. 2329 01:53:46,140 --> 01:53:50,100 And if I go back to app.py, well let's see how login works. 2330 01:53:50,100 --> 01:53:50,700 All right. 2331 01:53:50,700 --> 01:53:54,060 It's a lot all at once, but they're relatively simple reapplications 2332 01:53:54,060 --> 01:53:55,180 of the same idea. 2333 01:53:55,180 --> 01:54:01,680 So if the user visits /login via GET or POST, call this function login. 2334 01:54:01,680 --> 01:54:05,550 If the user has submitted via POST, and we saw this technique before, 2335 01:54:05,550 --> 01:54:08,040 go ahead and do this on line 23. 2336 01:54:08,040 --> 01:54:14,580 Store in this special session variable that comes with Flask a name key, 2337 01:54:14,580 --> 01:54:17,890 and store in it the user's own name. 2338 01:54:17,890 --> 01:54:21,570 So, quote unquote, "name" will have a value of David, or Carter, or the like. 2339 01:54:21,570 --> 01:54:24,180 And as soon as you do that, redirect the user back 2340 01:54:24,180 --> 01:54:26,950 to slash just so they see the home page again. 2341 01:54:26,950 --> 01:54:29,730 And this is how Amazon and all these other websites work too. 2342 01:54:29,730 --> 01:54:33,120 Otherwise if they visit this page implicitly via GET, 2343 01:54:33,120 --> 01:54:36,408 and even though I didn't say = = GET anywhere, 2344 01:54:36,408 --> 01:54:39,450 that's the implication because if you can only get here by a GET or POST, 2345 01:54:39,450 --> 01:54:42,750 and we already handled POST, logically all that remains is GET. 2346 01:54:42,750 --> 01:54:45,960 Well then just show them the login screen instead. 2347 01:54:45,960 --> 01:54:49,500 But there's a half a dozen ways we could express that same logic. 2348 01:54:49,500 --> 01:54:52,360 And then for log out, this is kind of straightforward. 2349 01:54:52,360 --> 01:54:56,610 If the user clicks that logout link and ends up at /logout, this route, 2350 01:54:56,610 --> 01:55:02,070 well just change the value of that key in the session to be none. 2351 01:55:02,070 --> 01:55:03,600 Effectively, no, Carter is gone. 2352 01:55:03,600 --> 01:55:04,320 David's gone. 2353 01:55:04,320 --> 01:55:06,610 There's no one logged in. 2354 01:55:06,610 --> 01:55:09,600 So that is all that's required to actually implement 2355 01:55:09,600 --> 01:55:11,850 the notion of logging in and logging out of a website. 2356 01:55:11,850 --> 01:55:14,220 Plus the password thing, which should probably involve the database, 2357 01:55:14,220 --> 01:55:15,630 but one thing at a time. 2358 01:55:15,630 --> 01:55:19,050 And really, session is sort of like the code version of a shopping cart 2359 01:55:19,050 --> 01:55:23,198 whereby if I visit the same code, I get my own session object. 2360 01:55:23,198 --> 01:55:25,740 If Carter visits the website, he gets his own session object. 2361 01:55:25,740 --> 01:55:28,950 And the way Flask keeps us straight is they 2362 01:55:28,950 --> 01:55:32,490 put one cookie on my computer, a different cookie on his computer, 2363 01:55:32,490 --> 01:55:36,690 and uses those to line up with making sure the right session gets 2364 01:55:36,690 --> 01:55:40,120 shown to the right actual user. 2365 01:55:40,120 --> 01:55:43,740 Questions on this notion of sessions? 2366 01:55:43,740 --> 01:55:46,860 2367 01:55:46,860 --> 01:55:47,580 No? 2368 01:55:47,580 --> 01:55:51,270 All right, how about a couple of final examples just to tie this all together. 2369 01:55:51,270 --> 01:55:53,700 Let me go back into VS Code here. 2370 01:55:53,700 --> 01:55:56,490 Let me quit my previous version of Flask. 2371 01:55:56,490 --> 01:55:59,400 Let's go into source nine and go into store, 2372 01:55:59,400 --> 01:56:01,020 which is a separate app altogether. 2373 01:56:01,020 --> 01:56:03,660 And let's start by just running Flask to see what it does. 2374 01:56:03,660 --> 01:56:06,750 Let's hover over the URL and open it in another tab. 2375 01:56:06,750 --> 01:56:08,590 And this is pretty ugly too. 2376 01:56:08,590 --> 01:56:09,660 Let me Zoom in. 2377 01:56:09,660 --> 01:56:12,270 But it's a very simple bookstore. 2378 01:56:12,270 --> 01:56:15,670 Like an early amazon.com for each of these seven books here, 2379 01:56:15,670 --> 01:56:16,980 each of which seems to be-- 2380 01:56:16,980 --> 01:56:19,950 maybe this is H1, this is H2, H2, H2, H2. 2381 01:56:19,950 --> 01:56:22,410 And then there's a button underneath each. 2382 01:56:22,410 --> 01:56:25,590 Well now let's use this as an opportunity to kind of infer, 2383 01:56:25,590 --> 01:56:27,760 like for any website, how this thing works. 2384 01:56:27,760 --> 01:56:29,790 Let me go ahead and do view page source-- 2385 01:56:29,790 --> 01:56:32,620 and you can do this for any website on the internet. 2386 01:56:32,620 --> 01:56:36,660 Let's try to figure out how this bookstore adds things to a cart. 2387 01:56:36,660 --> 01:56:38,340 Well here's the H1 tag. 2388 01:56:38,340 --> 01:56:39,000 Uninteresting. 2389 01:56:39,000 --> 01:56:40,170 H2, H2, H2. 2390 01:56:40,170 --> 01:56:42,480 So the juicy part is in these forms. 2391 01:56:42,480 --> 01:56:46,255 Each of these forms has an action of /cart, 2392 01:56:46,255 --> 01:56:48,880 so that's the route that's going to be interesting in a moment. 2393 01:56:48,880 --> 01:56:51,330 And it uses POST for privacy's sake. 2394 01:56:51,330 --> 01:56:54,870 Each of these forms like the deregister feature for Carter, 2395 01:56:54,870 --> 01:57:00,000 has an ID attribute-- an ID parameter that's hidden, visually, 2396 01:57:00,000 --> 01:57:03,090 that has a value of 1, or 2, or 3. 2397 01:57:03,090 --> 01:57:07,360 So like the unique bar codes for the books, if you will. 2398 01:57:07,360 --> 01:57:09,100 But super small numbers, in our case. 2399 01:57:09,100 --> 01:57:10,980 And then each of these other forms just-- 2400 01:57:10,980 --> 01:57:13,260 each of these other books has an identical form 2401 01:57:13,260 --> 01:57:15,690 except for the value of this here. 2402 01:57:15,690 --> 01:57:18,060 Now in this case, this isn't such a big deal 2403 01:57:18,060 --> 01:57:22,650 that a user could technically hack the HTML of this bookstore, amazon.com, 2404 01:57:22,650 --> 01:57:25,860 and change the IDs because, whoa, what's the worst they're going to do? 2405 01:57:25,860 --> 01:57:29,280 Buy more books by adding more IDs to their shopping cart? 2406 01:57:29,280 --> 01:57:30,300 That's not a problem. 2407 01:57:30,300 --> 01:57:33,240 There's no prices here, it's just the unique ideas of books. 2408 01:57:33,240 --> 01:57:35,880 So whereas the deregister was maybe worrisome 2409 01:57:35,880 --> 01:57:38,040 because you're changing the server, I think 2410 01:57:38,040 --> 01:57:42,120 it's OK because the user can only at worst buy more books than they 2411 01:57:42,120 --> 01:57:43,960 might via the buttons alone. 2412 01:57:43,960 --> 01:57:45,840 So how does this now work? 2413 01:57:45,840 --> 01:57:49,260 Well let's go into VS Code again here. 2414 01:57:49,260 --> 01:57:51,120 Let me give myself another terminal window. 2415 01:57:51,120 --> 01:57:56,778 And in source nine/store let me open up app.py which is where all the logic is. 2416 01:57:56,778 --> 01:57:59,820 So I'll flip through most of this quickly because we've seen this before. 2417 01:57:59,820 --> 01:58:02,310 These imports are pretty much the same as before. 2418 01:58:02,310 --> 01:58:03,718 This line is the same. 2419 01:58:03,718 --> 01:58:05,760 This line is almost the same but the database now 2420 01:58:05,760 --> 01:58:09,630 is called store.db instead of frosh IMs.db. 2421 01:58:09,630 --> 01:58:12,720 This is the boilerplate code for just enabling sessions, 2422 01:58:12,720 --> 01:58:14,380 this notion of a shopping cart. 2423 01:58:14,380 --> 01:58:16,410 And so let's see how the index works. 2424 01:58:16,410 --> 01:58:18,780 How is it I'm seeing all seven books at once? 2425 01:58:18,780 --> 01:58:23,550 Well in this index function, I'm using on line 19, select star from books 2426 01:58:23,550 --> 01:58:25,230 to get all the books from the database. 2427 01:58:25,230 --> 01:58:28,920 And then I'm rendering a template called bookstore HTML passing in 2428 01:58:28,920 --> 01:58:30,868 as a placeholder all of those books. 2429 01:58:30,868 --> 01:58:33,160 All right, let's go down that rabbit hole for a second. 2430 01:58:33,160 --> 01:58:36,750 Let me open up books.HTML in my templates directory. 2431 01:58:36,750 --> 01:58:39,540 And here again, even though it's new today, 2432 01:58:39,540 --> 01:58:42,480 it's probably increasingly familiar syntactically. 2433 01:58:42,480 --> 01:58:44,100 Here's the H1. 2434 01:58:44,100 --> 01:58:45,490 Here is my loop. 2435 01:58:45,490 --> 01:58:49,840 Here's the H2, which is going to output the current book's title in that loop. 2436 01:58:49,840 --> 01:58:51,030 Here's the form. 2437 01:58:51,030 --> 01:58:54,100 Here's the ID of that book that's going to be outputted in the form. 2438 01:58:54,100 --> 01:58:59,260 So I didn't manually type out seven long forms, I just did one in this template 2439 01:58:59,260 --> 01:59:00,990 so that it gets generated automatically. 2440 01:59:00,990 --> 01:59:03,060 Literally what a website like Amazon would 2441 01:59:03,060 --> 01:59:08,220 do to show you 10 books at a time, or 10 search results or more at a time. 2442 01:59:08,220 --> 01:59:12,000 All right, well let's go to /cart, which was the juicy one. 2443 01:59:12,000 --> 01:59:15,430 And this one's longer, but let's see if we can reason through it. 2444 01:59:15,430 --> 01:59:20,790 If the user submits via GET or POST to /cart, well we first do this. 2445 01:59:20,790 --> 01:59:23,790 And this is just necessary and some boilerplate rewrote. 2446 01:59:23,790 --> 01:59:28,330 We're going to use the session object to store a variable called cart that 2447 01:59:28,330 --> 01:59:29,830 in this case, is going to be a list. 2448 01:59:29,830 --> 01:59:31,960 So session, again, is just a dictionary. 2449 01:59:31,960 --> 01:59:33,660 You can put anything in it you want. 2450 01:59:33,660 --> 01:59:36,450 Previously we put students' names and sports. 2451 01:59:36,450 --> 01:59:40,170 Now what I want to do is-- 2452 01:59:40,170 --> 01:59:45,720 sorry, previously we put the student's name, the user's name in it. 2453 01:59:45,720 --> 01:59:50,920 Now I'm going to actually store a cart key whose value is a list. 2454 01:59:50,920 --> 01:59:51,420 Why? 2455 01:59:51,420 --> 01:59:54,360 Because I want to aggregate more and more books in this list. 2456 01:59:54,360 --> 01:59:57,960 All right, so that just makes sure that I have at least an empty shopping cart 2457 01:59:57,960 --> 02:00:00,030 the very first time the user does this. 2458 02:00:00,030 --> 02:00:04,020 If they visit this form via POST, let's go ahead and get the ID of the book 2459 02:00:04,020 --> 02:00:05,040 that they posted. 2460 02:00:05,040 --> 02:00:08,880 If it is not empty, if there is a number, like 1, or 2, or 3, 2461 02:00:08,880 --> 02:00:11,590 let's go ahead and go into the shopping cart-- 2462 02:00:11,590 --> 02:00:14,040 which is a list, per this line-- 2463 02:00:14,040 --> 02:00:16,050 and just append that ID. 2464 02:00:16,050 --> 02:00:18,120 So this list of books in your shopping cart 2465 02:00:18,120 --> 02:00:23,220 is going to contain 1, 2, 4, 6, whatever books you're actually buying. 2466 02:00:23,220 --> 02:00:25,830 And then the user gets redirected to cart. 2467 02:00:25,830 --> 02:00:29,070 What if, though, the user got here via GET and not POST? 2468 02:00:29,070 --> 02:00:31,120 Well this one's relatively straightforward. 2469 02:00:31,120 --> 02:00:37,200 If you just visit /cart, we select star from books where ID is in-- 2470 02:00:37,200 --> 02:00:39,540 OK, so this is interesting-- 2471 02:00:39,540 --> 02:00:40,767 this list. 2472 02:00:40,767 --> 02:00:42,850 And this is syntax you might not have seen before. 2473 02:00:42,850 --> 02:00:46,160 But if you read the documentation for CS50's library, if you 2474 02:00:46,160 --> 02:00:49,670 select something and use a question mark placeholder, 2475 02:00:49,670 --> 02:00:55,520 and the placeholder itself is a list, we output a comma separated list of values 2476 02:00:55,520 --> 02:00:58,760 just like you would use maybe in problem sets seven 2477 02:00:58,760 --> 02:01:01,320 for doing SQL queries on your own. 2478 02:01:01,320 --> 02:01:04,970 So this just means show me only those books in my shopping cart. 2479 02:01:04,970 --> 02:01:07,610 Not Carter's, not someone else's, not in the whole database, 2480 02:01:07,610 --> 02:01:12,900 only show me the books in my shopping cart and then render it as such. 2481 02:01:12,900 --> 02:01:17,450 So we only saw what the catalog here looks like at /books. 2482 02:01:17,450 --> 02:01:22,230 Let's go ahead and add maybe the first book to my cart. 2483 02:01:22,230 --> 02:01:27,890 And now I see at /cart only that first book whose ID is one. 2484 02:01:27,890 --> 02:01:30,200 Let me now go back to the bookstore here, 2485 02:01:30,200 --> 02:01:33,510 scroll down to maybe the seventh book and add that to my cart. 2486 02:01:33,510 --> 02:01:36,200 And now I see this here too. 2487 02:01:36,200 --> 02:01:40,050 Meanwhile all of this information is stored in my session. 2488 02:01:40,050 --> 02:01:43,470 And so when I reload this cart again and again, 2489 02:01:43,470 --> 02:01:47,060 the reason I'm only seeing my two is because we're 2490 02:01:47,060 --> 02:01:49,160 checking only the list in my session. 2491 02:01:49,160 --> 02:01:52,760 And flasks make sure, again, that my session is different from your session, 2492 02:01:52,760 --> 02:01:55,410 is different from Carter session as well. 2493 02:01:55,410 --> 02:01:58,170 But you write the code once and it works for thousands, 2494 02:01:58,170 --> 02:02:01,850 millions of people in parallel. 2495 02:02:01,850 --> 02:02:04,105 Any questions on this? 2496 02:02:04,105 --> 02:02:06,840 2497 02:02:06,840 --> 02:02:07,770 Yes, in the back. 2498 02:02:07,770 --> 02:02:09,230 AUDIENCE: [INAUDIBLE] 2499 02:02:09,230 --> 02:02:10,897 DAVID MALAN: Sorry, say a little louder. 2500 02:02:10,897 --> 02:02:15,160 AUDIENCE: [INAUDIBLE] 2501 02:02:15,160 --> 02:02:16,780 DAVID MALAN: So to recap. 2502 02:02:16,780 --> 02:02:19,780 So users will never have the same session values. 2503 02:02:19,780 --> 02:02:21,613 Theoretically, the cookie that gets planted 2504 02:02:21,613 --> 02:02:23,530 does not look like a smiley face for everyone. 2505 02:02:23,530 --> 02:02:26,897 Each of us gets a big random number that's assigned to us. 2506 02:02:26,897 --> 02:02:29,230 So it'd be like each of us gets a completely unique hand 2507 02:02:29,230 --> 02:02:30,790 stamp that no one else can see. 2508 02:02:30,790 --> 02:02:34,720 The reason no one else can see it is because if the website's using HTTPs, 2509 02:02:34,720 --> 02:02:37,750 every time this hand stamp is shown, every time this cookie is sent back 2510 02:02:37,750 --> 02:02:40,130 and forth, it's all encrypted as well. 2511 02:02:40,130 --> 02:02:44,110 So each of us can-- even if we have the same contents by coincidence 2512 02:02:44,110 --> 02:02:46,930 because we like the same books, they will be separate cookies, 2513 02:02:46,930 --> 02:02:49,660 separate memory, separate sessions. 2514 02:02:49,660 --> 02:02:50,290 Behind you. 2515 02:02:50,290 --> 02:02:50,790 Yeah. 2516 02:02:50,790 --> 02:02:53,903 AUDIENCE: [INAUDIBLE] 2517 02:02:53,903 --> 02:02:55,320 DAVID MALAN: Really good question. 2518 02:02:55,320 --> 02:02:56,403 When does the session end? 2519 02:02:56,403 --> 02:02:57,540 Totally configurable. 2520 02:02:57,540 --> 02:03:01,230 Typically it ends when you close the tab or when you quit the browser. 2521 02:03:01,230 --> 02:03:05,340 Or you can also configure cookies to themselves be persistent for a day, 2522 02:03:05,340 --> 02:03:06,780 for a week, for a longer. 2523 02:03:06,780 --> 02:03:12,030 So for instance, when you log into say Gmail, 2524 02:03:12,030 --> 02:03:13,950 they plant a cookie on your computer probably 2525 02:03:13,950 --> 02:03:16,170 for a week, a month, a year, something like that 2526 02:03:16,170 --> 02:03:18,870 because it would be annoying and probably drive you to Outlook 2527 02:03:18,870 --> 02:03:21,930 or something else if you kept having to log into your account. 2528 02:03:21,930 --> 02:03:25,290 Whereas your bank account might actually wait for you to just close the tab. 2529 02:03:25,290 --> 02:03:27,510 And then for your own financial safety they just 2530 02:03:27,510 --> 02:03:29,490 automatically delete the session far sooner. 2531 02:03:29,490 --> 02:03:30,780 But totally configurable. 2532 02:03:30,780 --> 02:03:32,910 By default as I'm using it, it will typically 2533 02:03:32,910 --> 02:03:35,040 be thrown away when the browser itself quits. 2534 02:03:35,040 --> 02:03:39,600 And here, too, is another reason to develop websites using incognito mode 2535 02:03:39,600 --> 02:03:42,190 because if you want to just throw away all of your cookies, 2536 02:03:42,190 --> 02:03:43,920 you close the incognito window mode. 2537 02:03:43,920 --> 02:03:46,380 Open a new one and now you're starting from scratch. 2538 02:03:46,380 --> 02:03:48,850 You don't have to manually delete all your cookies, 2539 02:03:48,850 --> 02:03:51,955 which could log you out of websites you actually care about. 2540 02:03:51,955 --> 02:03:52,455 Yeah. 2541 02:03:52,455 --> 02:03:56,132 AUDIENCE: [INAUDIBLE] 2542 02:03:56,132 --> 02:03:57,340 DAVID MALAN: A good question. 2543 02:03:57,340 --> 02:03:59,710 When using sessions, if someone maliciously changes 2544 02:03:59,710 --> 02:04:02,020 the value of such forms, could it affect other people? 2545 02:04:02,020 --> 02:04:04,930 Theoretically, no because the worst you can do 2546 02:04:04,930 --> 02:04:07,928 is like add books to your own shopping cart that you don't want there. 2547 02:04:07,928 --> 02:04:09,970 So at that point, even though it's on the server, 2548 02:04:09,970 --> 02:04:12,640 it doesn't affect you, or Carter, or anyone else, 2549 02:04:12,640 --> 02:04:20,110 unless there is something more globally happening like registering for a sport, 2550 02:04:20,110 --> 02:04:22,240 or removing books from the Amazon database. 2551 02:04:22,240 --> 02:04:23,480 That would be problematic. 2552 02:04:23,480 --> 02:04:27,820 But in this case, we're removing things only from my own session 2553 02:04:27,820 --> 02:04:29,890 that the website is giving me. 2554 02:04:29,890 --> 02:04:33,350 All right, the last topic for today is this thing here, 2555 02:04:33,350 --> 02:04:35,440 which is sort of everywhere nowadays, these things 2556 02:04:35,440 --> 02:04:38,710 called APIs, or application programming interfaces. 2557 02:04:38,710 --> 02:04:40,630 And this is a very generic term, in fact. 2558 02:04:40,630 --> 02:04:44,980 Because any function you've used in C, in Scratch, in Python, 2559 02:04:44,980 --> 02:04:47,470 in SQL, are all APIs. 2560 02:04:47,470 --> 02:04:51,640 There is a standard way of interfacing with those functions. 2561 02:04:51,640 --> 02:04:52,730 They all have names. 2562 02:04:52,730 --> 02:04:54,190 They sometimes have return values. 2563 02:04:54,190 --> 02:04:55,660 They sometimes have arguments. 2564 02:04:55,660 --> 02:04:58,930 And an API is just how you use a function. 2565 02:04:58,930 --> 02:05:03,880 Or more generally an API just specifies how you interact with some service. 2566 02:05:03,880 --> 02:05:06,910 And so nowadays there's a lot of web based services 2567 02:05:06,910 --> 02:05:11,170 that you can use to get back data like the weather, or the current time, 2568 02:05:11,170 --> 02:05:13,750 or the database of Amazon books, for instance, 2569 02:05:13,750 --> 02:05:16,930 all might have APIs, often web based, that 2570 02:05:16,930 --> 02:05:19,600 allow you, using URLs or some other technology, 2571 02:05:19,600 --> 02:05:22,030 to just get data from someone else as though it's 2572 02:05:22,030 --> 02:05:23,980 a function you're calling remotely. 2573 02:05:23,980 --> 02:05:26,740 But HTTP is very often the mechanism that's 2574 02:05:26,740 --> 02:05:29,470 used to actually get data from servers. 2575 02:05:29,470 --> 02:05:32,450 And the way the data can come back can be as follows. 2576 02:05:32,450 --> 02:05:36,280 Let me end with one final example using some of our familiar shows 2577 02:05:36,280 --> 02:05:38,620 from weeks past. 2578 02:05:38,620 --> 02:05:42,700 Let me go ahead and close the old Flask version, go back into source nine 2579 02:05:42,700 --> 02:05:44,020 and go into-- 2580 02:05:44,020 --> 02:05:47,800 how about an example called shows. 2581 02:05:47,800 --> 02:05:50,200 And the first version of this, zero, I'm just going 2582 02:05:50,200 --> 02:05:52,240 to go ahead and run with Flask run. 2583 02:05:52,240 --> 02:05:54,700 I'll hover over my URL and open it here. 2584 02:05:54,700 --> 02:05:58,810 And you'll see now that I have a very simple form, as we keep doing today. 2585 02:05:58,810 --> 02:06:02,140 I'm going to type in like O-F-F-I-C-E, office, 2586 02:06:02,140 --> 02:06:04,300 into this search box and click Search. 2587 02:06:04,300 --> 02:06:11,560 And you'll see now that I ended up at a URL ending in /search?q=office. 2588 02:06:11,560 --> 02:06:15,820 So this is like my own baby version of google.com but I implemented it myself. 2589 02:06:15,820 --> 02:06:20,440 And for any title of a TV show from a couple of weeks past that matches 2590 02:06:20,440 --> 02:06:25,090 O-F-F-I-C-E, I spit it out into an unordered list. 2591 02:06:25,090 --> 02:06:26,287 How is this working? 2592 02:06:26,287 --> 02:06:28,120 You can maybe imagine, even if you might not 2593 02:06:28,120 --> 02:06:31,540 be able to program this off the top of your head, certainly, so soon-- 2594 02:06:31,540 --> 02:06:33,310 let me go into source nine. 2595 02:06:33,310 --> 02:06:38,680 Let me go into show zero, let me open up app.py. 2596 02:06:38,680 --> 02:06:41,080 And in this file, you'll see that I'm grabbing 2597 02:06:41,080 --> 02:06:45,310 a file called shows.db, which is like a simpler version of the one 2598 02:06:45,310 --> 02:06:47,110 from a couple of weeks passed. 2599 02:06:47,110 --> 02:06:48,910 Here is why I see the web form. 2600 02:06:48,910 --> 02:06:51,260 My first route, my index is super simple. 2601 02:06:51,260 --> 02:06:52,540 It just spits out that form. 2602 02:06:52,540 --> 02:06:56,230 And my search route, you can think of this as google.com, 2603 02:06:56,230 --> 02:06:58,100 is only like four lines of code. 2604 02:06:58,100 --> 02:07:03,190 So if the user sends data to /search, this function called search is called. 2605 02:07:03,190 --> 02:07:06,070 I declare a variable called shows, I execute 2606 02:07:06,070 --> 02:07:11,770 a SQL command that is select star from shows where title like question mark. 2607 02:07:11,770 --> 02:07:14,260 And the syntax here is a little crazy, but I 2608 02:07:14,260 --> 02:07:17,860 want to prefix to the user's input percent sign, 2609 02:07:17,860 --> 02:07:20,800 and suffix it with a percent sign as well, 2610 02:07:20,800 --> 02:07:25,240 putting in between those two values the actual input, why? 2611 02:07:25,240 --> 02:07:27,970 In SQL what does it mean if you have a percent sign to the left 2612 02:07:27,970 --> 02:07:28,930 and to the right? 2613 02:07:28,930 --> 02:07:30,460 Nothing to do with Jinja today. 2614 02:07:30,460 --> 02:07:31,450 AUDIENCE: [INAUDIBLE] 2615 02:07:31,450 --> 02:07:33,030 DAVID MALAN: Yeah, it's a wild card. 2616 02:07:33,030 --> 02:07:35,910 So it means match zero or more characters on the left, 2617 02:07:35,910 --> 02:07:38,400 or match zero or more characters on the right, 2618 02:07:38,400 --> 02:07:42,810 you have to do the concatenation as the second argument to this function. 2619 02:07:42,810 --> 02:07:46,200 You can't do something clever like put it here around the question mark, 2620 02:07:46,200 --> 02:07:49,500 the question mark is the placeholder that you plug these values into. 2621 02:07:49,500 --> 02:07:54,000 But this just means, hey SQL, show me all of the titles that have O-F-F-I-C-E 2622 02:07:54,000 --> 02:07:55,230 somewhere in them. 2623 02:07:55,230 --> 02:07:57,930 That gives me back a list of dictionaries. 2624 02:07:57,930 --> 02:08:02,460 I pass that in as a placeholder for a variable called shows, 2625 02:08:02,460 --> 02:08:05,010 and if we look at search.HTML, let's look at that. 2626 02:08:05,010 --> 02:08:07,830 In my templates directory there's something called search.HTML. 2627 02:08:07,830 --> 02:08:12,730 Super simple, I mean this is like the essence of google.com search results. 2628 02:08:12,730 --> 02:08:15,150 I'm using an unordered list to keep things simple, 2629 02:08:15,150 --> 02:08:18,570 but I integrate over every show in the show's list that came back, 2630 02:08:18,570 --> 02:08:21,257 and I output an li with each of those shows' titles. 2631 02:08:21,257 --> 02:08:21,840 And that's it. 2632 02:08:21,840 --> 02:08:24,960 Now Google has blue links, and little previews, and other text, 2633 02:08:24,960 --> 02:08:26,820 the first sentence or so from each page. 2634 02:08:26,820 --> 02:08:28,380 But that's the idea. 2635 02:08:28,380 --> 02:08:33,450 This is really similar in spirit to what google.com/search does for you. 2636 02:08:33,450 --> 02:08:37,150 Now how is this working there's no app.py involved here yet. 2637 02:08:37,150 --> 02:08:39,540 This is just very basic HTTP. 2638 02:08:39,540 --> 02:08:42,930 I submit the form, I go to another route, and I get back the results. 2639 02:08:42,930 --> 02:08:44,280 But check out this version. 2640 02:08:44,280 --> 02:08:48,450 Let me close these tabs here and open my first terminal window. 2641 02:08:48,450 --> 02:08:52,590 Let me go into shows one from today's source nine directory 2642 02:08:52,590 --> 02:08:54,480 and do Flask run this time. 2643 02:08:54,480 --> 02:08:57,360 Let me go ahead and hover over that URL and open it here. 2644 02:08:57,360 --> 02:08:59,520 And gone now is the Submit button. 2645 02:08:59,520 --> 02:09:04,050 Now I'm going to make a user interface that uses a technique called AJAX-- 2646 02:09:04,050 --> 02:09:08,730 for Asynchronous, JavaScript, and XML, which is somewhat of a dated term 2647 02:09:08,730 --> 02:09:11,010 because we're not using something called XML anymore. 2648 02:09:11,010 --> 02:09:15,990 But AJAX is a technique whereby you don't have to submit forms anymore 2649 02:09:15,990 --> 02:09:17,830 to get more data from the server. 2650 02:09:17,830 --> 02:09:22,650 You can use JavaScript, per last week, listen for an event like the key press 2651 02:09:22,650 --> 02:09:26,130 coming down or up, and as soon as you hear such an event, 2652 02:09:26,130 --> 02:09:30,360 you can secretly in JavaScript code send a request to the server to get back 2653 02:09:30,360 --> 02:09:34,170 more data, and then plug it into the Dom-- the tree-- 2654 02:09:34,170 --> 02:09:35,560 in the computer's memory. 2655 02:09:35,560 --> 02:09:37,800 And this just makes for more seamless experiences 2656 02:09:37,800 --> 02:09:39,790 like autocomplete on any website. 2657 02:09:39,790 --> 02:09:42,330 So now let me try typing O-- 2658 02:09:42,330 --> 02:09:44,170 we got autocomplete super fast. 2659 02:09:44,170 --> 02:09:51,255 F-F-I-C-E. And you'll see every time I add more keys to my input, 2660 02:09:51,255 --> 02:09:53,630 I'm doing another search, another search, another search, 2661 02:09:53,630 --> 02:09:55,310 and the data is changing. 2662 02:09:55,310 --> 02:09:56,510 Now how is this working? 2663 02:09:56,510 --> 02:09:58,200 Well let me go back to VS Code here. 2664 02:09:58,200 --> 02:10:02,570 And in my other terminal window, let me open up app.py. 2665 02:10:02,570 --> 02:10:05,930 And in app.py, you'll see that there's still 2666 02:10:05,930 --> 02:10:13,050 a search route down below that returns a search template, but watch this. 2667 02:10:13,050 --> 02:10:20,420 Let me go into templates/search.HTML and notice here that we're indeed getting 2668 02:10:20,420 --> 02:10:26,790 back an unordered list of shows again, and again, and again. 2669 02:10:26,790 --> 02:10:30,710 And this HTML that's coming back-- 2670 02:10:30,710 --> 02:10:32,750 let me go here. 2671 02:10:32,750 --> 02:10:34,430 Let me open my terminal-- oh, sorry. 2672 02:10:34,430 --> 02:10:36,320 This is the wrong version. 2673 02:10:36,320 --> 02:10:37,790 Sorry, I was in the wrong folder. 2674 02:10:37,790 --> 02:10:39,140 Let's fix this. 2675 02:10:39,140 --> 02:10:42,800 In shows one, code of app.py, it's almost the same thing. 2676 02:10:42,800 --> 02:10:45,770 In search here-- 2677 02:10:45,770 --> 02:10:47,385 OK, well I change this slightly. 2678 02:10:47,385 --> 02:10:49,010 Let me show you this version of search. 2679 02:10:49,010 --> 02:10:52,130 If I open up app.py, here's my search route. 2680 02:10:52,130 --> 02:10:56,540 I'm getting a variable called q, giving it the value of whatever request.args 2681 02:10:56,540 --> 02:10:59,190 has from the user, like q=office. 2682 02:10:59,190 --> 02:11:01,190 And then I'm checking if the user actually typed 2683 02:11:01,190 --> 02:11:03,260 something in execute this SQL query. 2684 02:11:03,260 --> 02:11:06,557 Select star from shows where title is like that using the same. 2685 02:11:06,557 --> 02:11:08,390 And this time just to keep things efficient, 2686 02:11:08,390 --> 02:11:12,110 I limited the total results to 50 instead of an infinite number. 2687 02:11:12,110 --> 02:11:16,280 Otherwise if the user type nothing, just to be super safe here, 2688 02:11:16,280 --> 02:11:18,080 I'm setting shows equal to an empty list. 2689 02:11:18,080 --> 02:11:20,330 So if you don't type anything there's nothing to show. 2690 02:11:20,330 --> 02:11:24,478 And no matter what, I render this template called search.HTML. 2691 02:11:24,478 --> 02:11:25,520 Well, let's look at that. 2692 02:11:25,520 --> 02:11:30,920 If I open up templates/search.HTML, this time there's no layout. 2693 02:11:30,920 --> 02:11:34,010 There's no inheritance of that layout .HTML, 2694 02:11:34,010 --> 02:11:38,270 I am literally generating just a whole bunch of li fragments. 2695 02:11:38,270 --> 02:11:39,052 Why? 2696 02:11:39,052 --> 02:11:41,010 Well let's see what's happening in the browser. 2697 02:11:41,010 --> 02:11:42,890 And this is the beginning of an API. 2698 02:11:42,890 --> 02:11:46,730 If I wanted to make this API available-- this application programming 2699 02:11:46,730 --> 02:11:47,270 interface-- 2700 02:11:47,270 --> 02:11:51,950 I could tell the world that if you want to search for TV shows in my database, 2701 02:11:51,950 --> 02:12:00,770 go to URL, that's something, something, /search?q=office or cat, or dog, 2702 02:12:00,770 --> 02:12:01,610 or anything else. 2703 02:12:01,610 --> 02:12:03,740 And what I will return to you is this. 2704 02:12:03,740 --> 02:12:07,250 Enter-- I will just give you a whole bunch of li tags, which 2705 02:12:07,250 --> 02:12:08,210 almost looks the same. 2706 02:12:08,210 --> 02:12:10,070 But let me view the page source. 2707 02:12:10,070 --> 02:12:13,520 Only am I going to hand you back a fragment of HTML. 2708 02:12:13,520 --> 02:12:16,700 I'm not giving you an HTML tag, a body tag, a title tag, a head tag. 2709 02:12:16,700 --> 02:12:18,110 I'm not giving you a web page. 2710 02:12:18,110 --> 02:12:22,250 I'm giving you a fragment of HTML that you can now do whatever you want, 2711 02:12:22,250 --> 02:12:26,850 including insert this into your own unordered list. 2712 02:12:26,850 --> 02:12:29,870 So notice what happens in this actual app. 2713 02:12:29,870 --> 02:12:34,910 If I go back to VS Code here, let me open up my index template here, 2714 02:12:34,910 --> 02:12:37,850 and you'll see some JavaScript magic. 2715 02:12:37,850 --> 02:12:43,100 So in JavaScript here, in my form that only had the textbox and no button, 2716 02:12:43,100 --> 02:12:44,360 what am I doing? 2717 02:12:44,360 --> 02:12:48,680 In a script tag here, I am creating a variable called input. 2718 02:12:48,680 --> 02:12:51,860 And I'm using this function called query selector that 2719 02:12:51,860 --> 02:12:56,670 just gets me a reference to the input text box on the form. 2720 02:12:56,670 --> 02:12:58,160 So I can see what the human typed. 2721 02:12:58,160 --> 02:13:00,320 This is a little different today, but I'm 2722 02:13:00,320 --> 02:13:05,420 using input.addEventListener, which is a way in JavaScript to tell it, just 2723 02:13:05,420 --> 02:13:08,150 like in Scratch, listen for something to happen, 2724 02:13:08,150 --> 02:13:09,620 like the green flag being clicked. 2725 02:13:09,620 --> 02:13:13,370 But in this case listen for an event that involves input. 2726 02:13:13,370 --> 02:13:16,070 That is like typing on the keyboard, whether it's 2727 02:13:16,070 --> 02:13:19,520 by a copy paste, manual input, or anything else. 2728 02:13:19,520 --> 02:13:22,370 Then whenever that happens, call this function. 2729 02:13:22,370 --> 02:13:24,170 And async stands for Asynchronous. 2730 02:13:24,170 --> 02:13:27,710 This is a term of art which means that this function might 2731 02:13:27,710 --> 02:13:30,720 take a split second, maybe even a second or two to execute. 2732 02:13:30,720 --> 02:13:33,740 So it's going to do it behind the scenes, like in the background, 2733 02:13:33,740 --> 02:13:34,520 so to speak. 2734 02:13:34,520 --> 02:13:36,300 And what is it going to do? 2735 02:13:36,300 --> 02:13:39,650 Well, it's going to call a JavaScript function that all browsers now 2736 02:13:39,650 --> 02:13:43,760 support called fetch, which is a function that uses HTTP to go 2737 02:13:43,760 --> 02:13:46,010 fetch more data via from the server. 2738 02:13:46,010 --> 02:13:51,380 It's going to fetch data from a route called /search?q= and whatever 2739 02:13:51,380 --> 02:13:53,760 the value is that the user typed in. 2740 02:13:53,760 --> 02:13:56,630 So I'm just manually creating my own mini URL 2741 02:13:56,630 --> 02:13:59,240 and telling JavaScript go fetch me that HTML. 2742 02:13:59,240 --> 02:14:04,015 When it comes back via this line of text here called response.text, 2743 02:14:04,015 --> 02:14:05,390 and let me wave my hand at await. 2744 02:14:05,390 --> 02:14:07,820 Await just means this might not come back immediately. 2745 02:14:07,820 --> 02:14:09,990 Let's await the response and when it does come in, 2746 02:14:09,990 --> 02:14:11,450 then let's execute this code. 2747 02:14:11,450 --> 02:14:12,810 I'm going to do this. 2748 02:14:12,810 --> 02:14:17,572 I'm going to search the document, the whole web page, for this UL tag 2749 02:14:17,572 --> 02:14:20,030 which is somewhere in this page that we'll see in a moment. 2750 02:14:20,030 --> 02:14:24,236 Change its inner HTML to be that fragment of li, 2751 02:14:24,236 --> 02:14:26,780 li, li, of all of those matching shows. 2752 02:14:26,780 --> 02:14:28,190 And where does this all go? 2753 02:14:28,190 --> 02:14:30,920 Well if we scroll up here, you'll notice that there's 2754 02:14:30,920 --> 02:14:33,000 my usual HTML up at the top. 2755 02:14:33,000 --> 02:14:35,360 Head tag, body tag, and all of that. 2756 02:14:35,360 --> 02:14:38,240 There's the text box that we've talked about already. 2757 02:14:38,240 --> 02:14:41,810 There's no button for submitting because it all happens automatically. 2758 02:14:41,810 --> 02:14:45,840 But there is by default this empty UL that has nothing by default 2759 02:14:45,840 --> 02:14:48,750 until we start using that API. 2760 02:14:48,750 --> 02:14:51,270 And the final flourish here this. 2761 02:14:51,270 --> 02:14:56,670 This is kind of an ugly, sloppy way to get data from a server 2762 02:14:56,670 --> 02:14:58,890 to just get back a fragment of HTML. 2763 02:14:58,890 --> 02:15:00,570 Like what if I'm not using HTML? 2764 02:15:00,570 --> 02:15:04,890 I want to store these TV shows in a PDF, or in some other web tag, 2765 02:15:04,890 --> 02:15:06,660 in a table, or something like that. 2766 02:15:06,660 --> 02:15:08,460 It doesn't really make sense for the server 2767 02:15:08,460 --> 02:15:12,480 to be presuming that I want like tags surrounding each of my data. 2768 02:15:12,480 --> 02:15:15,570 Better would be to get a more generic format back. 2769 02:15:15,570 --> 02:15:18,450 And that format is almost always nowadays called 2770 02:15:18,450 --> 02:15:20,310 this, our final acronym-- 2771 02:15:20,310 --> 02:15:23,310 JSON, JavaScript Object Notation. 2772 02:15:23,310 --> 02:15:24,430 And let me do this. 2773 02:15:24,430 --> 02:15:28,830 Let me close these two tabs here and open my terminal window, 2774 02:15:28,830 --> 02:15:33,510 and cancel the previous version of Flask that was running. 2775 02:15:33,510 --> 02:15:36,300 Let me close this version and look at our final version called 2776 02:15:36,300 --> 02:15:39,430 shows two and do Flask run. 2777 02:15:39,430 --> 02:15:42,510 I'm going to hover over that URL and open it in a browser. 2778 02:15:42,510 --> 02:15:47,010 And I'm going to manually visit, after zooming in, let's do again 2779 02:15:47,010 --> 02:15:52,980 /search?q=office Enter. 2780 02:15:52,980 --> 02:15:55,470 And this is what JSON looks like. 2781 02:15:55,470 --> 02:15:58,050 Now at a glance, this does not seem like an improvement. 2782 02:15:58,050 --> 02:16:00,730 This looks crazy that it's just this big blob of text. 2783 02:16:00,730 --> 02:16:02,730 But it's just enough text for the computer 2784 02:16:02,730 --> 02:16:04,980 to be able to process it reliably. 2785 02:16:04,980 --> 02:16:07,935 Notice that there's a square bracket here. 2786 02:16:07,935 --> 02:16:09,810 And if I actually scroll to the bottom, there 2787 02:16:09,810 --> 02:16:12,210 would be a closed square bracket like way down there. 2788 02:16:12,210 --> 02:16:16,920 Inside of that square bracket is a curly brace, then ID, colon, 2789 02:16:16,920 --> 02:16:18,130 and then a number. 2790 02:16:18,130 --> 02:16:21,480 Then a title, quote unquote, colon, and then the title. 2791 02:16:21,480 --> 02:16:23,470 And then the closed curly brace. 2792 02:16:23,470 --> 02:16:26,040 So what you're seeing in JavaScript Object Notation 2793 02:16:26,040 --> 02:16:28,380 is a very standard super popular format that's 2794 02:16:28,380 --> 02:16:32,549 just text that still uses square brackets for lists, a.k.a. arrays. 2795 02:16:32,549 --> 02:16:36,459 That still uses curly braces for dictionaries, key value pairs. 2796 02:16:36,459 --> 02:16:39,240 So what you see here is a massive list-- up to 50, 2797 02:16:39,240 --> 02:16:43,559 I think-- shows that came back from this API, each of which 2798 02:16:43,559 --> 02:16:47,830 has a dictionary, if you will, an object of key value pairs. 2799 02:16:47,830 --> 02:16:49,110 What keys and values? 2800 02:16:49,110 --> 02:16:53,590 An ID key and a title key, each of which has a value respectively. 2801 02:16:53,590 --> 02:16:56,280 And this is the same data from IMDb, some of which 2802 02:16:56,280 --> 02:16:58,290 you might be recalling visually. 2803 02:16:58,290 --> 02:17:01,097 This is just a very raw, computer friendly way 2804 02:17:01,097 --> 02:17:03,930 of returning a whole bunch of data that we humans don't need to see. 2805 02:17:03,930 --> 02:17:08,549 But I can use this data by going back into VS code. 2806 02:17:08,549 --> 02:17:14,190 Let me open another terminal window and go into source nine/shows2. 2807 02:17:14,190 --> 02:17:21,660 And in here, let me go ahead and open up, how about templates index.html, 2808 02:17:21,660 --> 02:17:26,055 which previously just use that inner HTML trick. 2809 02:17:26,055 --> 02:17:27,930 And this is not going to impress-- you're not 2810 02:17:27,930 --> 02:17:29,472 going to be pleased with this syntax. 2811 02:17:29,472 --> 02:17:32,309 But let me just at least explain what we're doing. 2812 02:17:32,309 --> 02:17:35,070 It turns out that JSON is just the better 2813 02:17:35,070 --> 02:17:39,360 way in general, the more generic, multipurpose, user agnostic, language 2814 02:17:39,360 --> 02:17:42,738 agnostic way of returning data from a server because it's just text. 2815 02:17:42,738 --> 02:17:45,780 So it doesn't matter if you're using Python, or C, or C++, or JavaScript, 2816 02:17:45,780 --> 02:17:47,760 or Ruby, or PHP, or something else. 2817 02:17:47,760 --> 02:17:51,490 All of those languages can process JSON information. 2818 02:17:51,490 --> 02:17:54,270 And indeed here is some JavaScript that does just that. 2819 02:17:54,270 --> 02:17:56,250 Same code is before initially. 2820 02:17:56,250 --> 02:18:00,209 I declare a variable called input that gives me access to the user's text box. 2821 02:18:00,209 --> 02:18:04,150 I listen for input like keystrokes going up and down. 2822 02:18:04,150 --> 02:18:07,770 And when they happen, I call this anonymous function. 2823 02:18:07,770 --> 02:18:11,370 I fetch data from the server using the exact same code as before. 2824 02:18:11,370 --> 02:18:15,639 Search?q=office, or anything else. 2825 02:18:15,639 --> 02:18:19,080 And then this is just now new code that I 2826 02:18:19,080 --> 02:18:23,610 use to convert that JSON data into my own HTML format, 2827 02:18:23,610 --> 02:18:27,570 be it an unordered list, and ordered list, a table, or anything else. 2828 02:18:27,570 --> 02:18:28,719 What am I doing? 2829 02:18:28,719 --> 02:18:31,200 I've got a variable called HTML initialize to nothing. 2830 02:18:31,200 --> 02:18:33,420 So I've got no HTML initially. 2831 02:18:33,420 --> 02:18:37,209 I then iterate over every ID in those shows. 2832 02:18:37,209 --> 02:18:39,360 So every one of IMDb's unique identifier, 2833 02:18:39,360 --> 02:18:41,309 I integrate over them one at a time. 2834 02:18:41,309 --> 02:18:47,070 And then I go into the show at its ID location and I grab its title. 2835 02:18:47,070 --> 02:18:52,840 And this is-- forget this for just a moment. 2836 02:18:52,840 --> 02:18:56,549 I then take this HTML variable, concatenate, 2837 02:18:56,549 --> 02:19:03,270 or join onto it, my own li tag, plus the title, plus the close li tag. 2838 02:19:03,270 --> 02:19:05,370 And I skip this because it got scary pretty fast, 2839 02:19:05,370 --> 02:19:09,570 but it turns out that if some TV shows have actually angled brackets in them, 2840 02:19:09,570 --> 02:19:12,299 that could break my HTML entirely. 2841 02:19:12,299 --> 02:19:15,209 So it turns out, you might recall super briefly last week 2842 02:19:15,209 --> 02:19:18,240 we had the copyright symbol, using an HTML entity, 2843 02:19:18,240 --> 02:19:20,129 using the ampersand, and the hash symbol, 2844 02:19:20,129 --> 02:19:23,160 and 169 semicolon-- it turns out there are 2845 02:19:23,160 --> 02:19:27,600 other such cryptic sequences of characters that represent otherwise 2846 02:19:27,600 --> 02:19:29,730 dangerous or untypable characters. 2847 02:19:29,730 --> 02:19:32,580 Like this, which could confuse the computer into thinking 2848 02:19:32,580 --> 02:19:34,695 it's at the beginning of a tag, and an ampersand, 2849 02:19:34,695 --> 02:19:38,850 which could similarly trick the computer into thinking that it's an entity which 2850 02:19:38,850 --> 02:19:39,370 it isn't. 2851 02:19:39,370 --> 02:19:42,120 But long story short, there are libraries, thankfully, 2852 02:19:42,120 --> 02:19:43,590 that handle much of this for you. 2853 02:19:43,590 --> 02:19:48,450 For our purposes, the takeaway is that now that you understand a bit of HTTP, 2854 02:19:48,450 --> 02:19:52,050 now that you understand a bit of HTML, CSS, and JavaScript, all of which 2855 02:19:52,050 --> 02:19:54,480 have their roles, you can use them ultimately 2856 02:19:54,480 --> 02:19:57,180 to start assembling your own web applications as you will 2857 02:19:57,180 --> 02:20:00,780 for problem set nine, stitching together all of those languages 2858 02:20:00,780 --> 02:20:04,140 and building full fledged web applications, mobile applications, 2859 02:20:04,140 --> 02:20:05,680 or anything more. 2860 02:20:05,680 --> 02:20:08,430 And for that, I think we are all set. 2861 02:20:08,430 --> 02:20:11,950 And the first one up here can have these cookies as well. 2862 02:20:11,950 --> 02:20:14,280 We'll see you next time for our very last CS50 lecture. 2863 02:20:14,280 --> 02:20:16,730 [MUSIC PLAYING] 2864 02:20:16,730 --> 02:20:53,000