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.
Related
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`);
}
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)
}
}
}
I'm trying to upload an image as form-data to a Nextjs api route. I use the package formidable to parse and save the file in a server folder. For the http request I use postman on the client.
Here ist the backend code:
import formidable from 'formidable';
export const config = {
api: {
bodyParser: false,
},
};
export default async (req, res) => {
const form = new formidable.IncomingForm();
form.on('fileBegin', (name, file) => {
file.path = "./" + file.name
});
form.parse(req, (err, fields, files) => {
console.log( files);
});
res.statusCode = 200
res.end()
};
The image (jpeg) is saved in the folder. However, it appears to be corrupt or damaged.
Here is the original image:
source image
corrupt image
Next.js need the package formidable-serverless instead of formidable
https://github.com/node-formidable/formidable/issues/629
I have built and deployed a basic portfolio website to Heroku. In this app, I use a third-party API for sending emails (sendgrid) in the contact form. When I was running my app locally on localhost:3000, the API was working as anticiapted and would send me emails. However, once I deployed my app to Heroku, I recieve this error. When I run heroku logs --tail in my terminal, I get this.
Inexcplicably, the API has now stopped working when I run it locally as well. I see error 503 means network error so I am somehow not making a request to the server? The only thing I have changed that I could think would break it is:
I removed the react router to change pages and instead used react-scroll. Maybe this messed with the routes I use in my contact.js file to send the object to sendgird?
I moved my API key to .env rather than storing it in my global environmental variables. I've used dotenv to transpile this but maybe i went wrong somewhere? When I run console.log(process.env.REACT_APP_SENDGRID_API_KEY), it logs the correct key.
This is where I call the API from the contact.js form:
emailApi = () => {
let sendgridObj = {
to: 'caseyclinga#gmail.com',
from: this.state.from,
subject: this.state.subject,
text: this.state.text
}
this.resetState();
axios.post('/', sendgridObj)
.then(res => console.log(`CONTACT.JS RESPONSE: ${res}`))
.catch(err => console.log(`CONTACT.JS ERROR: ${err}`));
}
This is the server.js file:
const express = require('express');
var app = express();
const SgMail = require('#sendgrid/mail');
const path = require('path');
require('dotenv').config();
SgMail.setApiKey(process.env.REACT_APP_SENDGRID_API_KEY);
//Middleware
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const PORT = process.env.PORT || 5000;
//Serve static assets if in production
if(process.env.NODE_ENV === 'production') {
//Set static folder
app.use(express.static('client/build'))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
app.post('/', (req, res) => {
console.log(req.body)
SgMail.send(req.body)
.then(res => console.log(`SERVER.JS RESPONSE: ${res}`))
.catch(err => console.log(`SERVER.JS ERROR: ${err}`));
});
app.listen(PORT, () => console.log(`Server running on port ${PORT}`))
Here is my deployed site: https://still-sands-49669.herokuapp.com/
Here is my code: https://github.com/caseycling/portfolio
What I'm trying to do is deploy react / apollo-server full stack app to heroku. Thus I' trying to serve static client files from express/apollo-server backend, like this:
const path = require('path');
const express = require('express');
const app = express();
const cors = require('cors');
const { ApolloServer } = require('apollo-server');
const { schema } = require('./schema');
const { resolvers } = require('./resolvers');
app.use(cors());
app.use(express.static('public'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'public', 'index.html'));
});
const server = new ApolloServer({
typeDefs: schema,
resolvers,
});
server.listen({ port: process.env.PORT || 4000 }).then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
For some reason I don't understand client is not served while deployed to heroku. On heroku URL I'm getting: GET query missing. If I set graphql to enabled in production I can see it, I can play with resolving data. But client is not rendered. I'm guseing app.get with * is not working and then index.html is not catched.
How can I fix that?
Thanks!
The error you are getting is because you are only exposing the server from ApolloServer to the port 4000 and not exposing the app with the frontend client application.
In order to have the fullstack app deployed, you also have to expose the app, in order to do that you can use applyMiddleware from ApolloServer and bind both apollo server and the frontend client, something like:
.....
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'public', 'index.html'));
});
const server = new ApolloServer({
typeDefs: schema,
resolvers,
});
server.applyMiddleware({
path: '/my-frontend', // you should change this to whatever you want
app,
});
app.listen({ port: process.env.PORT || 4000 }, () => {
console.log(`🚀 Server ready at http://localhost:4000`);
});
Now you should be able to navigate to http://localhost:4000/my-frontend and see your client application.