CORS (Cross-Origin Resource Sharing) is a constraint of browser-based applications that provides extra security for APIs and servers. In this lesson, we'll set appropriate CORS headers for our Workers API, so that our frontend application is able to access it.
Kristian Freeman: [0:00] It's extremely common in API development that you're going to obviously be using that API from some sort of device. For web developers, one of the most common ways that we do that is via a frontend interface.
[0:12] In this example, I have a React application which, when working, should make an API request to the Workers API that we've been developing and return the data that we've been getting from the Unsplash API as a larger list of images.
[0:24] In my React code here, I just have this function called getImages, which takes in a query, and then makes a request to serverless-api.signalnerve.workers.dev. It's a POST request and sends a body that's just a JSON string containing that query value. It's a lot like what we've been doing with our cURL request in the console, but in an actual browser in a React application.
[0:46] If I make a query here, for instance, for guitar, you can see that nothing happens. If I come into my Chrome DevTools, you can see that it returns a CORS error here. If I highlight that, it says, Cross-Origin Resource Sharing error-- Preflight missing. Allow origin header.
[1:01] What does that mean? Whenever you're working with integrating backend APIs or servers with your frontend application, you're going to deal with something called Cross-Origin Resource Sharing or CORS.
[1:11] This is a strategy that browsers and servers use together to indicate that a given browser application is allowed to access the server that it's trying to access.
[1:21] To do this, it makes an initial request which is called a preflight request that identifies the browser application saying, I'm coming from this website. I'm trying to make this request. Is that allowed?
[1:32] Our issue here is when we're making this request, the backend serverless API isn't saying, you're requesting from this origin, which in our case is localhost:3000. That is an origin that we are expecting to see so yes you can access this data.
[1:48] To fix this, we need to provide an Access-Control-Allow-Origin header which says, this resource can be accessed by this origin. In our case, we're just going to use star, which means it can get accessed by any origin.
[2:01] If you're building a more production ready API, you probably want to allow specific origins so say for instance, in this case they use foo.example. You could do something like app.myapp.com, or whatever your React application is being served from.
[2:17] One thing is worth mentioning is that CORS errors only happen when you're making a request inside of the browser. When we were making cURL request from the command line, we were essentially making a request from one server to another, from my computer to the worker serverless API.
[2:32] That's important because when you're using say another backend service in making a request to your serverless function or to your database or something like that, you're not going to run into CORS issues.
[2:42] In the same way, when we make a request from the worker serverless function to our Unsplash API, we also don't have to worry about CORS issues because we're essentially making a backend service to backend service request.
[2:56] Essentially a server to server request, even though it's technically a serverless function. It's only when we're dealing with browsers that we have to work with this CORS issue. Back in our code, let's begin integrating CORS support into our serverless function.
[3:09] Also, take this opportunity to reformat the code and make it easier to understand. Looking at our actual request that was made, you can see that there's a second one here which returns a 500.
[3:21] If I come in here and click, you can see that it's making a request to my serverless API. Specifically, it's setting the request method options. This is a specific request that the browser will make to your API to check for CORS data.
[3:35] We need to handle that inside of the serverless API and return the appropriate CORS headers. In my code, I'm going to delete this comment here to clean it up a little bit. At the beginning of my function, I'm going to look for the incoming request.method and check to see if it is an options request which is what we saw in the browser.
[3:52] If it is, we're going to return a new response and that's going to be a really simple response that just says, OK. Then parses in a set of headers. I'm going to call this CORS headers. Let's set that up.
[4:04] I'm going to come out of that function and set up a new variable called CORS headers, and this is going to be an object that has three header set. First, access control allow headers which I'm going to set to star.
[4:14] This just allows any headers that come in with the API request to parse through to the server. Access control allow methods which says, we want to allows post request to our API. Of course, you could put things like, get, post, delete, any of the HTTP methods that you might be familiar with though in our case we'll use, post.
[4:34] Finally, access control allow origin, which we'll set to star. These three headers together will say, allow any post request with any headers to our API server from any origin.
[4:47] On the Mozilla developer network page for CORS, there's a section here called the HTTP response headers. This will be a better definition of each of the headers that you need to send and how can specify more granular settings.
[4:59] For instance, maybe you want to set a specific origin that says, only allow request from Mozilla.org, or maybe you want to specify a certain set of methods or headers or anything else to tell your browsers, tell your client how it can work with your serverless API, though for now this is the basic so that anything as long as it is a post request.
[5:20] Now when an options request comes in, it will return this response, this is the CORS information that will allow you to use when you're working with this API.
[5:28] I'm going to take this opportunity to clean up the rest of this code by saying, if the request method is set to post then call return get images, which will parse in a request to.
[5:42] What is get images? Well, it's going to be all of this code. I'm going to put it into a slightly easier to understand function which I'll call, const getImages, making an async function that takes a request argument in, and then I'll just paste all of that code in.
[5:59] As you can see, if the option request comes in, I'm going to return a new response with all of that CORS headers information. If it's a post request, I'm going to call that original API code, which goes and makes a request to Unsplash like we would expect.
[6:13] Now, with all of that setup, I'll run Wrangler Publish one more time. It will publish my application. If I come back here and I search guitar here, you can see that it still gives me a CORS error, though it appears to return a 200. I still have this, missing allow origin header error.
[6:32] The reason for that might be a little tricky for most people. I wanted to show this error case and show you how to fix it. The issue is that you need to return those CORS headers in your API response when you're making a post request as well. It's easy to do that.
[6:46] We are already returning this response here that is a content type application JSON and we already have this CORS headers object, which includes all of the CORS headers that we care about.
[6:57] In order to include all of these headers inside of this response, we're going to add another line here and use the spread operator to say, CORS headers. Essentially, what this will do is inline all of the header key value pairs from inside of this object into this other response.
[7:16] Now, instead of just parsing this single content type header back, we're also going to include the CORS headers inside of that response. I'll run Wrangler Publish one more time to update my code. If I come back here in the browser, I try search one more time. You can see there is a lot of data coming back.
[7:35] It's making this request to Unsplash's API, doing the proper CORS information, and then rendering out a list of guitars.