Search code examples
reactjsruby-on-rails-4serverbackendrails-api

Opening up Rails API to users within a closed network


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);});
    }

Solution

  • 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!