Using Filters and Request Attributes8:25 with Craig Dennis
Filters come in handy when you want to process all requests a certain way, to avoid duplicating that code in each of your controllers. Request attributes in Spark allow you to share data on a single request as it flows through your site, allowing each filter and controller to access its properties.
You might have felt the want to start including the same code in 0:00 each of your route methods here. 0:04 Now like we talked about, 0:05 we really want to know the username before the idea's page is able to be accessed. 0:06 So a common way to do this is by applying what is known as HTTP middleware. 0:12 What this allows you to do is this. 0:17 A request comes in, and the framework first looks for 0:20 any handler that should run before the request is processed. 0:23 This handler has access to request and response, and 0:27 it can add or change things, including stopping the request altogether. 0:31 [SOUND] If things are to continue, 0:35 the request is handled using the proper methods. 0:37 Finally, any matching after-methods are run. 0:40 Now this pattern is pretty powerful for 0:43 things like authentication, like logging into a site with a username or a password. 0:46 If you wanna make sure that proper access is granted for 0:52 a specific section, you simply need to make a before-handler that checks that 0:54 the request is coming from someone that is logged in, or authenticated. 0:59 Otherwise, you handle things. 1:03 In Spark, this HTTP middleware concept is handled with something called filters. 1:05 There's one for before and another for after. 1:11 Why don't we make sure that visiting the ideas page requires a known user name, and 1:15 if not, let's redirect them. 1:19 Okay, so let's add a filter for before the /ideas page renders. 1:22 In Spark, that is just using the Spark static method called before. 1:28 So we'll put that up there. 1:33 So we'll say before, and it was right. 1:34 We want a static import that method, Spark.before. 1:42 And the first optional parameter here, is the URI that you wanna catch. 1:46 So this also takes wild card matching, but 1:51 we wanna catch specifically this ideas page, right? 1:54 And then it takes a filter object and 1:58 it's very similar to the single abstract method that our routes are using. 2:02 So it takes a request and a response. 2:06 And we can, of course, represent that as a lambda. 2:09 What we wanna do is we wanna check and see if the username is in the cookies, so 2:13 if it's not, null. 2:17 So let's go ahead and we'll say if 2:18 (req.cookie("username") != null) 2:23 then what we want to do is we wanna redirect, right? 2:29 We wanna redirect to the home page. 2:37 So we'll say res.redirect. 2:39 And now, since we've already dealt with this response, 2:45 we don't need to do any other processing. 2:48 So, let's stop the request from hitting one of the other routes. 2:50 So, we can do this by calling the static halt method, and nothing more will happen. 2:55 So, we just say halt. 2:59 When that redirect happens, that's gonna be a little jarring. 3:02 So, I think we should probably tell them a message, right? 3:04 Let's add a to do about that. 3:07 Let's add a to do. 3:09 We'll say, // TODO. 3:12 Send message about, whoops. 3:21 Send message about redirect...somehow. 3:26 We don't have any messaging in place, do we? 3:31 We should fix that. 3:32 I don't know what's going on with the indentation. 3:35 Let's fix that, there we go. 3:38 Okay, so let's double check that that's working, right? 3:39 So we will restart the server, flip over to our page. 3:42 There are no cookies. 3:47 So if I go to the /ideas, this before filter should catch it and redirect us. 3:49 It did it, let's take a look at why. 3:53 I said not equal to null. 4:01 If it is equal to null, okay. 4:03 So if it doesn't exist, we wanna flip them over there. 4:07 Common mistake, I'm gonna keep that in there, enjoy. 4:10 All right, no cookies, let's go to the ideas, I restarted the server. 4:14 See now it flipped to Welcome Students instead of, what's your idea. 4:20 So it's working, but we really should show a message, right? 4:25 We should say like, you need to log in before you can see the ideas page, 4:28 something like that. 4:31 Okay, so we already added a to do about that. 4:33 Let's see what other to do's are out there, ooh! 4:35 TODO, this username is tied to the cookie implementation. 4:38 Maybe we can take care of that. 4:42 I mean, that's one of the powers of middleware, right? 4:44 We can abstract away parts of this flow. 4:46 So let's do that, let's go take look at where that's at. 4:49 One thing that we can do, is we can manipulate the request object and 4:52 we can add data to it, so that other filters and routes can access it. 4:56 So, let's remove this dependence on our cookie implementation and 5:00 we'll keep it in our middleware. 5:03 We'll keep it secret in our middleware, just using filters. 5:05 So, let's do that. 5:07 We'll come up here. 5:08 Now, the way that before filters work is it's the way that they're added. 5:10 So, we want it before this one. 5:14 Before this before, that's a lot of beforing. 5:17 All right, if we don't put a path, what that means is this is gonna happen for 5:20 every single request response. 5:23 Every single request. 5:26 So, here we'll check and see if the cookie exists. 5:29 Now we'll use my inverted logic that I did before. 5:33 If it exists, what we're going to do is we're going to add 5:39 an attribute to the request, so the rest of the request can use it. 5:44 So those, on Spark, are called attributes. 5:49 So we're gonna say, req.attribute, and we're gonna set username. 5:51 And we're gonna pull that right off of the cookie. 6:00 Now it's okay that it knows about it here, right? 6:02 Because we could write any one of these filters for later, okay? 6:05 So that should do it. 6:09 And now any place after this request where we're doing this, 6:10 if we wanna find any time that we talk about cookie. 6:15 Right, every time I talk about a request cookie, 6:18 let's replace that now with request attribute. 6:21 So, req.attribute, 6:23 that was a Cmd+R opened this up. 6:27 So let's go ahead and let's do Replace. 6:32 And it's gonna flip through each one. 6:34 We wanna replace that one, and we wanna replace that one. 6:35 So now, any time we talk about request cookie, 6:39 it's only up in the top area. 6:46 Every other time, it's looking for request.attribute. 6:49 So, there we go. 6:52 The cookie implementation, at least on the read side, has been removed. 6:53 Now as long as we set the attribute username, anything can do this, right? 6:56 Any kind of middleware, we could do facial recognition or voice recognition, 7:00 anything. 7:04 As long as it sets the username attribute, the username will be used in present. 7:05 Pretty cool, right? 7:09 So we definitely can remove this to do. 7:11 And I guess, before we get too brave, 7:18 we should make sure that our changes are working, right? 7:21 Cuz we don't have tests. 7:25 So I'm gonna restart this. 7:26 And I'm gonna try to go, there are no cookies, 7:29 I'm gonna try to go to the ideas page. 7:31 And I can't, but if I do put in my ID, a cookie comes across, 7:34 but it's using the request attribute. 7:39 So I want, really want a course on Spark testing. 7:42 Things are looking good. 7:46 HTTP middleware is definitely powerful and 7:49 allows you to abstract away the implementation of fairly difficult things. 7:51 I'm glad you got some hands on experience with it. 7:56 When you feel yourself duplicating code and 7:58 routes, consider leaning on them as a solution. 8:01 I really enjoy Spark's simple approach to the problem space of being 8:05 able to modify requests and responses. 8:08 You'll find similar solutions in other frameworks. 8:11 But this is so nice and succinct, and 8:14 really, in my opinion, what makes these micro frameworks like Spark shine. 8:16 Okay, now we can gather awesome ideas from students, 8:20 let's allow you all to vote on them. 8:23
You need to sign up for Treehouse in order to download course files.Sign up