React Native fetch a local server using a proxy - reactjs

In my react native app I am trying to perform a fetch to my local backend server. In my package.json I have put "proxy": "http://localhost:3000" .
My fetch looks like
fetch('/')
.then(response => response.json())
.then(json => console.log(json))
.catch(err => console.log)
It catches an error
[TypeError: Network request failed]
When I remove the proxy and manually enter the address in the fetch it works and my server receives a GET request.
fetch('http://localhost:3000')
.then(response => response.json())
.then(json => console.log(json))
.catch(err => console.log)

Two points here:
Set proxy in package.json is a feature of create-react-app, which wraps webpack dev server's proxy. react-native uses Metro instead of Webpack as bundler and it does not support setting up a local proxy.
Different from the web, http client in react-native has no current host. So if you use fetch('/'), it won't know which domain or ip address to send request to.

hello you can use your network IP Address for using local server like instead localhost change with your Ip address and you can call your server e.g, http://192.xxx.x.xxx:3000

Related

Calling heroku API from React app, error 200

I created a small API that scrapes a web page for train arrival/departures. I hosted it on Heroku and when i visit the page: https://sl-scraper.herokuapp.com/fromstockholm i can see the JSON response i expect. It looks like this:
Everything fine so far. Now i am looking to get this data in my React app to display it in a nicer way. This is where i run into problem. I tried to get the information in two ways, and both ways causes the same issue.
Here is the first attempt:
React.useEffect(function(){
axios.get("https://sl-scraper.herokuapp.com/fromstockholm")
.then(response =>{
console.log(response);
})
.catch(err => console.log(err));
},[]);
Here is the second attempt:
React.useEffect(()=>{
fetch("https://sl-scraper.herokuapp.com/fromstockholm")
.then(response => {
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => console.log(error));
},[]);
Both these attempts causes this issue when i inspect the log:
Access to XMLHttpRequest at 'https://sl-scraper.herokuapp.com/fromstockholm' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Does anyone know why i get these errors? Thank you so much in advance.
Cloning the CORS-Anywhere repo to our PC
we have our environment set up we can proceed to clone the CORS-Anywhere repo into a selected destination on our PC.
As a developer, it is always nice to appreciate the effort of other developers that provide solutions that make our lives easier by sending some form of support in their direction, so do drop a star for the CORS-Anywhere repo if it helps you solve your problem.
To start, we will open our terminal at the directory of the local storage we want to place the CORS-Anywhere server in locally and run the git command:
git clone https://github.com/Rob--W/cors-anywhere/
After the cloning is complete we will have to install all the packages this project depends on by running the command npm install on your terminal:
npm install
After that deploy your heroku app.
Reference: https://dev.to/imiebogodson/fixing-the-cors-error-by-hosting-your-own-proxy-on-heroku-3lcb

How do I configure my React-Node App so I can deploy it to Heroku?

So I've built a simple MERN app using create-react-app, that I want to deploy to Heroku. I build the front end in a client folder operating on localhost:3000, that sends requests to my express sever as a proxy to localhost:5000. My file structure is as follows:
+client
|
+-node_modules
+-public
+-src
|
+-components
+-App.js
+-index.js
//server
+-models
+-node-modules
+-package-lock.json
+-package.json
+-server.js
And I've set up the proxy in my package-json like this: "proxy": "http://localhost:5000",
So my main question is this: How do I configure my API endpoints for deployment?
At the moment, they're structured like this:
API call from react component:
useEffect(() => {
axios.get("http://localhost:5000/api/all-cafes")
.then((cafe) => {
setCafe(cafe.data);
})
.catch((err) => {
console.log(err);
})
}, [])
Express function on server.js
app.get('/api/all-cafes', (req,res) => {
Cafe.find()
.then((result) => {
res.send(result)
})
.catch(err => {
console.log(err)
})
})
My other question is what is the role of the .env file, and will I need to make one in order to solve this?
I've had a helpful suggestion saying that I can run the front end and back end on different servers, and adjust the code depending on whether it is in development or production, using the following code:
const prefix = process.env.NODE_ENV === 'production' ? "http://heroku_app_address" : "http://localhost:5000"
function getUrl(relativeUrl) {
return prefix + "/" + relativeUrl;
}
fetch(getUrl('api/all-reviews'));
But I'm not sure how to implement this, whether I need a .env file, and if so, what to put in said file.
The .env file helps you specifiy certain credentials or endpoints that are either going to change based on deployment environment (dev,qa,prod may have differewnt API endpoints), or you want to provide certain secret keys or configurations, which otherwise should not be part of your code repository (clientSecret etc).
The create-react-app.dev/docs has detailed explanation to these.
If you have not bootstraped your app using create-react-app then you can use dot-env npm package. The steps are detailed here: Stack overflow :Adding an .env file to React Project

In Axios, res.data returns html source of the my own index.html?

axios
.get(`/?keyword=${queries}`)
.then(res => {
setResponse(res);
console.log("Test----");
console.table(res);
setSearching(true);
})
.catch(console.log);
Here I'm trying to request a json file from a site that is at a port 5000, my current port for the frontend is port 3000. What is going on? why does this keep happening?
Your URL is a relative one, consisting of just the path. That makes the request to the same:
scheme
host
port
… as the HTML document was loaded from. Since that was from port 3000, the Ajax request is also made to port 3000.
If you want to make the request to a different server, then you need to specify the hostname and port explicitly.
.get(`//example.com:5000/?keyword=${queries}`)

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

How to use a proxy for a link with reactjs

I'm working on a website using Reactjs and Typescript for the front-end and the backend is in Java. While I'm developing I use port 3000 for the frontend and the 8080 for the backend. I have setup the proxy property on the package.json
"proxy": "http://localhost:8080"
so I don't have any problem while I'm doing requests to the backend because the proxy works perfectly.
Now I need to create some links to download reports, so I'm generating dynamically the links and I need them to point to the port 8080 and not to the port 3000
I'm passing the url like:
<a href={this.state.url}>Download Report</a>
where this.state.url looks like /reports/download/users and make sense its pointing to http://3000/reports/download/users
Any idea how to create the links in dev to point to the port 8080.
Updated
The proxy is working with a request like the below code:
fetch('./app/admin/reports/availableReports')
.then(res => res.json())
.then(json => json.reportTypes)
.catch(ex => {
console.log('Alert!!', ex)
return []
})
But its not working when I generate a url link:
<a href={'app' + this.state.currentDownloadUrl}>Download Report</a>
I used one not a very good solution I think, but it works for me.
<a href={`http://localhost:8000${record_detail_item.file}`} download>Download File</a>
You can have some global variable which points to your dev server and you can use it instead of http://localhost:8000
Update:
Instead of hardcoding URL, you can set up environment variables Create-react-app environment variables
You shouldn't use the proxy property to set the backend base url. As per the doc:
Keep in mind that proxy only has effect in development (with npm start), and it is up to you to ensure that URLs like /api/todos point to the right thing in production.
When you build your app, it won't work.
You should add an environment variable for your backend base URL and prepend it when you make backend calls.
Something like
fetch(`${process.env.REACT_APP_API_ENDPOINT}/app/admin/reports/availableReports`)
.then(res => res.json())
.then(json => json.reportTypes)
.catch(ex => {
console.log('Alert!!', ex)
return []
})
<a href={`${process.env.REACT_APP_API_ENDPOINT}${this.state.currentDownloadUrl}`}>Download Report</a>

Resources