I am trying to enable CORS to connect my nestJS API with a local react app. But it seems that CORS is blocking access from the React App.
I've tries this so far:
First attempt:
async function bootstrap() {
const app = await NestFactory.create(AppModule, { cors: true });
app.listen(3000);
}
bootstrap();
Second attempt:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
methods: ["GET", "POST"],
origin: '*',
})
app.listen(3000);
}
bootstrap();
And third attempt:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
methods: ["GET", "POST"],
origin: 'http://localhost:3001/',
})
app.listen(3000);
}
bootstrap();
Nothing of that seems to work.
The React app is just a simple superagent call like this:
const res = sa.get(`http://localhost:3000/jokes/random`).withCredentials().end(res => console.log(res))
I've tried to use the superagent with and without the withCredentials.
Any idea of what is going on? thank you.
Related
I'm trying to fetch data from my Express API but I'm keep getting this error.
Firefox Console Error
Chrome Console Error
I have tried everything I find on internet.
I tried using different browser, browser extensions to bypass CORS check.
I thought maybe the issue is related to localhost, so I deployed it, but the same issue persisted.
I tried mockup API with the same frontend, and it fetches data just fine.
I tried manually adding Access-Control-Allow-Origin header on server side but did not work.
I also tried CORS middleware for Express and again did not work.
I'm getting proper responses with Postman just fine, but not within a browser.
This is my code on client side:
async create(visit) {
this.setState({visits: [...this.state.visits, {...visit}]})
fetch('http://localhost:8000/create-visit', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: `{"params": ${JSON.stringify(visit)}}`
})
.then(resolve => resolve.json())
.then(result => {console.log(result)})
}
I also tried GET request with but no difference.
And this is my server side code:
const express = require('express')
const visitRouter = require('./routers/visits')
const cors = require('cors')
const PORT = process.env.PORT;
const app = express();
var corsOptions = {
credentials: true,
origin: "*",
preflightContinue: true,
allowedHeaders: 'GET,PUT,POST,DELETE,OPTIONS'
}
var logger = function(req, res, next) {
console.log(res)
next()
}
app.use(logger)
app.use(express.json())
app.use(visitRouter)
// app.use((req, res, next) => {
// res.append('Access-Control-Allow-Origin', ['*'])
// res.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
// res.append('Access-Control-Allow-Headers', 'Content-Type')
// next()
// })
// app.use(cors())
app.use(cors(corsOptions))
app.listen(PORT, () => {
console.log(`Listening from port: ${PORT}`)
})
Router:
const express = require('express')
const router = new express.Router()
const visitModel = require('../models/visits')
router.post('/create-visit', async (req, res) => {
try {
const params = req.body.params
console.log(params)
const newVisit = await visitModel.createVisit(params)
res.status(201).send(newVisit)
} catch (err) {
res.status(500).send(err)
}
})
// main.ts
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
// tried with config passed in
app.enableCors({ origin: true });
app.enableCors({ origin: '...' });
// tried setting it in the app
const app = await NestFactory.create(AppModule, { cors: true });
const app = await NestFactory.create(AppModule, { cors: { origin: true } });
const app = await NestFactory.create(AppModule, { cors: { origin: '...' } });
await app.listen(8080);
}
bootstrap();
I've tried every documented method of enabling CORS, none of them have worked.
I'm using NestJS with Express. The request is being sent by Axios.
The OPTIONS request is 404ing.
Hi I'm trying to upload a file to a server send with axios. To send it I use react with Hooks and UseState, the thing is that when I do the console.log of the file in de frontend it shows all correctly but when I send it to backend I recive it empty.
Here is an example about what shows the frontend with console.log():
Here is the function I use to send the 3 files to backend and the differents things like react Hooks and that which I need:
const [weight, setWeight] = useState("");
const [frontPhoto, setFrontPhoto] = useState({});
const [sidePhoto, setSidePhoto] = useState({});
const [backPhoto, setBackPhoto] = useState({});
const JWT = new ClassJWT();
const axiosReq = axios.create();
const [uploadErrors, setUploadErrors] = useState([{}]);
const upload = async (e) => {
e.preventDefault();
await JWT.checkJWT();
console.log(frontPhoto);
axiosReq.post("http://localhost:3001/upload-progress", {
weight,
frontPhoto,
sidePhoto,
backPhoto,
token: JWT.getToken()
}).then((response) => {
console.log(response);
if (response.data.statusCode === '200') {
} else {
}
});
};
And then, in the backend de console.log() is like this:
{
weight: '70',
frontPhoto: {},
sidePhoto: {},
backPhoto: {},
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjI2NTk3Mjg1LCJleHAiOjE2MjY1OTgxODV9.njDz7BZX57NvAK399abQLhoelpTS4kStj4LBzjw5gR8'
}
Here is the router code I use to this upload:
routerProgress.post("/upload-progress", verifyJWT, async (req, res) => {
console.log(req.body);
}
And here is all the server configuration:
import express from 'express';
import sequelize from './db/db.js';
import cors from 'cors';
import fileUpload from 'express-fileupload';
// SERVER CONFIGURATION
const app = express();
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`Listening at ${PORT}`);
sequelize.sync({ force: false })
.then(() => console.log('Database Connected!'))
.catch(err => console.log(err));
});
// BODYPARSER
app.use(express.json({limit: '50mb'}));
app.use(express.urlencoded({ limit: '50mb', extended: true, parameterLimit: 50000}));
app.use(cors({
origin: ["http://localhost:3000"],
methods: ["GET", "POST"],
credentials: true
}));
app.use(fileUpload({
createParentPath: true
}));
// ROUTES
import { routerAuthentication } from './routes/authentication.js';
import { routerProgress } from './routes/progress.js';
app.use(routerAuthentication);
app.use(routerProgress);
I don't know how to solve it, I tried many things but anything doesn't word. Please if anyone know what can I do to solve it, I'll be very grateful with him. Thanks!
Heroku backend Node.js and Netlify frontend react app has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I've seen a lot of posts on this, but I just can't seem to fix what's creating this error. Of course, I believe it has to do with CORS. But as you can see, I've added multiple versions of CORS middleware to allow this to work. Locally everything is fine. Production/live is where I get the issue:
Access to XMLHttpRequest at 'https://seb-youtube-api.herokuapp.com//videos?page=1&limit=50' from origin 'https://seb-youtube-api.netlify.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here is my backend server with Node.js and Express.js
They make a simple call to a youtube API.
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser')
const app = express();
const cors = require('cors')
const chalk = require('chalk');
const { google } = require('googleapis');
const youtube = google.youtube('v3'); // initialize the Youtube API library
// Middleware
app.use(cors());
app.use(bodyParser.json());
/******************** GET REQUEST TO VIDEOS *********************/
app.get('/videos', async (req, res) => {
const results = await fetchYoutubePlaylist();
res.json(results)
})
// /******************** POST REQUEST, USER SEARCH *********************/
app.post('/videos', async (req, res) => {
console.log('POST QUERY',req.body)
const query = req.body
res.body = await fetchYoutubeSearch(query)
console.log("RES POST", res.body)
res.json(res.body)
})
app.use('*', cors(), (req, res) => {
return res.status(404).json({ message: 'Not Found' });
});
// CORS
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type,multipart/form-data,Authorization');
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE');
if (req.method === 'OPTIONS') {
return res.send(204);
}
next();
});
/******************** FIRST YOUTUBE API CALL *********************/
const fetchYoutubePlaylist = async () => {
try {
const {data} = await youtube.playlistItems.list({
key: process.env.YOUTUBE_API_TOKEN,
part: ['snippet'],
maxResults: 50,
playlistId: "UUBh8XcZST_JTHt-IZDxT_pQ"
})
console.log(data)
return data.items
} catch(err) {
console.log(chalk.red(err))
}
}
/******************** SECOND YOUTUBE API CALL *********************/
const fetchYoutubeSearch = async ({query}) => {
console.log(query)
try {
const {data} = await youtube.search.list({
key: process.env.YOUTUBE_API_TOKEN,
part: ['snippet'],
q: query,
channelId: 'UCBh8XcZST_JTHt-IZDxT_pQ',
order: 'date',
type: 'video',
maxResults: 50
})
console.log('YOUTUBE SEARCH', data)
return data.items
} catch(err) {
console.log(chalk.red(err))
}
}
/******************** LIST TO PORT *********************/
const port = process.env.PORT || 3001;
app.listen(port, () => console.log(`Listing on port ${port}`));
Is the issue that your browser is blocking CORS? That happens to me with Heroku stuff sometimes. There are browser extensions to block/unblock CORS depending on the browser you're using
Stick only with app.use(cors()); that alone should work fine. Instead double check your Config Vars (env vars) on heroku and/or netlify wherever you set such variables. Sometimes that CORS error can be misleading being actually a connection error more about your environment variables.
So I am migrating to apollo-server-express 2.3.3 ( I was using 1.3.6 )
I've followed several guides, making the necessary tweaks but am stuck in a CORS issue.
According to the docs you have to use the applyMiddleware function to wire up the apollo server with express.
I am currently doing the following:
const app = express();
// CORS configuration
const corsOptions = {
origin: 'http://localhost:3000',
credentials: true
}
app.use(cors(corsOptions))
// Setup JWT authentication middleware
app.use(async (req, res, next) => {
const token = req.headers['authorization'];
if(token !== "null"){
try {
const currentUser = await jwt.verify(token, process.env.SECRET)
req.currentUser = currentUser
} catch(e) {
console.error(e);
}
}
next();
});
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({ Property, User, currentUser: req.currentUser })
});
server.applyMiddleware({ app });
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
})
For some reason my express middleware doesn't seem to be executing, when I try to do a request from localhost:3000 (client app) I get the typical CORS error
With apollo-server-express 1.3.6 I was doing the following without no issues:
app.use(
'/graphql',
graphqlUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }),
bodyParser.json(),
graphqlExpress(({ currentUser }) => ({
schema,
context: {
// Pass Mongoose models
Property,
User,
currentUser
}
}))
);
Now with the new version, event though the docs make this look like a straightforward migration, I don't seem to be able to make it work. I've checked various articles and no one seems to be having the issue.
From my understanding of the Apollo Server middleware API, CORS options, body-parser options and the graphql endpoint are treated as special entities that must be passed directly to the applyMiddleware param object.
So you want to try the following configuration:
const app = express();
// CORS configuration
const corsOptions = {
origin: 'http://localhost:3000',
credentials: true
}
// The following is not needed, CORS middleware will be applied
// using the Apollo Server's middleware API (see further below)
// app.use(cors(corsOptions))
// Setup JWT authentication middleware
app.use(async (req, res, next) => {
const token = req.headers['authorization'];
if(token !== "null"){
try {
const currentUser = await jwt.verify(token, process.env.SECRET)
req.currentUser = currentUser
} catch(e) {
console.error(e);
}
}
next();
});
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({ Property, User, currentUser: req.currentUser })
});
// There is no need to explicitly define the 'path' option in
// the configuration object as '/graphql' is the default endpoint
// If you planned on using a different endpoint location,
// this is where you would define it.
server.applyMiddleware({ app, cors: corsOptions });
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
})
With Apollo Server 2.x you supply the cors field in the constructor of ApolloServer.
So in your case, it should look like the following:
const corsOptions = {
origin: 'http://localhost:3000',
credentials: true
}
// Setup JWT authentication middleware
app.use(async (req, res, next) => {
const token = req.headers['authorization'];
if(token !== "null"){
try {
const currentUser = await jwt.verify(token, process.env.SECRET)
req.currentUser = currentUser
} catch(e) {
console.error(e);
}
}
next();
});
const server = new ApolloServer({
typeDefs,
cors: cors(corsOptions),
resolvers,
context: ({ req }) => ({ Property, User, currentUser: req.currentUser })
});
server.applyMiddleware({ app });
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
})
Here you find all params accepted by the apollo server:
https://www.apollographql.com/docs/apollo-server/api/apollo-server.html#Parameters-2
Here you find the relevant discussion:
https://github.com/apollographql/apollo-server/issues/1142
The CORS settings come from ExpressJS, not from ApolloServer. If you want to add a custom or wildcard origin you have to handle it with a callback/handler function.
const server = new ApolloServer({
....,
cors: {
credentials: true,
origin: (origin, callback) => {
const whitelist = [
"http://site1.com",
"https://site2.com"
];
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error("Not allowed by CORS"))
}
}
}
});
By default, the express middleware will instantiate cors middleware with default options on the graphql path, overriding any cors middleware configuration you yourself have specified for other paths(!)
You can override the defaults when you apply the apollo middleware, e.g.
apollo.applyMiddleware({ app, cors: {credentials: true, origin: true} })
I'm using apollo-server-express 2.17
Just remove csrfPrevention: true and you are good to go
import { ApolloServer } from 'apollo-server-express';
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';
import express from 'express';
import http from 'http';
async function startApolloServer(typeDefs, resolvers) {
// Required logic for integrating with Express
const app = express();
// Our httpServer handles incoming requests to our Express app.
// Below, we tell Apollo Server to "drain" this httpServer,
// enabling our servers to shut down gracefully.
const httpServer = http.createServer(app);
// Same ApolloServer initialization as before, plus the drain plugin
// for our httpServer.
const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: 'bounded',
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
// More required logic for integrating with Express
await server.start();
server.applyMiddleware({
app,
// By default, apollo-server hosts its GraphQL endpoint at the
// server root. However, *other* Apollo Server packages host it at
// /graphql. Optionally provide this to match apollo-server.
path: '/',
});
// Modified server startup
await new Promise(resolve => httpServer.listen({ port: 4000 }, resolve));
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`);
}