Proxies are almost as old as the internet itself, yet still a little mysterious.
When developing a single page web application they can be a serious timesaver. I'll show you how just a few lines of code in your Nuxt.js project can help you avoid common problems with single page apps that talk to an API.
"Wait hold on, I've heard the word plenty of times... but what exactly is a proxy?"
In computer networks, a proxy server is a server (a computer system or an application) that acts as an intermediary for requests from clients seeking resources from other servers. A client connects to the proxy server, requesting some service, such as a file, connection, web page, or other resource available from a different server and the proxy server evaluates the request as a way to simplify and control its complexity. Proxies were invented to add structure and encapsulation to distributed systems. Wikipedia
"OK well I could have looked it up on Wikipedia myself, but hey ho. How will this save me time?"
Many advances have been made in web security in recent years. However, if you're unfortunate enough to be someone that slings code for a living it has probably added increased complexity to the stuff you build. For example, you've probably encountered the most common issue, (CORS errors) if you've ever tried to load data from a third party API on your website.
A whole load of these problems can be completely avoided using a proxy. You are essentially tricking your code into thinking the data is coming from your own server, even when it isn't.
An example using the wonderful Nuxt.js and AWS API Gateway
Nuxt.js is a beautiful framework built upon the even more beautiful Vue.js. Like many people I use the Axios module for communicating with my API endpoints. The great news is proxy support is already built in.
The standard config in your nuxt.config.js
would normally look something like this:
axios: {
baseUrl: 'http://localhost:8080/api'
},
The html/javascript part of your website is most likely running from another port, like http://localhost:3000
. This means your browser treats them like different sites and steps it to halt communication in the way of a CORS error that will look something like this.
Cannot load http://localhost:8080/api. Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin.
Like all the best developers we are lazy. So instead of manually adding headers, or adding more complexity by installing a third party CORS package to our API, we can add a few simple lines of code to our Axios config. Like this:
axios: {
proxy: true
},
proxy: {
'/api/': { 'http://localhost:8080/api', pathRewrite: { '^/api/': '' } }
},
This extra config, including that little bit of path rewriting at the end, will reroute all traffic that is directed to /api/
via your new proxy, which is then sent on to your API. The proxy module built into the Axios Nuxt package will do the rest. Clever huh?
The last thing to do is update the API calls in your codebase to your new proxied API URI.
// Old direct request
const data = await $axios.$get('users')
// New proxy request :)
const data = await $axios.$get('/api/users')
Bonus round. Pushing to production
If you are building a single page app this solution will only work in your development environment. This is because the proxy magic is happening inside the server that Nuxt.js creates to serve requests. Once you build and push the files to production you are passing that job onto a real web server, in my case NGINX. Luckily creating a proxy in NGINX is just a case of writing a little more config.
Find your NGINX site config file and make these changes to proxy traffic to my API located on a different server:
# This is the relevant part of my existing config
location / {
try_files \$uri /index.html;
}
# Add a new block to proxy api requests to API Gateway
location /api {
proxy_set_header Host "subdomain.execute-api.ap-southeast-2.amazonaws.com";
proxy_set_header X-Real-IP $remote_addr;
proxy_pass https://subdomain.execute-api.ap-southeast-2.amazonaws.com/production;
proxy_ssl_server_name on;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
proxy_buffering off;
}
AWS API Gateway users take note of the proxy_set_header
and proxy_ssl_server_name
values. They are required to allow requests into your API. Without them, all requests will be denied.
Congratulations ð
You can now confidently use proxies in your web applications. This allows you to entirely skip over a whole bunch of potential traps a lot of web developers can find themselves falling in to. I hope I saved you some head scratching. I advise you to spend that extra time observing a good sunset or cuddling a puppy.