Link to home
Start Free TrialLog in
Avatar of Bruce Gust
Bruce GustFlag 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?
Avatar of Zvonko
Zvonko
Flag of North Macedonia image

Extend this:   Access-Control-Allow-Methods

Add: OPTIONS

Avatar of 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
Avatar of Zvonko
Zvonko
Flag of North Macedonia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

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



Excellent, gentlemen!

Thank you!