How to execute external API calls with React + Express on Heroku - reactjs

I’m still fairly new to full stack development and I’ve been stuck for days. I could really use some help from anyone who is familiar with React + Express + External API projects. Right now I still have my frontend and backend working concurrently and works fine on my local machine,
https://mernaddonsapp.herokuapp.com
the login and register are working with connected to mongodb alas on heroku but the external api is not working.
I've tried with heroku local, which I think runs the code on heroku locally, and everything works just fine. As for my client I served the files locally with "yarn build" and then "serve -d build" and it works.
but when I deployed the mern app to heroku I get no data sent to the front end from the external api in the back end.
this is the back end code in express
router.get('/filterByValue', (req, res) => {
let url = `https://restcountries.eu/rest/v2/all`;
let search = req.query.search;
axios({
method: 'get',
url,
})
.then((response) => {
var listofcountries = filterByValue(response.data, search);
console.log(listofcountries);
res.status(200).json(listofcountries);
})
.catch((error) => {
console.log(error);
});
});
and this is the front end code in react
filtersearch = async (e) => {
console.log(e.target.value)
if (e.key === "Enter") {
try {
const response = await axios.get(`/api/countries/filterByValue/?search=${this.state.s}`
)
this.setState({
specificCountry: response.data
})
this.props.history.push('/FilterListOfCountries', { response: this.state.specificCountry })
console.log(response)
} catch (e) {
console.log(e.message)
alert(e.message)
}
}
}

Related

How can I deal with CORS issue with create-react-app?

I'm trying to get data from images.google.com with axios.get on my create-react-app application and hosting by firebase.
This is the function of getting request results data from the URL.
const getImage = (transcript) => {
console.log("getImage executed,", transcript[transcript.length-1])
axios.get(`/images?&um=1&hl=en&nfpr=1&q=${transcript[transcript.length-1]}`)
.then((res)=> {
const search = document.querySelector(".search");
search.innerHTML = res.data;
search.querySelectorAll("img").forEach((element) => {
if(element.hasAttribute("data-src")){
const firstImage = element.getAttribute('data-src');
images.push(firstImage);
setSearchResult(images[images.length-1]);
}
});
console.log(res);
})
.catch((error) => {
console.log(error);
})
}
and on package.json I added
"proxy": "https://images.google.com"
but of course still blocked by CORS.
error
I know this is wrong and I think I don't understand the concept of middleware or backend server stuff enough.
So is there any idea to solve this problem in an easy way? Thanks.

Can I create a local API?

I'm learning about fetch and promises on reactjs, and sometimes I had a problem with my internet connection. So is it possible for me to create my own API but still can use or call it with fetch() function?
You could use mocking tools to mock the APIs.
One such example is https://mockoon.com/
You can setup a local server and use fetch() to pull from localhost.
This is an example Node server:
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('test')
})
const server = app.listen(8081, () => {
console.log("Example app up")
})
You can then fetch() from localhost:8081
We can locally read the JSON data using fetch API in JavaScript. If you are using react hooks, place it inside the useEffect hook.
Check the console in this code sample link
Code: Your data.json will contain the sample JSON data.
fetch("./data.json")
.then(function (response) {
return response;
})
.then(function (data) {
return data.json();
})
.then(function (finalData) {
console.log(finalData);
})
.catch(function (err) {
console.log("Fetch problem show: " + err.message);
});

React App deployed on Digital ocean gives 404 Error

