How to integrate Gatsby with NodeJs Express Backend - node.js

I have Gatsby as my frontend and NodeJs/Express to fetch API data. I edited gatsby-config.js with the following
module.exports = {
/* Your site config here */
proxy: {
prefix: "/api",
url: "http://localhost:4000",
},
}
to make this work.
It works in my development environment, but not when I run the gatsby production build. When I run the gatsby production build and go to the live production website, the nodeJS API data is not being fetched. I'm I missing a build step.
I do
gatsby build
gatsby serve

From the documentation:
Keep in mind that proxy only has effect in development (with gatsby
develop), and it is up to you to ensure that URLs like /api/todos
point to the right place in production.
In production, you need to send your HTML requests directly to your backend server without a proxy. Use a library like Axios:
Here an example from the axios repo for a POST request:
// Send a POST request
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
You will run into a CORS block by your browser. Your backend needs to set the right response header so your browser will accept the response. In your express app set the cors:
const Express = require("express");
const BodyParser = require("body-parser");
const cors = require("cors");
const app = Express();
app.use(BodyParser.text({ type: "text/plain" }));
/* CORS */
// app.use(cors()); // Enable cors for all origins
app.use(cors({
/** Use this when web frontend / production **/
// origin: 'https://example.com',
/** Use this when local frontend / development **/
origin: "http://localhost:8000",
}));

Related

getting CORS and network error while calling axios post request using Vue js

I am getting error while calling axios post request. But it works properly on postman.
The code I used for calling the request is
methods : {
displayData(){
var config = {
method: 'post',
url: 'http://localhost:5000/api/request/displayRequest',
headers: {
'Content-Type': 'application/json'
},
data : JSON.parse(JSON.stringify(this.user._id))
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
},
async mounted(){
this.displayData()
}
I have already implemented CORS on the back-end in server.js
// Cors Middleware
const cors = require('cors');
app.use(cors());
app.options("*", cors());
app.use(
cors({
origin: (origin, callback) => callback(null, true), // you can control it based on condition.
credentials: true, // if using cookie sessions.
})
);
in your backend use this :
npm i cors
and in your express backend entrypoint:
const cors = require("cors");
app.use(cors());
app.options("*", cors());
You are running your front-end on localhost and using some port. Also, your back-end is running on localhost, port 5000. But your front-end application can not access any other port due to CORS policy. You can solve this problem in the back-end if you are using Node JS.
Install cors by the following command:
npm i cors
Then on your server file, change your app by
app.use(cors());
N.B. If you used React js, you could use http-proxy-middleware. Just create a file inside the src directory named "setupProxy.js". and add the following lines.
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
"/api",
createProxyMiddleware({
target: "http://localhost:5000/",
})
);
};
Don't forget to change the port in this file into the port of your server.

Deploying VueJS app - Back end (ExpressJS) Not Responding

This is my first time deploying a VueJS app. It is full stack, back end is Express/MySQL. All running fine in developer mode. My dev platform is Windows 10, VS Code.
I am currently trying to preview the app on my dev PC using local webserver.
To that end, I built Vue app to server/public. The static site then runs fine, but I can't seem to get the Express back end to respond, either from the app or from browser accessing the api directly. I followed a model from Brad Traversy tutorial, here is what vue.config.js looks like:
const path = require('path');
module.exports = {
outputDir: path.resolve(__dirname, './server/public'),
devServer: {
disableHostCheck: true,
proxy: {
'/api': {
target: 'http://localhost:5000'
}
}
},
transpileDependencies: ['vuetify'],
pluginOptions: {
i18n: {
locale: 'en',
fallbackLocale: 'en',
localeDir: 'locales',
enableInSFC: false,
},
},
};
Here is the index.js for Express/back end. I commented out the NODE_ENV test because I haven't yet figured out how to set it properly. This should just hardwire the code to run in production mode. __dirname points to the server directory, which contains the Express code and other server stuff.
// Create express app
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
//Create Express App
const app = express();
// Add Middleware
app.use(bodyParser.json());
app.use(cors());
//
const water = require('./routes/api/water');
const waterlog = require('./routes/api/waterlog');
// Direct /api
app.use('/api/water', water);
app.use('/api/waterlog', waterlog);
// Handle production
// if (process.env.NODE_ENV === 'production') {
// Static folder
app.use(express.static(__dirname + '/public/'));
// Handle SPA
app.get(/.*/, (req, res) => res.sendFile(__dirname + '/public/index.html'));
// }
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`CORS-EnabledServer started on port ${port}`));
I use (from npm serve) this to start the Vue app:
serve -s server/public
What am I missing? Feels very close but no cigar yet...
serve is just a simple, static HTTP server. It won't run your backend.
Your production build puts your front-end assets into your Express app's statically served directory so all you should need to do after building the front-end is start your server
# Build your front-end
npm run build
# Start your Express server, assuming this is configured in package.json
NODE_ENV=production npm start
Now open http://localhost:5000/ in your browser
See also https://expressjs.com/en/advanced/best-practice-performance.html#set-node_env-to-production

