proxy websocket requests in development with create-react-app

this is inspired from [https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development#configuring-the-proxy-manually]

if you need to proxy your api call in development, it is very easy: just add the following in your package.json

proxy: "http://myserver"

so that calls to /api will be proxied to http://myserver in development. For example, in your react code you will have

export const getUsers = () => {
    return fetch('/api/getUsers', { method: 'GET' })
    .then(response => { ...

in this example, the call localhost:3000/api/getUsers will be proxied to http://myserver/api/getUsers

if you need to proxy websockets as well, then there is also an easy solution:

  • remove the proxy setting from the package.json
  • add a file src/setupProxy.js with the following
const proxy = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(proxy('/api', { target: 'http://myserver' }));
  app.use(proxy('/ws', { target: 'ws://myserver', ws: true }));
};

in your React code nothing change for the /api calls, just use the URL /api. For the websockets request, it is a bit more involved, here is how I do it

  componentDidMount() {
     const protocolPrefix = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
     let { host } = window.location; // nb: window location contains the port, so host will be localhost:3000 in dev
     this.ws = new WebSocket(`${protocolPrefix}//${host}/ws/dbstates`); // dbstates is my websocket route
     this.ws.onopen = () => {
       ...
  }

so that when the url is localhost:3000/ws/dbstates, it will be proxied based on the setup in src/setupProxy.js

Another solution is to use an environment variable to change the websocket url in development. This can be used in combination with the previous solution, my code would then be

const protocolPrefix = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
let { host } = window.location; // nb: window location contains the port, so host will be localhost:3000 in dev
if (process.env.NODE_ENV === 'development' && process.env.REACT_APP_WSPROXYIP) {
  host = process.env.REACT_APP_WSPROXYIP;
  if (process.env.REACT_APP_WSPROXYPORT) {
    host += `:${process.env.REACT_APP_WSPROXYPORT}`;
  } else {
    const { port } = window.location;
    host += `:${port}`;
  }
}
this.ws = new WebSocket(`${protocolPrefix}//${host}/ws/dbstates`); // dbstates is my websocket route
Written on January 10, 2019