I have a validation form on React but on clicking submit m getting "404 Error".
It works perfect on local machine.
//from app.js
handleSubmit = async e => {
e.preventDefault();
const response = await fetch('/api/emailVerifier', {
method: 'POST',
body: this.state,
headers: {
'Content-Type': 'application/json',
},
//body: JSON.stringify({ post: this.state.post }),
});
const body = await response.text();
this.setState({ responseToPost: body });
};
//from server.js
app.post('/api/emailVerifier', async (req, res) => {
console.log(req.body);
const emailValidator = new EmailValidator();
const { wellFormed, validDomain, validMailbox } = await emailValidator.verify(req.body.post);
res.send(
`response received , welllformed = ${wellFormed}, validDomain = ${validDomain}, validMailbox = ${validMailbox}`,
);
});
i have installed my my validator on server using npm i add deep-email-validator --save
My Directory on server has
asset-manifest.json index.html manifest.json package.json static
build logo192.png node_modules robots.txt
favicon.ico logo512.png package-lock.json server.js
Can you access other endpoints in server.js on DigitalOcean? EG: if you create:
app.get('/', function (req, res) {
res.send('hello world')
})
And make a request to it from your React app does it reach that endpoint?
I think you will struggle to run the React app and server from the same location.
If your React app is setup correctly it will try to handle all requests coming to that url.
You could run the express server on a different port to the React app. Then traffic won't get routed to both the React server and your Express server.

Combining a ExpressJS Router endpoint with a fetch call to an external enpoint

I am trying to create an Express Router endpoint that will return the CSV file from an external API (Jenkins in this case)
In more detail, what I am trying to achieve is to have a React Frontend call this route on the Express backend and download a CSV file.
BACKEND
The Express route is has this structure:
router.get('/path/latestCsvTestReport', async (req, res) => {
const { channel } = req.params;
return fetch(
`${jenkinsHost}/job/${channel}/${jenkinsPath}/lastSuccessfulBuild/artifact/test_result/report_test.csv`, {
...fetchOptions,
headers: { Authorization: jenkinsAuth},
},
)
.then(r => {
console.log('====== DATA =====', r);
res.setHeader('Content-type', 'text/csv');
res.setHeader('Cache-Control', 'no-cache');
res.send(r)
})
.catch((err) => {
// console.log(err);
res.status(404);
res.send('report not found');
});
});
and the URL called in the fetch returns a CSV file.
FRONTEND
I am calling the Express endpoint from a method on the React frontend using the following function, which utilised the file-saver library:
async function triggerReportDownload(chlId) {
console.log('===== CSV Request ====')
const resource = `/api/jenkins/${chlId}/latestCsvTestReport`;
saveAs(resource, "report.csv")
}
which is triggered by the click of a button on the FrontEnd.
At the moment, the button, triggers a download but the csv downloaded only contains:
{"size":0 timeout:0}
I am certain I am doing something completely wrong on the way the backend returns the CSV from the fetch call, but for the life of me I do not seem to be able to find the way to formulate the response. Any help/direction towards fixing this would be greatly appreciated.
The solution to this is to simply things as possible (being a newbie I had overcomplicated things). So here we are:
Backend
Import the utils library and then create a stream:
import util from 'util';
const streamPipeline = util.promisify(require('stream').pipeline);
This is then called from the Express router:
router.get('/jenkins/:channel/latestCsvTestReport.csv', async (req, res) => {
const { channel } = req.params;
const response = await fetch(
`${jenkinsHost}/job/${channel}/${jenkinsPath}/lastSuccessfulBuild/artifact/test_result/report_test.csv`, {
...fetchOptions,
headers: { Authorization: jenkinsAuth },
},
);
res.setHeader('Content-disposition', `attachment; filename=report_test_${Date.now()}.csv`);
res.set('Content-Type', 'text/csv');
return streamPipeline(response.body, res);
});
Frontend
Use windows.open to get the download file
async function triggerReportDownload(chlId) {
window.open(`/api/jenkins/${chlId}/latestCsvTestReport.csv`);
}

React Native: Why isn't this invocation of fetch working?

I have the following invocation of fetch in my React Native app:
test = async () => {
try {
let a = await fetch('https://rxapitest.alliancepharmacygroup.ca:12345/', {
method,
}).then(response => {
console.log("success")
})
} catch(err) {
console.log("error")
}
}
Normally I'm hitting actual endpoints from this API with a bearer token, but none of them is working, so I tried the more basic task of just hitting the web page itself. When I run this from Postman it works fine. I'm using React Native v0.62.1.
Does anyone know how I can approach this?

Resources