I am attempting to run a React/Rails Website locally for 2-3 users within a closed network. Currently, the users can reach the React portion (I have that set to port 80). The problem is, the API calls I have set to my Rails backend are all on localhost:3001
and the users have zero access to that database when I try to submit HTTP requests.
I know it's a CORS issue but I thought the code below would allow any domain to make the necessary request.
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
Server side work is not my forte, so I may be missing something glaring. Any idea how to open up that backend so the networked users can make API Calls on their end?
React is on this ip: http://192.168.2.70:80/
API calls on this port: 3001
Example API call from front end (works on host computer; not on other users):
getData = () => {
axios.get('http://localhost:3001/api/v1/pickup_deliveries')
.then((response) => {
this.setState({
apiData: response.data})
})
.catch((error)=>{console.log(error);});
}
The Problem
Unless I missed something, it looks like you're making a simple mistake that you're going to smack yourself for.
Typically, a CORS issue in a JavaScript application would yield a CORS/pre-flight request error error in your browser's JavaScript console.
The Misconception
The JavaScript that makes up a React application is downloaded by the client (i.e. your users). After that, the fetch call is executed on the client's computer. The fetch request doesn't originate from the server, but rather from the remote end.
It works on your computer because both React and the Rail API are hosted on your computer, so localhost:3001
resolves correctly. However, on your users computer, the React app attempts to find a service running on port 3001 on their computer.
Initial Solution
You need to tell React to reach out to the IP server that's hosting the API, like this:
getData = () => {
axios.get('http://192.168.2.70:3001/api/v1/pickup_deliveries')
.then((response) => {
this.setState({
apiData: response.data})
})
.catch((error)=>{console.log(error);});
}
Long Term Solution (for deployment)
In the future, look into dotenv
, which will allow you to set React environment variables. You could have a .env.local
file, and a .env.production
file.
In the local file, you could put:
REACT_APP_BACKEND_SERVER=http://localhost:3001
and in the production
on you could put:
REACT_APP_URL=http:/<server_ip>:3001
Then, in your program, do something like:
getData = () => {
axios.get(process.env.REACT_APP_SERVER_URL + "/api/v1/pickup_deliveries")
.then((response) => {
this.setState({
apiData: response.data})
})
.catch((error)=>{console.log(error);});
}
This will automatically resolve to localhost
when serving React using npm run start
and then resolve to <server_ip>
when you are serving the static files generated by npm run build
.
Feel free to comment on this answer. I would be happy to answer any other questions you have. Welcome to React!