1 00:00:00,740 --> 00:00:04,190 You might have felt the want to start including the same code in 2 00:00:04,190 --> 00:00:05,750 each of your route methods here. 3 00:00:05,750 --> 00:00:06,750 Now like we talked about, 4 00:00:06,750 --> 00:00:12,160 we really want to know the username before the idea's page is able to be accessed. 5 00:00:12,160 --> 00:00:17,130 So a common way to do this is by applying what is known as HTTP middleware. 6 00:00:17,130 --> 00:00:20,050 What this allows you to do is this. 7 00:00:20,050 --> 00:00:23,010 A request comes in, and the framework first looks for 8 00:00:23,010 --> 00:00:27,060 any handler that should run before the request is processed. 9 00:00:27,060 --> 00:00:31,330 This handler has access to request and response, and 10 00:00:31,330 --> 00:00:35,895 it can add or change things, including stopping the request altogether. 11 00:00:35,895 --> 00:00:37,764 [SOUND] If things are to continue, 12 00:00:37,764 --> 00:00:40,584 the request is handled using the proper methods. 13 00:00:40,584 --> 00:00:43,720 Finally, any matching after-methods are run. 14 00:00:43,720 --> 00:00:46,830 Now this pattern is pretty powerful for 15 00:00:46,830 --> 00:00:52,260 things like authentication, like logging into a site with a username or a password. 16 00:00:52,260 --> 00:00:54,950 If you wanna make sure that proper access is granted for 17 00:00:54,950 --> 00:00:59,580 a specific section, you simply need to make a before-handler that checks that 18 00:00:59,580 --> 00:01:03,620 the request is coming from someone that is logged in, or authenticated. 19 00:01:03,620 --> 00:01:05,870 Otherwise, you handle things. 20 00:01:05,870 --> 00:01:11,520 In Spark, this HTTP middleware concept is handled with something called filters. 21 00:01:11,520 --> 00:01:14,260 There's one for before and another for after. 22 00:01:15,400 --> 00:01:19,940 Why don't we make sure that visiting the ideas page requires a known user name, and 23 00:01:19,940 --> 00:01:21,600 if not, let's redirect them. 24 00:01:22,910 --> 00:01:28,970 Okay, so let's add a filter for before the /ideas page renders. 25 00:01:28,970 --> 00:01:33,660 In Spark, that is just using the Spark static method called before. 26 00:01:33,660 --> 00:01:34,540 So we'll put that up there. 27 00:01:34,540 --> 00:01:42,010 So we'll say before, and it was right. 28 00:01:42,010 --> 00:01:46,300 We want a static import that method, Spark.before. 29 00:01:46,300 --> 00:01:51,222 And the first optional parameter here, is the URI that you wanna catch. 30 00:01:51,222 --> 00:01:54,452 So this also takes wild card matching, but 31 00:01:54,452 --> 00:01:58,624 we wanna catch specifically this ideas page, right? 32 00:01:58,624 --> 00:02:02,630 And then it takes a filter object and 33 00:02:02,630 --> 00:02:06,960 it's very similar to the single abstract method that our routes are using. 34 00:02:06,960 --> 00:02:09,472 So it takes a request and a response. 35 00:02:09,472 --> 00:02:13,160 And we can, of course, represent that as a lambda. 36 00:02:13,160 --> 00:02:17,524 What we wanna do is we wanna check and see if the username is in the cookies, so 37 00:02:17,524 --> 00:02:18,766 if it's not, null. 38 00:02:18,766 --> 00:02:23,551 So let's go ahead and we'll say if 39 00:02:23,551 --> 00:02:29,989 (req.cookie("username") != null) 40 00:02:29,989 --> 00:02:37,260 then what we want to do is we wanna redirect, right? 41 00:02:37,260 --> 00:02:39,130 We wanna redirect to the home page. 42 00:02:39,130 --> 00:02:41,848 So we'll say res.redirect. 43 00:02:45,931 --> 00:02:48,116 And now, since we've already dealt with this response, 44 00:02:48,116 --> 00:02:50,080 we don't need to do any other processing. 45 00:02:50,080 --> 00:02:55,160 So, let's stop the request from hitting one of the other routes. 46 00:02:55,160 --> 00:02:59,880 So, we can do this by calling the static halt method, and nothing more will happen. 47 00:02:59,880 --> 00:03:01,160 So, we just say halt. 48 00:03:02,320 --> 00:03:04,510 When that redirect happens, that's gonna be a little jarring. 49 00:03:04,510 --> 00:03:07,970 So, I think we should probably tell them a message, right? 50 00:03:07,970 --> 00:03:09,260 Let's add a to do about that. 51 00:03:09,260 --> 00:03:12,230 Let's add a to do. 52 00:03:12,230 --> 00:03:17,612 We'll say, // TODO. 53 00:03:21,009 --> 00:03:26,061 Send message about, whoops. 54 00:03:26,061 --> 00:03:31,140 Send message about redirect...somehow. 55 00:03:31,140 --> 00:03:32,459 We don't have any messaging in place, do we? 56 00:03:32,459 --> 00:03:35,870 We should fix that. 57 00:03:35,870 --> 00:03:38,070 I don't know what's going on with the indentation. 58 00:03:38,070 --> 00:03:39,690 Let's fix that, there we go. 59 00:03:39,690 --> 00:03:42,870 Okay, so let's double check that that's working, right? 60 00:03:42,870 --> 00:03:47,800 So we will restart the server, flip over to our page. 61 00:03:47,800 --> 00:03:49,400 There are no cookies. 62 00:03:49,400 --> 00:03:53,828 So if I go to the /ideas, this before filter should catch it and redirect us. 63 00:03:53,828 --> 00:03:57,480 It did it, let's take a look at why. 64 00:04:01,270 --> 00:04:03,120 I said not equal to null. 65 00:04:03,120 --> 00:04:04,770 If it is equal to null, okay. 66 00:04:07,150 --> 00:04:10,740 So if it doesn't exist, we wanna flip them over there. 67 00:04:10,740 --> 00:04:14,080 Common mistake, I'm gonna keep that in there, enjoy. 68 00:04:14,080 --> 00:04:18,090 All right, no cookies, let's go to the ideas, I restarted the server. 69 00:04:20,810 --> 00:04:23,490 See now it flipped to Welcome Students instead of, what's your idea. 70 00:04:25,310 --> 00:04:28,563 So it's working, but we really should show a message, right? 71 00:04:28,563 --> 00:04:31,203 We should say like, you need to log in before you can see the ideas page, 72 00:04:31,203 --> 00:04:32,050 something like that. 73 00:04:33,120 --> 00:04:35,540 Okay, so we already added a to do about that. 74 00:04:35,540 --> 00:04:38,430 Let's see what other to do's are out there, ooh! 75 00:04:38,430 --> 00:04:41,000 TODO, this username is tied to the cookie implementation. 76 00:04:42,930 --> 00:04:44,250 Maybe we can take care of that. 77 00:04:44,250 --> 00:04:46,480 I mean, that's one of the powers of middleware, right? 78 00:04:46,480 --> 00:04:49,050 We can abstract away parts of this flow. 79 00:04:49,050 --> 00:04:51,140 So let's do that, let's go take look at where that's at. 80 00:04:52,370 --> 00:04:56,360 One thing that we can do, is we can manipulate the request object and 81 00:04:56,360 --> 00:05:00,450 we can add data to it, so that other filters and routes can access it. 82 00:05:00,450 --> 00:05:03,950 So, let's remove this dependence on our cookie implementation and 83 00:05:03,950 --> 00:05:05,270 we'll keep it in our middleware. 84 00:05:05,270 --> 00:05:07,900 We'll keep it secret in our middleware, just using filters. 85 00:05:07,900 --> 00:05:08,970 So, let's do that. 86 00:05:08,970 --> 00:05:10,220 We'll come up here. 87 00:05:10,220 --> 00:05:14,370 Now, the way that before filters work is it's the way that they're added. 88 00:05:14,370 --> 00:05:15,880 So, we want it before this one. 89 00:05:17,220 --> 00:05:20,172 Before this before, that's a lot of beforing. 90 00:05:20,172 --> 00:05:23,890 All right, if we don't put a path, what that means is this is gonna happen for 91 00:05:23,890 --> 00:05:26,620 every single request response. 92 00:05:26,620 --> 00:05:27,400 Every single request. 93 00:05:29,540 --> 00:05:33,740 So, here we'll check and see if the cookie exists. 94 00:05:33,740 --> 00:05:36,540 Now we'll use my inverted logic that I did before. 95 00:05:39,440 --> 00:05:44,610 If it exists, what we're going to do is we're going to add 96 00:05:44,610 --> 00:05:49,210 an attribute to the request, so the rest of the request can use it. 97 00:05:49,210 --> 00:05:51,760 So those, on Spark, are called attributes. 98 00:05:51,760 --> 00:05:57,495 So we're gonna say, req.attribute, and we're gonna set username. 99 00:06:00,460 --> 00:06:02,040 And we're gonna pull that right off of the cookie. 100 00:06:02,040 --> 00:06:05,352 Now it's okay that it knows about it here, right? 101 00:06:05,352 --> 00:06:09,131 Because we could write any one of these filters for later, okay? 102 00:06:09,131 --> 00:06:10,970 So that should do it. 103 00:06:10,970 --> 00:06:15,020 And now any place after this request where we're doing this, 104 00:06:15,020 --> 00:06:18,800 if we wanna find any time that we talk about cookie. 105 00:06:18,800 --> 00:06:21,460 Right, every time I talk about a request cookie, 106 00:06:21,460 --> 00:06:23,510 let's replace that now with request attribute. 107 00:06:23,510 --> 00:06:27,122 So, req.attribute, 108 00:06:27,122 --> 00:06:32,181 that was a Cmd+R opened this up. 109 00:06:32,181 --> 00:06:34,602 So let's go ahead and let's do Replace. 110 00:06:34,602 --> 00:06:35,520 And it's gonna flip through each one. 111 00:06:35,520 --> 00:06:37,820 We wanna replace that one, and we wanna replace that one. 112 00:06:39,770 --> 00:06:44,910 So now, any time we talk about request cookie, 113 00:06:46,260 --> 00:06:49,190 it's only up in the top area. 114 00:06:49,190 --> 00:06:52,500 Every other time, it's looking for request.attribute. 115 00:06:52,500 --> 00:06:53,600 So, there we go. 116 00:06:53,600 --> 00:06:56,930 The cookie implementation, at least on the read side, has been removed. 117 00:06:56,930 --> 00:07:00,880 Now as long as we set the attribute username, anything can do this, right? 118 00:07:00,880 --> 00:07:04,309 Any kind of middleware, we could do facial recognition or voice recognition, 119 00:07:04,309 --> 00:07:05,230 anything. 120 00:07:05,230 --> 00:07:09,800 As long as it sets the username attribute, the username will be used in present. 121 00:07:09,800 --> 00:07:10,390 Pretty cool, right? 122 00:07:11,450 --> 00:07:18,381 So we definitely can remove this to do. 123 00:07:18,381 --> 00:07:21,056 And I guess, before we get too brave, 124 00:07:21,056 --> 00:07:25,165 we should make sure that our changes are working, right? 125 00:07:25,165 --> 00:07:26,530 Cuz we don't have tests. 126 00:07:26,530 --> 00:07:27,810 So I'm gonna restart this. 127 00:07:29,770 --> 00:07:31,770 And I'm gonna try to go, there are no cookies, 128 00:07:31,770 --> 00:07:33,380 I'm gonna try to go to the ideas page. 129 00:07:34,650 --> 00:07:39,640 And I can't, but if I do put in my ID, a cookie comes across, 130 00:07:39,640 --> 00:07:42,390 but it's using the request attribute. 131 00:07:42,390 --> 00:07:46,970 So I want, really want a course on Spark testing. 132 00:07:46,970 --> 00:07:48,120 Things are looking good. 133 00:07:49,360 --> 00:07:51,790 HTTP middleware is definitely powerful and 134 00:07:51,790 --> 00:07:56,390 allows you to abstract away the implementation of fairly difficult things. 135 00:07:56,390 --> 00:07:58,950 I'm glad you got some hands on experience with it. 136 00:07:58,950 --> 00:08:01,310 When you feel yourself duplicating code and 137 00:08:01,310 --> 00:08:03,780 routes, consider leaning on them as a solution. 138 00:08:05,050 --> 00:08:08,470 I really enjoy Spark's simple approach to the problem space of being 139 00:08:08,470 --> 00:08:11,520 able to modify requests and responses. 140 00:08:11,520 --> 00:08:14,160 You'll find similar solutions in other frameworks. 141 00:08:14,160 --> 00:08:16,210 But this is so nice and succinct, and 142 00:08:16,210 --> 00:08:20,440 really, in my opinion, what makes these micro frameworks like Spark shine. 143 00:08:20,440 --> 00:08:23,580 Okay, now we can gather awesome ideas from students, 144 00:08:23,580 --> 00:08:24,730 let's allow you all to vote on them.