CORS giving issues once I went from localhost --> heroku

I have a chat application where my client side is written in Reactjs and my backend is written in Nodejs/Express. I have required cors and everything on my backend and the entire application worked perfectly when I was using localhost:3000 for the client and localhost:5000 for the server. I then deployed the server to heroku and the client to netlify, and now I am getting this CORS error every time I try to log in using a POST request (using axios as well):
Under the network tab on chrome, I get two things, a "signin" that has 204 and it works, and then a "signin" that just says error.
This is what my backend looks like in Nodejs/express:
require('dotenv').config()
const http = require('http');
const cors = require('cors');
const hostname = '127.0.0.1';
const port = process.env.PORT || 5000;
const express = require('express');
const jwt = require('jsonwebtoken')
const cookieParser = require('cookie-parser');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const {AddUser, FindUser, RemoveUser, FindId} = require('./users.js')
var corsOptions = {
origin: ['http://localhost:3000', 'https://easytalkchat.netlify.app'],
credentials: true,
methods: ['GET', 'POST', 'OPTIONS', 'PUT', 'DELETE'] };
app.use(cors(corsOptions));
app.use(express.json())
app.use(cookieParser());
//Tells the server what port to listen to and can add a function to talk to command line
server.listen(port, () => {
console.log("Server is up!");
});
What I THINK might be the problem is maybe I'm not setting up the server using https, because I'm doing it with http. Maybe this is causing the problem but I don't know how to fix it. Other people have also mentioned it might not be a problem with CORS but rather Heroku, since Heroku only installs devDependencies or something like that, but I don't know how to fix that either.
I've tried adding headers, credentials, everything, I have no clue.
My front end looks like this:
const signIn = (e) => {
e.preventDefault();
axios.post('https://easytalkchatapp.herokuapp.com/signin', {
username: username,
password: password
}).then(res => {
...
and I have axios.defaults.withCredentials = true written at the top.
And just to re-state above, if I literally go to terminal and just run my server on localhost:5000 instead of heroku and make all my POST/GET requests through the localhost:500 server it works completely fine. If, however, I run my client on localhost:3000 and have the server be heroku, it breaks, so the problem is most certaintly with heroku and how I'm using it.
Since, you are using withCredentials, so I thinks its better to provide specific values for origin instead of true or '*' because it will not work with credentials true.
Try using this options:
var corsOptions = {
origin: ['http://localhost:3000', 'https://easytalkchat.netlify.app'],
credentials: true,
};
I hope it helps.
if you use withCredentials= true and when you run frontend and backend both form localhost, it runs perfectly because they are in the same origin
but if you run frontend and backend from different origin(host) in that time it gives you cors issue. for resolve this issue you have to whitelist the frontend origin in the backend
var corsOptions = {
origin: ['http://localhost:3000', 'https://easytalkchat.netlify.app'],
credentials: true,
};
by this way backend now trust the frontend origin
It turns out it was completely my own fault with my backend code. I was using process.env.(variable) and I had never specified it in the heroku config vars so it kept breaking when trying to access it. UGH. Thanks everyone.

How to fix "Response to preflight request doesn't pass access control check: It does not have HTTP ok status" error in react app with nodejs api

I have been trying to do an api call (nodejs with express running on localhost) from a react app running in the browser over a local dev server (web-pack dev server). Everything was working well until I tried to call the api. They are both running on separate ports.
I have tried adding the cors headers (Recommended by MDN) to both the post call (from the app in browser) and to the response from the Nodejs API but neither of these solved the issue.
Code for the api call (in browser):
const headers = {
'Content-Type': 'application/json',
'access-token': '',
'Access-Control-Allow-Origin': '*',
}
export default async () => {
try {
const body = JSON.stringify({
test: true,
})
const response = await fetch('http://localhost:1337/internal/provider/check_email_exist', {
method: 'POST',
headers,
body,
})
console.log(response)
} catch (e) {
return e
}
}
API Middleware (in nodejs):
// Verify All Requests
app.use(VerifyToken)
// Compress
app.use(compression())
// Helmet middlware
app.use(helmet())
// Body Parser
app.use(bodyParser.urlencoded({
extended: false,
}))
app.use(bodyParser.json())
The expected result is to just give a 200 status code and respond with the data.
The actual output is:
OPTIONS http://localhost:1337/internal/provider/check_email_exist 404 (Not Found)
Access to fetch at 'http://localhost:1337/internal/provider/check_email_exist' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Since you're using webpack-dev-server you can use the proxy option DevServerProxy.
Your configuration will look like this:
// webpack.config.js
devServer: {
proxy: {
'/internal': 'http://localhost:1337'
}
}
Since I can't see your express routes on your question I'm speculating about the proxy route if your API lives on /internal endpoint then you should modify your React code like this:
const response = await fetch('/internal/provider/check_email_exist', {
method: 'POST',
headers,
body,
})
As you can see I ommited the https://localhost:1337 because the proxy option from webpack-dev-server will handle this and it will redirect to http://localhost:1337. Hope this will help you. Cheers, sigfried.
EDIT
As the comment on your question pointed out you should set the headers on your express server, not the client, for this task you can use the cors-middleware package.
Maybe this can help if you face with preflight errors.
My full config:
const cors = require('cors');
const express = require('express');
const { createProxyMiddleware: proxy } = require('http-proxy-middleware');
...
const logLevel = 'info';
const ip = require('ip').address();
const proxyOptions = {
xfwd: true,
target,
changeOrigin: true,
logLevel,
cookieDomainRewrite: {
'*': 'localhost',
},
headers: {
'X-Forwarded-For': ip,
'X-Node': 'true',
},
};
const backNginxApp = express();
backNginxApp.use(
cors({
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
origin: 'http://localhost:3000',
optionsSuccessStatus: 200,
credentials: true,
})
);
backNginxApp.use('/api', proxy(proxyOptions));
API: const target = 'https://someapi.com'
Local development running at: http://localhost:3000

Proxy in package.json not affecting fetch request

I am trying to fetch some data from the development server using React.
I am running the client on localhost:3001 and the backend on port 3000.
The fetch request :
const users = fetch('/api/users');
users.then((err,res) => {
console.log(res);
})
When I run my development server and webpack-dev-server I get the following output:
GET http://localhost:3001/api/users 404 (Not Found)
I tried specifying the proxy in the package.json so it would proxy the request to the API server, however nothing has changed.
Here is my package.json file:
.. and the webpack.config :
Please tell me, if you need to see anything else from my project. I apologies, if I'm missing something and not being thorough, I'm still quite new to using these technologies.
You can modify your fetch request API url to give the complete hostname since
fetch('http://localhost:3000/api/users')
also make sure that you have CORS enabled on your backend
In case your want to redirect through webpack, your can try devServer.proxy as
devServer: {
inline: true,
contentBase: './dist',
port: 3001,
proxy: { "/api/**": { target: 'http://localhost:3000', secure: false } }
}
I know I'm a little late to the game here, but I'll leave it here for future reference.
To make the devServer proxy work as expected, you need to specify the HTTP Accepts header to be something else than "text/html". Do this with the init-object that fetch accepts as the second argument. A simple example:
fetch("/api/profile",{
headers:{
"accepts":"application/json"
}
})
.then(res => {
console.log(res);
return res.json();
})
.then(json => console.log(json) )
.catch( a => { console.log(a) });
The reason for this is that the WebPack Dev Server normally uses a context/namespace to differentiate between what to serve and what to forward. The create-react-app scripts do not extract a namespace from the proxy path in the package.json file. Instead the scripts has the opinionated default behaviour that any request using something else than HTTP GET will get forwarded. Also, anything using HTTP GET, but NOT text/html as the Accepts header will get forwarded.
The reasoning is because most React Apps are SPA (Single Page Applications) which use AJAX/Fetch to communicate with some API. API's normally use JSON or XML, but not text/html.
In the package.json
"proxy": {
"/api/users": {
"target": "http://localhost:3000"
}
},
I had the same problem using axios and was only able to get it working by using the complete hostname and enabling Cors.
const response = await axios.get('http://localhost/users/');
Install cors
npm i cors
Use cors
const express = require("express");
const request = require("request");
const cors = require("cors");
const app = express();
app.use(cors());
app.use("/", (req, res) => {
//...
});
app.listen(80, () => {
console.log("CORS-enabled web server listening on port 80");
});
Ref
The solution by user jellyfish-tom in https://github.com/webpack/webpack-dev-server/issues/793#issuecomment-316650146 worked for me.
devServer: {
proxy: {
"*": "http://[::1]:8081"
// "secure": false,
// "changeOrigin": true
}
},
Webpack Dev Server uses devServer.proxy config in your Webpack config to control proxying requests.

Resources