Jonas: In this lecture we're gonna implement something
called CORS, which means cross-origin resource sharing.
And this is a fundamental feature in any API,
but I can only show you this now
that the application is actually already deployed.
Now what actually is cross-origin resource sharing,
and why do we need to implement it?
Well let's say we have our API
here at natours-jonas.herokuapp.com/api/v1,
and so on and so forth.
And then some other website, for example at example.com,
is trying to access our API.
So basically trying to call this URL here.
And this is then called a cross-origin request,
because herokuapp.com is a different domain
than example.com, and so therefore if example.com
is trying to access herokuapp.com,
it will be a cross-origin request, all right?
Now usually cross-origin requests are not allowed,
and will by default fail, unless we implement CORS,
so cross-origin resource sharing.
And since we want to make our API available to everyone,
we definitely need to implement that, all right?
Now let me actually show you how this would fail.
So let's grab this URL here,
and open in your tab and then inspect.
And so basically let's do an HTTP request to our API
here from the console, okay?
Because basically when we do it from here,
it will also be a cross-origin request.
So let's just say const x equals await,
and then let's use the fetch JavaScript function, all right?
So fetch is basically a function
that's a bit similar to the Axios library
that we used in our code,
but it's native JavaScript in the browser,
and so we can just use it here in the console.
So let's say that we want to do a request
to our tours API like this, all right?
So if we try this now, let's see what we get.
And indeed we get the error
that trying to access this path here
from this other origin has been blocked by the CORS policy.
And so that is exactly what I said before.
So that by default, a cross-origin request
will always be blocked.
Now by the way, this only applies to requests
made from the browser.
For example, using the fetch API here,
or something like the Axios library
that we used in our code.
And so that means that from the server,
we will always be able to make cross-origin requests
without any problems.
So there are no restrictions on the server,
but really only on the browser,
for security reasons basically.
Oh, and also in order to be considered cross-origin,
a request might come from a different domain.
So just as we saw in our first example here,
but also a different subdomain, a different protocol,
or even a different port is considered
a cross-origin request.
So for example, if we had API.natours.com for our API,
and would then do a request from natours.com,
that would then also be considered a cross-origin request,
and would fail, okay?
But again, since we want to allow other websites
to basically access our API,
let's now implement cross-origin resource sharing.
All right, and so we do that once more
by installing an NPM package.
So NPM install, and simply CORS.
Then here we require that package.
And once again, this CORS here
is a very simple middleware function
that we now need to use for our application, all right?
So let's do that here, and why not do it
right here at the top?
So let's say implement CORS.
And so app.use, and then call CORS,
which in turn will return a middleware function
which is then gonna add a couple of different headers
to our response.
And since all this middleware function here does
is to basically add some specific headers,
maybe you're thinking "Why we are using
"yet another NPM package?"
Well, let's just actually take a look
at the code of this package.
So GitHub CORS, so once more,
that's usually how I find documentation
or the source code itself for my packages.
And so let's go here into lib,
which usually means library.
And then all we really have here is this index.js.
And so you see that here is all the code,
and basically what you see here
is that it simply adds this header here
with the value of basically everything to the headers.
All right, so then you have a couple of other headers,
Access-Control-Allow-Methods, allow-credentials,
and that's for different cases.
All right, but so you see that it's really
just all about headers here.
So yeah, maybe we could just add these headers by ourselves,
but why would we actually do that?
I mean we could of course,
in order to fully understand really how it works,
but in Node.js and Express development,
in the real environment you usually
will not want to reinvent the wheel,
and instead, whenever you can,
use packages that other developers have written for us.
So really we just focus on making our application work,
instead of rewriting code that other developers
have already written for us, all right?
So we can take a look at all of this,
but as I mentioned, we can also just go ahead
and actually use this, all right?
Anyway, this is how we enable cross-origin resource sharing
for all incoming requests.
So basically for our entire API.
But let's say we only wanted to enable CORS
on a specific route.
So we could use that as well, so let's just copy this.
And so if we only wanted to enable CORS,
let's say on the tours, well,
we could simply add that here into this middleware stack.
All right, but again in this case
we really want to allow it everywhere.
So as we saw previously in the GitHub code,
what this does is to set
the Access-Control-Allow-Origin header to everything.
And so what this everything here means
is for all the requests no matter here they are coming from.
And so this is ideal for allowing everyone
to consume our API.
But now imagine the case
where we don't want to share our API,
but we want to be able to have the API on one domain,
or even one subdomain, and then have
our front-end application on a different domain.
For example, let's say, so as I mentioned before,
we had our API at API.natours.com,
but then our front-end app at natours.com.
And so in that case all we want it to do
is to allow access from this origin here, basically.
And so in that case we would use app.use,
and then CORS, and then pass in an object for the options
where we'd specify the origin
to let's say HTTPS://www.natours.com.
And so this is just an example
in case we had our front-end at natours.com, all right?
And so again, with this we would only allow
this URL basically, so this origin,
to create requests to API.natours.com.
And of course we could also allow other origins.
For example, only for some specific websites
that we want it to allow, okay?
But again, in this case we really want to allow everyone.
Okay, so this was the first part of enabling CORS,
but actually that's not all,
because right now this will only work
for so-called simple requests.
And simple requests are get and post requests.
On the other hand, we have so-called non-simple requests.
And these are put, patch and delete requests,
or also requests that send cookies
or use nonstandard headers.
And these non-simple requests,
they require a so-called preflight phase.
So whenever there is a non-simple request,
the browser will then automatically issue
the preflight phase, and this is how that works.
So before the real request actually happens,
and let's say a delete request,
the browser first does an options request
in order to figure out if the actual request
is safe to send.
And so what that means for us developers
is that on our server we need to actually respond
to that options request.
And options is really just another HTTP method,
so just like get, post or delete, all right?
So basically when we get one of these options requests
on our server, we then need to send back
the same Access-Control-Allow-Origin header.
And this way the browser will then know
that the actual request,
and in this case the delete request, is safe to perform,
and then executes the delete request itself, all right?
So let's do that and say app.options.
Okay, and so again this is very similar
to doing app.get for example, or .post, .delete, .patch,
and all these verbs that you already know.
So .options is not to set any options on our application,
it's really just another HTTP method that we can respond to.
And so again, in this case we need to respond to it
because the browser sends an option request
when there is a preflight phase.
So we need to define the route
for which we want to handle the options.
And once again, we will do this on all the routes, okay?
And then basically the handler,
which once more is the CORS middleware, all right?
And once more, we could of course only allow
these complex requests on just a specific route.
For example app.options,
and let's say only on api/v1/tours/:id,
like this, okay?
So let's say that someone does a delete or a patch request
for one of the tours, and only there
we allow a preflight phase.
And so basically only on this route here,
one of these complex requests can be done.
So in this case here where we only had this options route,
only the tours could be deleted or patched
from a cross-origin request, right?
And none of our other resources, all right?
But once more, let's allow all of them, okay?
But I will still just leave this here for you as an example.
Okay, anyway, that's all we really have to do
in order to enable CORS for our application.
And so let's now redeploy the application
by pushing it again to Heroku.
But before we do that, I actually want to change
something here in our package.json.
And that is this node engine here.
So sometimes it can create some problems
when we specify the version like this.
So basically allowing versions to install
that are greater than the version
that we're currently running.
And so what I want to do here
is to say that it should only install version 10,
and not a version after that.
So I do it by saying this caret symbol here,
and then version 10.
And so once more, that's using the semantic versioning,
and so just like here.
Which remember, means that NPM is allowed
to install any of these subversions or patch versions,
but not bump up to the next major version.
And so here what I'm doing is the same, okay?
So I'm currently running Node version 10 something,
and so you can confirm yours by typing node -v,
and so you see that I'm on 10.11 right now.
But probably when you're watching this course,
you're gonna be at least at version 12, maybe even 14 or 16,
depending on how long in the future you are, all right?
And don't worry of course,
everything that I show you here in the course
should still be working fine
for whatever Node version you're using.
So if you're using version 12,
then please go ahead and put the 12 right here, okay?
Anyway, let's now add all the modified files
to the staging area, so git add all.
And then commit them with a meaningful message,
so implemented CORS.
And then get push Heroku master.
And now that takes some time,
so I'll see you when that's done.
So the application is successfully deployed now,
let's just quickly reload here
just to see if it's still working, and indeed it is.
And so now to prove you that it works differently with CORS,
if we do this request here again
it should then actually work, right?
So let's try that, and here we go.
No error this time, let's check x here.
And indeed, it looks like there is something here.
So you see that actually the response is of type CORS,
we have our headers, well, I cannot really see them here.
That doesn't matter, here we also have
just a readable string,
but again that's not important at all.
What matters here is that now we are able
to perform cross-origin requests, so that's fantastic.
Now let me just also show you the actual headers
that the CORS package adds
by just doing some request here in Postman.
So in production, let's now send it.
And so here you see in the response headers
that we actually have this Access-Control-Allow-Origin
set to everything, okay, great.
And so this is how you actually implement
cross-origin resource sharing in your own application.