1 00:00:01,210 --> 00:00:03,330 In this lecture we're gonna implement something 2 00:00:03,330 --> 00:00:08,020 called CORS, which means cross-origin resource sharing. 3 00:00:08,020 --> 00:00:11,670 And this is a fundamental feature in any API, 4 00:00:11,670 --> 00:00:13,400 but I can only show you this now 5 00:00:13,400 --> 00:00:16,183 that the application is actually already deployed. 6 00:00:17,900 --> 00:00:21,610 Now what actually is cross-origin resource sharing, 7 00:00:21,610 --> 00:00:24,170 and why do we need to implement it? 8 00:00:24,170 --> 00:00:26,610 Well let's say we have our API 9 00:00:26,610 --> 00:00:31,610 here at natours-jonas.herokuapp.com/api/v1, 10 00:00:34,570 --> 00:00:36,180 and so on and so forth. 11 00:00:36,180 --> 00:00:40,393 And then some other website, for example at example.com, 12 00:00:41,860 --> 00:00:44,380 is trying to access our API. 13 00:00:44,380 --> 00:00:48,470 So basically trying to call this URL here. 14 00:00:48,470 --> 00:00:51,730 And this is then called a cross-origin request, 15 00:00:51,730 --> 00:00:54,940 because herokuapp.com is a different domain 16 00:00:54,940 --> 00:00:58,550 than example.com, and so therefore if example.com 17 00:00:58,550 --> 00:01:01,570 is trying to access herokuapp.com, 18 00:01:01,570 --> 00:01:05,520 it will be a cross-origin request, all right? 19 00:01:05,520 --> 00:01:09,160 Now usually cross-origin requests are not allowed, 20 00:01:09,160 --> 00:01:13,290 and will by default fail, unless we implement CORS, 21 00:01:13,290 --> 00:01:16,660 so cross-origin resource sharing. 22 00:01:16,660 --> 00:01:20,660 And since we want to make our API available to everyone, 23 00:01:20,660 --> 00:01:25,240 we definitely need to implement that, all right? 24 00:01:25,240 --> 00:01:27,933 Now let me actually show you how this would fail. 25 00:01:28,800 --> 00:01:31,073 So let's grab this URL here, 26 00:01:31,920 --> 00:01:35,743 and open in your tab and then inspect. 27 00:01:36,770 --> 00:01:41,320 And so basically let's do an HTTP request to our API 28 00:01:41,320 --> 00:01:43,540 here from the console, okay? 29 00:01:43,540 --> 00:01:45,840 Because basically when we do it from here, 30 00:01:45,840 --> 00:01:48,273 it will also be a cross-origin request. 31 00:01:49,260 --> 00:01:53,440 So let's just say const x equals await, 32 00:01:53,440 --> 00:01:58,100 and then let's use the fetch JavaScript function, all right? 33 00:01:58,100 --> 00:02:00,050 So fetch is basically a function 34 00:02:00,050 --> 00:02:02,600 that's a bit similar to the Axios library 35 00:02:02,600 --> 00:02:04,640 that we used in our code, 36 00:02:04,640 --> 00:02:07,080 but it's native JavaScript in the browser, 37 00:02:07,080 --> 00:02:10,100 and so we can just use it here in the console. 38 00:02:10,100 --> 00:02:12,900 So let's say that we want to do a request 39 00:02:12,900 --> 00:02:17,460 to our tours API like this, all right? 40 00:02:17,460 --> 00:02:20,870 So if we try this now, let's see what we get. 41 00:02:20,870 --> 00:02:22,480 And indeed we get the error 42 00:02:22,480 --> 00:02:24,990 that trying to access this path here 43 00:02:24,990 --> 00:02:29,900 from this other origin has been blocked by the CORS policy. 44 00:02:29,900 --> 00:02:32,350 And so that is exactly what I said before. 45 00:02:32,350 --> 00:02:35,320 So that by default, a cross-origin request 46 00:02:35,320 --> 00:02:37,250 will always be blocked. 47 00:02:37,250 --> 00:02:40,270 Now by the way, this only applies to requests 48 00:02:40,270 --> 00:02:41,880 made from the browser. 49 00:02:41,880 --> 00:02:44,990 For example, using the fetch API here, 50 00:02:44,990 --> 00:02:47,260 or something like the Axios library 51 00:02:47,260 --> 00:02:49,010 that we used in our code. 52 00:02:49,010 --> 00:02:51,210 And so that means that from the server, 53 00:02:51,210 --> 00:02:54,500 we will always be able to make cross-origin requests 54 00:02:54,500 --> 00:02:55,920 without any problems. 55 00:02:55,920 --> 00:02:58,620 So there are no restrictions on the server, 56 00:02:58,620 --> 00:03:00,500 but really only on the browser, 57 00:03:00,500 --> 00:03:03,080 for security reasons basically. 58 00:03:03,080 --> 00:03:06,680 Oh, and also in order to be considered cross-origin, 59 00:03:06,680 --> 00:03:09,440 a request might come from a different domain. 60 00:03:09,440 --> 00:03:12,020 So just as we saw in our first example here, 61 00:03:12,020 --> 00:03:15,160 but also a different subdomain, a different protocol, 62 00:03:15,160 --> 00:03:17,650 or even a different port is considered 63 00:03:17,650 --> 00:03:19,950 a cross-origin request. 64 00:03:19,950 --> 00:03:24,950 So for example, if we had API.natours.com for our API, 65 00:03:27,100 --> 00:03:31,480 and would then do a request from natours.com, 66 00:03:31,480 --> 00:03:34,650 that would then also be considered a cross-origin request, 67 00:03:34,650 --> 00:03:37,200 and would fail, okay? 68 00:03:37,200 --> 00:03:39,950 But again, since we want to allow other websites 69 00:03:39,950 --> 00:03:42,410 to basically access our API, 70 00:03:42,410 --> 00:03:45,423 let's now implement cross-origin resource sharing. 71 00:03:46,680 --> 00:03:49,620 All right, and so we do that once more 72 00:03:49,620 --> 00:03:51,653 by installing an NPM package. 73 00:03:53,130 --> 00:03:55,940 So NPM install, and simply CORS. 74 00:03:57,770 --> 00:03:59,933 Then here we require that package. 75 00:04:08,140 --> 00:04:10,450 And once again, this CORS here 76 00:04:10,450 --> 00:04:12,480 is a very simple middleware function 77 00:04:12,480 --> 00:04:17,480 that we now need to use for our application, all right? 78 00:04:17,580 --> 00:04:20,250 So let's do that here, and why not do it 79 00:04:20,250 --> 00:04:21,533 right here at the top? 80 00:04:22,980 --> 00:04:25,930 So let's say implement CORS. 81 00:04:28,240 --> 00:04:32,380 And so app.use, and then call CORS, 82 00:04:32,380 --> 00:04:35,270 which in turn will return a middleware function 83 00:04:35,270 --> 00:04:37,860 which is then gonna add a couple of different headers 84 00:04:37,860 --> 00:04:39,580 to our response. 85 00:04:39,580 --> 00:04:41,870 And since all this middleware function here does 86 00:04:41,870 --> 00:04:44,820 is to basically add some specific headers, 87 00:04:44,820 --> 00:04:46,767 maybe you're thinking "Why we are using 88 00:04:46,767 --> 00:04:49,060 "yet another NPM package?" 89 00:04:49,060 --> 00:04:51,240 Well, let's just actually take a look 90 00:04:51,240 --> 00:04:52,853 at the code of this package. 91 00:04:55,370 --> 00:04:58,820 So GitHub CORS, so once more, 92 00:04:58,820 --> 00:05:02,490 that's usually how I find documentation 93 00:05:02,490 --> 00:05:05,610 or the source code itself for my packages. 94 00:05:05,610 --> 00:05:08,730 And so let's go here into lib, 95 00:05:08,730 --> 00:05:10,793 which usually means library. 96 00:05:11,870 --> 00:05:15,960 And then all we really have here is this index.js. 97 00:05:15,960 --> 00:05:20,020 And so you see that here is all the code, 98 00:05:20,020 --> 00:05:21,500 and basically what you see here 99 00:05:21,500 --> 00:05:24,730 is that it simply adds this header here 100 00:05:24,730 --> 00:05:28,653 with the value of basically everything to the headers. 101 00:05:29,850 --> 00:05:33,740 All right, so then you have a couple of other headers, 102 00:05:33,740 --> 00:05:37,320 Access-Control-Allow-Methods, allow-credentials, 103 00:05:37,320 --> 00:05:40,003 and that's for different cases. 104 00:05:40,900 --> 00:05:42,800 All right, but so you see that it's really 105 00:05:42,800 --> 00:05:45,010 just all about headers here. 106 00:05:45,010 --> 00:05:49,000 So yeah, maybe we could just add these headers by ourselves, 107 00:05:49,000 --> 00:05:51,430 but why would we actually do that? 108 00:05:51,430 --> 00:05:52,810 I mean we could of course, 109 00:05:52,810 --> 00:05:56,260 in order to fully understand really how it works, 110 00:05:56,260 --> 00:05:58,790 but in Node.js and Express development, 111 00:05:58,790 --> 00:06:01,010 in the real environment you usually 112 00:06:01,010 --> 00:06:03,440 will not want to reinvent the wheel, 113 00:06:03,440 --> 00:06:05,340 and instead, whenever you can, 114 00:06:05,340 --> 00:06:08,810 use packages that other developers have written for us. 115 00:06:08,810 --> 00:06:12,110 So really we just focus on making our application work, 116 00:06:12,110 --> 00:06:14,740 instead of rewriting code that other developers 117 00:06:14,740 --> 00:06:17,750 have already written for us, all right? 118 00:06:17,750 --> 00:06:20,070 So we can take a look at all of this, 119 00:06:20,070 --> 00:06:23,930 but as I mentioned, we can also just go ahead 120 00:06:23,930 --> 00:06:27,110 and actually use this, all right? 121 00:06:27,110 --> 00:06:31,190 Anyway, this is how we enable cross-origin resource sharing 122 00:06:31,190 --> 00:06:32,890 for all incoming requests. 123 00:06:32,890 --> 00:06:35,560 So basically for our entire API. 124 00:06:35,560 --> 00:06:37,950 But let's say we only wanted to enable CORS 125 00:06:37,950 --> 00:06:39,490 on a specific route. 126 00:06:39,490 --> 00:06:43,253 So we could use that as well, so let's just copy this. 127 00:06:44,310 --> 00:06:48,250 And so if we only wanted to enable CORS, 128 00:06:48,250 --> 00:06:50,360 let's say on the tours, well, 129 00:06:50,360 --> 00:06:53,930 we could simply add that here into this middleware stack. 130 00:06:53,930 --> 00:06:56,930 All right, but again in this case 131 00:06:56,930 --> 00:06:59,233 we really want to allow it everywhere. 132 00:07:00,210 --> 00:07:03,400 So as we saw previously in the GitHub code, 133 00:07:03,400 --> 00:07:04,980 what this does is to set 134 00:07:04,980 --> 00:07:09,980 the Access-Control-Allow-Origin header to everything. 135 00:07:14,120 --> 00:07:16,040 And so what this everything here means 136 00:07:16,040 --> 00:07:19,670 is for all the requests no matter here they are coming from. 137 00:07:19,670 --> 00:07:22,350 And so this is ideal for allowing everyone 138 00:07:22,350 --> 00:07:24,380 to consume our API. 139 00:07:24,380 --> 00:07:25,940 But now imagine the case 140 00:07:25,940 --> 00:07:28,440 where we don't want to share our API, 141 00:07:28,440 --> 00:07:31,590 but we want to be able to have the API on one domain, 142 00:07:31,590 --> 00:07:33,960 or even one subdomain, and then have 143 00:07:33,960 --> 00:07:36,760 our front-end application on a different domain. 144 00:07:36,760 --> 00:07:40,580 For example, let's say, so as I mentioned before, 145 00:07:40,580 --> 00:07:45,580 we had our API at API.natours.com, 146 00:07:46,020 --> 00:07:50,290 but then our front-end app at natours.com. 147 00:07:50,290 --> 00:07:52,210 And so in that case all we want it to do 148 00:07:52,210 --> 00:07:56,290 is to allow access from this origin here, basically. 149 00:07:56,290 --> 00:08:01,290 And so in that case we would use app.use, 150 00:08:01,700 --> 00:08:06,700 and then CORS, and then pass in an object for the options 151 00:08:06,719 --> 00:08:08,720 where we'd specify the origin 152 00:08:11,320 --> 00:08:16,320 to let's say HTTPS://www.natours.com. 153 00:08:19,547 --> 00:08:21,560 And so this is just an example 154 00:08:21,560 --> 00:08:26,560 in case we had our front-end at natours.com, all right? 155 00:08:28,870 --> 00:08:31,510 And so again, with this we would only allow 156 00:08:31,510 --> 00:08:34,210 this URL basically, so this origin, 157 00:08:34,210 --> 00:08:39,142 to create requests to API.natours.com. 158 00:08:39,142 --> 00:08:42,070 And of course we could also allow other origins. 159 00:08:42,070 --> 00:08:44,400 For example, only for some specific websites 160 00:08:44,400 --> 00:08:46,770 that we want it to allow, okay? 161 00:08:46,770 --> 00:08:50,690 But again, in this case we really want to allow everyone. 162 00:08:50,690 --> 00:08:54,560 Okay, so this was the first part of enabling CORS, 163 00:08:54,560 --> 00:08:56,940 but actually that's not all, 164 00:08:56,940 --> 00:08:59,160 because right now this will only work 165 00:08:59,160 --> 00:09:01,410 for so-called simple requests. 166 00:09:01,410 --> 00:09:05,280 And simple requests are get and post requests. 167 00:09:05,280 --> 00:09:08,770 On the other hand, we have so-called non-simple requests. 168 00:09:08,770 --> 00:09:12,300 And these are put, patch and delete requests, 169 00:09:12,300 --> 00:09:14,840 or also requests that send cookies 170 00:09:14,840 --> 00:09:17,210 or use nonstandard headers. 171 00:09:17,210 --> 00:09:19,240 And these non-simple requests, 172 00:09:19,240 --> 00:09:22,490 they require a so-called preflight phase. 173 00:09:22,490 --> 00:09:25,520 So whenever there is a non-simple request, 174 00:09:25,520 --> 00:09:27,910 the browser will then automatically issue 175 00:09:27,910 --> 00:09:31,370 the preflight phase, and this is how that works. 176 00:09:31,370 --> 00:09:34,240 So before the real request actually happens, 177 00:09:34,240 --> 00:09:36,480 and let's say a delete request, 178 00:09:36,480 --> 00:09:39,640 the browser first does an options request 179 00:09:39,640 --> 00:09:42,400 in order to figure out if the actual request 180 00:09:42,400 --> 00:09:44,150 is safe to send. 181 00:09:44,150 --> 00:09:46,410 And so what that means for us developers 182 00:09:46,410 --> 00:09:49,410 is that on our server we need to actually respond 183 00:09:49,410 --> 00:09:51,420 to that options request. 184 00:09:51,420 --> 00:09:54,860 And options is really just another HTTP method, 185 00:09:54,860 --> 00:09:59,110 so just like get, post or delete, all right? 186 00:09:59,110 --> 00:10:02,530 So basically when we get one of these options requests 187 00:10:02,530 --> 00:10:05,080 on our server, we then need to send back 188 00:10:05,080 --> 00:10:08,120 the same Access-Control-Allow-Origin header. 189 00:10:08,120 --> 00:10:10,430 And this way the browser will then know 190 00:10:10,430 --> 00:10:11,930 that the actual request, 191 00:10:11,930 --> 00:10:15,520 and in this case the delete request, is safe to perform, 192 00:10:15,520 --> 00:10:20,070 and then executes the delete request itself, all right? 193 00:10:20,070 --> 00:10:24,513 So let's do that and say app.options. 194 00:10:26,130 --> 00:10:29,200 Okay, and so again this is very similar 195 00:10:29,200 --> 00:10:34,200 to doing app.get for example, or .post, .delete, .patch, 196 00:10:35,430 --> 00:10:37,850 and all these verbs that you already know. 197 00:10:37,850 --> 00:10:42,490 So .options is not to set any options on our application, 198 00:10:42,490 --> 00:10:46,490 it's really just another HTTP method that we can respond to. 199 00:10:46,490 --> 00:10:49,670 And so again, in this case we need to respond to it 200 00:10:49,670 --> 00:10:52,010 because the browser sends an option request 201 00:10:52,010 --> 00:10:54,630 when there is a preflight phase. 202 00:10:54,630 --> 00:10:56,520 So we need to define the route 203 00:10:56,520 --> 00:10:59,630 for which we want to handle the options. 204 00:10:59,630 --> 00:11:04,630 And once again, we will do this on all the routes, okay? 205 00:11:04,920 --> 00:11:07,270 And then basically the handler, 206 00:11:07,270 --> 00:11:11,653 which once more is the CORS middleware, all right? 207 00:11:12,610 --> 00:11:15,370 And once more, we could of course only allow 208 00:11:15,370 --> 00:11:18,810 these complex requests on just a specific route. 209 00:11:18,810 --> 00:11:22,630 For example app.options, 210 00:11:22,630 --> 00:11:27,630 and let's say only on api/v1/tours/:id, 211 00:11:31,110 --> 00:11:34,340 like this, okay? 212 00:11:34,340 --> 00:11:37,730 So let's say that someone does a delete or a patch request 213 00:11:37,730 --> 00:11:39,840 for one of the tours, and only there 214 00:11:39,840 --> 00:11:41,890 we allow a preflight phase. 215 00:11:41,890 --> 00:11:44,340 And so basically only on this route here, 216 00:11:44,340 --> 00:11:47,680 one of these complex requests can be done. 217 00:11:47,680 --> 00:11:51,840 So in this case here where we only had this options route, 218 00:11:51,840 --> 00:11:54,150 only the tours could be deleted or patched 219 00:11:54,150 --> 00:11:56,820 from a cross-origin request, right? 220 00:11:56,820 --> 00:11:59,870 And none of our other resources, all right? 221 00:11:59,870 --> 00:12:04,000 But once more, let's allow all of them, okay? 222 00:12:04,000 --> 00:12:07,960 But I will still just leave this here for you as an example. 223 00:12:07,960 --> 00:12:11,550 Okay, anyway, that's all we really have to do 224 00:12:11,550 --> 00:12:14,410 in order to enable CORS for our application. 225 00:12:14,410 --> 00:12:17,030 And so let's now redeploy the application 226 00:12:17,030 --> 00:12:19,620 by pushing it again to Heroku. 227 00:12:19,620 --> 00:12:23,010 But before we do that, I actually want to change 228 00:12:23,010 --> 00:12:25,520 something here in our package.json. 229 00:12:25,520 --> 00:12:28,010 And that is this node engine here. 230 00:12:28,010 --> 00:12:30,380 So sometimes it can create some problems 231 00:12:30,380 --> 00:12:33,220 when we specify the version like this. 232 00:12:33,220 --> 00:12:35,770 So basically allowing versions to install 233 00:12:35,770 --> 00:12:37,400 that are greater than the version 234 00:12:37,400 --> 00:12:38,930 that we're currently running. 235 00:12:38,930 --> 00:12:40,540 And so what I want to do here 236 00:12:40,540 --> 00:12:43,700 is to say that it should only install version 10, 237 00:12:43,700 --> 00:12:45,493 and not a version after that. 238 00:12:46,560 --> 00:12:50,970 So I do it by saying this caret symbol here, 239 00:12:50,970 --> 00:12:52,470 and then version 10. 240 00:12:52,470 --> 00:12:55,990 And so once more, that's using the semantic versioning, 241 00:12:55,990 --> 00:12:57,770 and so just like here. 242 00:12:57,770 --> 00:13:00,610 Which remember, means that NPM is allowed 243 00:13:00,610 --> 00:13:04,390 to install any of these subversions or patch versions, 244 00:13:04,390 --> 00:13:08,070 but not bump up to the next major version. 245 00:13:08,070 --> 00:13:10,760 And so here what I'm doing is the same, okay? 246 00:13:10,760 --> 00:13:14,350 So I'm currently running Node version 10 something, 247 00:13:14,350 --> 00:13:19,070 and so you can confirm yours by typing node -v, 248 00:13:19,070 --> 00:13:22,060 and so you see that I'm on 10.11 right now. 249 00:13:22,060 --> 00:13:24,270 But probably when you're watching this course, 250 00:13:24,270 --> 00:13:29,250 you're gonna be at least at version 12, maybe even 14 or 16, 251 00:13:29,250 --> 00:13:32,510 depending on how long in the future you are, all right? 252 00:13:32,510 --> 00:13:33,860 And don't worry of course, 253 00:13:33,860 --> 00:13:36,240 everything that I show you here in the course 254 00:13:36,240 --> 00:13:37,550 should still be working fine 255 00:13:37,550 --> 00:13:40,010 for whatever Node version you're using. 256 00:13:40,010 --> 00:13:42,030 So if you're using version 12, 257 00:13:42,030 --> 00:13:46,900 then please go ahead and put the 12 right here, okay? 258 00:13:46,900 --> 00:13:51,170 Anyway, let's now add all the modified files 259 00:13:51,170 --> 00:13:56,163 to the staging area, so git add all. 260 00:13:58,300 --> 00:14:02,053 And then commit them with a meaningful message, 261 00:14:03,670 --> 00:14:05,260 so implemented CORS. 262 00:14:08,707 --> 00:14:11,120 And then get push Heroku master. 263 00:14:14,390 --> 00:14:16,200 And now that takes some time, 264 00:14:16,200 --> 00:14:18,453 so I'll see you when that's done. 265 00:14:21,950 --> 00:14:25,640 So the application is successfully deployed now, 266 00:14:25,640 --> 00:14:28,230 let's just quickly reload here 267 00:14:29,100 --> 00:14:32,550 just to see if it's still working, and indeed it is. 268 00:14:32,550 --> 00:14:37,190 And so now to prove you that it works differently with CORS, 269 00:14:37,190 --> 00:14:38,970 if we do this request here again 270 00:14:38,970 --> 00:14:41,720 it should then actually work, right? 271 00:14:41,720 --> 00:14:45,170 So let's try that, and here we go. 272 00:14:45,170 --> 00:14:48,233 No error this time, let's check x here. 273 00:14:49,750 --> 00:14:53,740 And indeed, it looks like there is something here. 274 00:14:53,740 --> 00:14:57,150 So you see that actually the response is of type CORS, 275 00:14:57,150 --> 00:15:01,053 we have our headers, well, I cannot really see them here. 276 00:15:01,920 --> 00:15:04,010 That doesn't matter, here we also have 277 00:15:04,010 --> 00:15:05,690 just a readable string, 278 00:15:05,690 --> 00:15:08,070 but again that's not important at all. 279 00:15:08,070 --> 00:15:10,450 What matters here is that now we are able 280 00:15:10,450 --> 00:15:15,450 to perform cross-origin requests, so that's fantastic. 281 00:15:15,800 --> 00:15:19,130 Now let me just also show you the actual headers 282 00:15:19,130 --> 00:15:21,260 that the CORS package adds 283 00:15:21,260 --> 00:15:25,610 by just doing some request here in Postman. 284 00:15:25,610 --> 00:15:28,513 So in production, let's now send it. 285 00:15:31,540 --> 00:15:34,240 And so here you see in the response headers 286 00:15:34,240 --> 00:15:37,690 that we actually have this Access-Control-Allow-Origin 287 00:15:37,690 --> 00:15:41,960 set to everything, okay, great. 288 00:15:41,960 --> 00:15:45,000 And so this is how you actually implement 289 00:15:45,000 --> 00:15:47,993 cross-origin resource sharing in your own application.