I have an issue with http-proxy-middleware
.
My setup is I have my flask API
and my React frontend
both in docker containers
, run from a docker-compose
file. All works well. Flask is on localhost:5000
and react on localhost:3000
My Flask API is listening on a route localhost:5000/recent_customers
for a POST
request.
Using Postman
, I can send some info and get a nicely formed JSON response. It's working well.
The problem is, when I try and use the http-proxy-middleware
to call say http://localhost:3000/api/recent_customers
which SHOULD route to http://localhost:5000/recent_customers
I get the following error:
Error occured while trying to proxy to: localhost:3000/api/recent_customers
With React, I've setup http-proxy-middleware
and have the setupProxy.js
as such:
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
"/api",
createProxyMiddleware({
target: "http://localhost:5000",
changeOrigin: true,
})
);
};
I've setup my Axios
as such:
import axios from "axios";
const instance = axios.create({
baseURL: "/api",
});
instance.defaults.headers.common["Authorization"] = "AUTH TOKEN FROM INSTANCE";
// instance.interceptors.request...
export default instance;
I import the axios into my React component
and this is a cropped version of it for clarity:
import React, { useEffect, useState } from "react";
import RecentCustomersList from "../../components/Home/RecentCustomerList/RecentCustomerList";
import axios from "../../axios";
export default function Home(props) {
// total number of active customers in the system
const [totalActiveCustomers, setTotalActiveCustomers] = useState(
"calculating."
);
// list of a few customers that have been added recently
const [recentCustomers, setRecentCustomers] = useState([]);
// This is currently taking temp JSON data. We will take this from our API with axios in time
const recentCustomersHandler = () => {
axios.post("/recent_customers").then((response) => {
const customers = response.data;
setRecentCustomers(customers);
});
};
// load the axios API data to be sent to the recent customers
useEffect(() => {
recentCustomersHandler();
}, []);
// more here for prepping the display of data
return (
<div>
<Grid container spacing={3}>
{/* more layout here but trimmed for clarity */}
<RecentCustomerListGridItem />
</Grid>
</div>
);
}
My React Dockerfile
is here:
# Pull official node image
FROM node:14.15.1
# Expose ports. 3000 for web access. 35729 for hot reloading
EXPOSE 3000
EXPOSE 35729
# Set working directory in the docker container
WORKDIR /app
# Add /app/node_modules/.bin to environment variables
ENV PATH /app/node_modules/.bin:$PATH
# Copy package files and install app dependencies
COPY package.json ./app/package.json
COPY package-lock.json ./app/package.json
RUN npm install
RUN npm install react-scripts -g
# Add React app to working directory
ADD . /app
# Start the React app
CMD ["npm", "start"]
My docker-compose
file is here:
version: "3.7"
services:
# react
client:
container_name: react
build:
context: ./frontend
dockerfile: Dockerfile
tty: true
ports:
- "3000:3000"
volumes:
- ./frontend:/app
- /app/node_modules
networks:
- frontend
depends_on:
- flask_api
# flask
flask_api:
container_name: flask-api
build:
context: ./backend
dockerfile: Dockerfile
command: gunicorn --reload --bind 0.0.0.0:5000 flask_api.app:create_app()
ports:
- "5000:5000"
volumes:
- ./backend:/app # mount the /backend folder to the docker's /app directory. This allows for hotloading in flask, so when I save locally, container updates
- appdata:/var/www/
networks:
- frontend
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
volumes:
appdata:
driver: local
I wonder if anyone is able to spot an issue. If I am missing any info that might help, please do let me know and I'll udpate the question. Thank you.
UPDATE 1 : If I update my axios file to the following:
import axios from "axios";
const instance = axios.create({
baseURL: "http://localhost:5000",
});
instance.defaults.headers.common["Authorization"] = "AUTH TOKEN FROM INSTANCE";
// instance.interceptors.request...
export default instance;
I still get the same error from Postman
, however my console in react / the browser shows as this error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/recent_customers. (Reason: CORS request did not succeed).
I was finally able to get this working with a reverse proxy using nginx to host my app.
First you have to use a multistage build with Docker so you can pull in nginx to host your app. Here's a sample Docker config:
There's a few key points in this config:
react-scripts
so I can create a production build of my app within the context of Docker so we can use that output in the second stage. In the second stage, I create an nginx build that hosts my app.nginx.conf
In
nginx.conf
- that's where you set up the main entry point for your app which serves up your react app. After that, you add a reverse proxy to point to your actual API. Here's my config:location /
is the main entry point for your app - that's where you specify that everything routes toindex.html
.The juicy part is
location /api
- that's the reverse proxy you need to allow your app to communicate via middleware proxy back to your API. In your React app, everything goes to/api/someEndpoint
- I created anapi.ts
file to ensure every call is prepended with/api
. This is all working excellently for me, the app performs well and calls to my back end are very fast. Hopefully this helps :)