Avatar of Bruce Gust
Bruce Gust
Flag for United States of America asked on

Why Does This Make a Difference?

Here's my initial code:

app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader(
    'Access-Control-Allow-Methods',
    'GET, POST, PUT, PATCH, DELETE'
  );
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
  next();
});

Open in new window


This is part of a Node.js tutorial I'm going through. It's a React front end that interacts with an API which utilizes GraphQL.

The code that I've got above is from the "app.js" file that's a part of the API. I've got the code in its entirety below:

const path = require("path");

const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const multer = require("multer");
const graphqlHttp = require('express-graphql');

const graphqlSchema = require('./graphql/schema');
const graphqlResolver = require('./graphql/resolvers');

const app = express();

const fileStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "images");
  },
  filename: (req, file, cb) => {
    //cb(null, uuidv4());
    cb(null, file.originalname);
  }
});

const fileFilter = (req, file, cb) => {
  if (
    file.mimetype === "image/png" ||
    file.mimetype === "image/jpg" ||
    file.mimetype === "image/jpeg"
  ) {
    cb(null, true);
  } else {
    cb(null, false);
  }
};

app.use(bodyParser.json());
app.use(
  multer({
    storage: fileStorage,
    fileFilter: fileFilter
  }).single("image")
);
app.use("/images", express.static(path.join(__dirname, "images")));

app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader(
    'Access-Control-Allow-Methods',
    'GET, POST, PUT, PATCH, DELETE'
  );
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
  if(req.method==='OPTIONS') {
	  return res.sendStatus(200);
  }
  next();
});

app.use(
	'/graphql', 
	graphqlHttp({
		schema: graphqlSchema, 
		rootValue: graphqlResolver, 
		graphiql:true, 
		formatError(err) {
			if(!err.originalError) {
				return err;
			}
			const data = err.originalError.data;
			const message = err.message || 'An error occurred.';
			const code = err.originalError.code || 500;
			return { message: message, status: code, data: data };
		}
	})
);

app.use((error, req, res, next) => {
  console.log(error);
  const status = error.statusCode || 500;
  const message = error.message;
  const data = error.data;
  res.status(status).json({ message: message, data: data });
});

mongoose
  .connect(
    "my database"
  )
  .then(result => {
    const server = app.listen(8080);
  })
  .catch(err => console.log(err));

Open in new window



Everything about the app is sound, as far as there being no syntactical errors. But every time I attempted to set up a user, I would get this error:

Access to fetch at 'http://localhost:8080/graphql' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

After researching what CORS was and trying different things, I downloaded the sample code from the tutorial and was able to identify this one line as being the "thing" that made all the difference. I've got it in bold below:

app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader(
    'Access-Control-Allow-Methods',
    'GET, POST, PUT, PATCH, DELETE'
  );
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
[b] if (req.method === 'OPTIONS') {
    return res.sendStatus(200);
  }[/b]
  next();
});

Open in new window


At that point, the error went away.

Why?
Node.jsJavaScript

Avatar of undefined
Last Comment
Bruce Gust

8/22/2022 - Mon
Zvonko

Extend this:   Access-Control-Allow-Methods

Add: OPTIONS

Bruce Gust

ASKER
OK, I was able to get some more information.

Apparently, GraphQL automatically denies anything that isn't a GET or a POST request. Hence, anything that falls into the category of "options" is processed as a problem.

By including the aforementioned IF statement and returning a status code of 200, we're able to circumvent all of that.

But if I'm adding a user, is that not a POST request? Why do "OPTIONS" solve the problem?
ASKER CERTIFIED SOLUTION
Zvonko

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
SOLUTION
Chris Stanyon

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
SOLUTION
Julian Hansen

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Zvonko

Hello Bruce, you handled the CORS Request Methot OPTIONS yourself in your app.

For that is a npm package: cors


I got this info from here:
https://medium.com/@dvelasquez/handle-an-options-request-with-cors-in-node-js-f3f81c5a7494



Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
Bruce Gust

ASKER
Excellent, gentlemen!

Thank you!