Cross-Origin Resource Sharing (CORS) is a relatively new problem in JavaScript development. Maybe I’m showing my age here, but I can distinctly remember when there were no concerns with loading JavaScript from all over the internet into your blog. It was new! It was fun! But as more and more of us got online, and JavaScript webpages turned into JavaScript applications, it became a huge security risk. Thus, we have our modern world where a JavaScript file can only be loaded outside of its domain if it contains the correct Access-Control-Allow-Origin
headers.
So, what do you do when you’re happily making a block (as part of your agency’s Gutenberg-first initiative, of course), and the API you are trying to access doesn’t have the correct headers? Let me show you a quick way to resolve a CORS error with the WordPress REST API. In particular, we’re going to create a custom REST endpoint and proxy our request through the WordPress API.
I ran into this problem when revisiting my old custom oEmbed provider. I wanted to accomplish the same thing, but in JavaScript:
However, when trying to load the API from my local machine, I got these errors:
In short, because the remote server backend.deviantart.com
is not set up to allow an arbitrary web page to load its JavaScript, I could not call the API directly from my block using fetch
. To get around this, we’ll be using the PHP backend and wp_remote_get
.
New REST Endpoint
First, we need to set up our custom endpoint. This will allow us to call the WordPress backend from our block:
You can read more about register_rest_route
in the WordPress docs. With this code, we are setting up the following flow:
- Block will call
/wp-json/oddevan/v1/devArtProxy/
- WordPress will call the
proxy_deviantart_oembed_security
function to find out if the current user has permissions to access this endpoint - WordPress will call the
proxy_deviantart_oembed
function.
Next, let’s check our security function:
As you can see, it’s not very complicated. We just need to pass along whether the current user can use the editor. If the user can’t use the editor, there’s no reason for them to use our endpoint. This will prevent anonymous users (aka, “anyone on the internet”) from using our endpoint, possibly for purposes we don’t like.
Now, let’s see our proxy function:
There’s a bit going on here. First, we get the url
variable from the request and run it through a helper function we wrote to make sure it is actually a DeviantArt URL. Then we use wp_remote_get
to have the PHP backend make the request to DeviantArt’s oEmbed API. Because requests like this don’t have the extra considerations that a JavaScript request has, they are not usually subject to CORS. After some quick checking to make sure we have an actual response, we package up the response from DeviantArt inside a WP_REST_Response
object and send it back to our block.
Inside our block, we just have to call apiFetch
to have WordPress automatically set up the request to our endpoint:
Because apiFetch
returns a Promise
, we need to use async
and await
when using it. But that’s another blog post.
You can see the whole thing in action in the finished plugin. It’s built using our own WDS Block Starter!