Here is a bit of a background: I am making a full stack to-do list application. The front-end is based on React and Bootstrap. The backend is using Express, Node and MongoDB. The problem is that when I’m fetching the data from MongoDB using GET, I can view it on frontend. But when I’m sending the data using POST, I get this error:
Access to XMLHttpRequest at 'http://localhost:5035/api/todos' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I’m adding the required code files here.
Frontend
TodoTask.js
// Handles displaying components related to todo task list
import React, { useState, useEffect } from "react";
import TodoForm from "./TodoForm";
import TodoUpdate from "./TodoUpdate";
import axios from "axios";
function TodoTask() {
//for the list of tasks
const [todos, setTodos] = useState([]);
//add task in the list of tasks
const addTodo = async todo => {
//check for empty input
if (!todo.text || /^s*$/.test(todo.text)) {
return
}
const newTodos = [todo, ...todos];
setTodos(newTodos);
console.log(todos);
try {
await axios.post("http://localhost:5035/api/todos", {
todo
});
} catch (error) {
console.log(error);
}
}
const ViewAllTodos = () => {
useEffect(() => {
getAllTodo();
}, []);
}
const getAllTodo = async () => {
const response = await axios.get("http://localhost:5035/api/todos");
setTodos(response.data.Todo);
console.log(response.data.Todo);
}
const updateTodo = (todoId, newValue) => {
if (!newValue.text || /^s*$/.test(newValue.text)) {
return
}
setTodos(prev => prev.map(item => (item.id === todoId ? newValue : item)))
}
const removeTodo = id => {
const remove = [...todos].filter(todo => todo.id !== id);
setTodos(remove);
}
const completeTodo = id => {
let updatedTodos = todos.map(todo => {
if (todo.id === id) {
todo.isComplete = !todo.isComplete;
}
return todo;
});
setTodos(updatedTodos);
}
const [message, setMessage] = useState('');
return (
<div id="container">
<h1 className="display-1">My To Do List Application</h1>
<p className="lead">This is a basic to do list application with complete frontend and backend configuration. For details, check ReadMe.md of this project.</p>
{/* calling the form component to show a text field */}
<label htmlFor="formGroupExampleInput">Enter your to do here:</label>
<TodoForm onSubmit={addTodo} />
{/* checking if the list is empty, otherwise list all the todos with update and delete button */}
{todos.length === 0 ?
<p className="lead">The list is empty!</p> :
<TodoUpdate todos={todos} completeTodo={setTodos} removeTodo={removeTodo}
updateTodo={updateTodo} />
}
{/* {todos.length === 0 ? <p>Empty</p> :
todos.map((todo, index) => (
<tr key={todo._id}>
<td>{todo.priority}</td>
<td>{todo.todo}</td>
</tr>
))
} */}
</div>
)
}
export default TodoTask;
Backend:
MongooseServer.js
// import dependencies
const express = require('express');
var bodyParser = require('body-parser');
const mongoose = require('mongoose');
const router = require('./routers/routes');
const cors = require('cors');
// const dbUrl = require('./config/db.config/url')
// set up dependencies
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/api/', router);
const corsOptions ={
origin:'http://localhost:3000',
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200,
methods: "GET, POST"
}
app.use(cors(corsOptions));
//app.use(cors());
// app.use(cors({
// origin: 'http://localhost:3000',
// }))
// set up mongoose
mongoose.connect("mongodb://127.0.0.1:27017/mytodolist")
.then(()=> {
console.log('Database connected');
})
.catch((error)=> {
console.log('Error connecting to database');
});
// set up port
const port = 5035;
// set up route
app.get('/', (req, res) => {
res.status(200).json({
message: 'Welcome to todo list',
});
});
app.listen(port, () => {
console.log(`Our server is running on port ${port}`);
});
Model.js
const mongoose = require("mongoose");
const MyTodoListSchema = new mongoose.Schema({
taskId: {
type: Number,
required: true,
unique: true
},
todo: {
type: String,
default: "",
required: true
},
priority: {
type: String,
default: "high",
required: true
},
});
const MyTodoList = mongoose.model("MyTodoList", MyTodoListSchema);
module.exports = MyTodoList;
Controller.js
// import mongoose from 'mongoose';
const mongoose = require('mongoose')
// import {MyTodoList} from '../models/model';
const MyTodoList = require('../models/model');
exports.createTodo = (req, res) => {
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "*");
next();
});
const todo = new MyTodoList({
taskId: req.body.taskId,
todo: req.body.todo,
priority: req.body.priority,
});
return todo
.save()
.then((newTodo) => {
return res.status(201).json({
success: true,
message: 'New todo list created successfully',
MyTodoList: newTodo,
});
})
.catch((error) => {
res.status(500).json({
success: false,
message: 'Server error. Please try again.',
error: error.message,
});
});
}
//get all todos
exports.getAllTodo = (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*")
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Max-Age", "1800");
res.setHeader("Access-Control-Allow-Headers", "content-type");
res.setHeader( "Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, PATCH, OPTIONS" );
MyTodoList.find()
.select('taskId todo priority')
// .then( () => {
// res.setHeader("Access-Control-Allow-Origin", "*")
// res.setHeader("Access-Control-Allow-Credentials", "true");
// res.setHeader("Access-Control-Max-Age", "1800");
// res.setHeader("Access-Control-Allow-Headers", "content-type");
// res.setHeader( "Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, PATCH, OPTIONS" );
// })
.then((allTodo) => {
// const response = res.status(200).json( {
// success: true,
// message: 'A list of all todos',
// Todo: allTodo
// });
return res.status(200).json({
// success: true,
// message: 'A list of all todos',
Todo: allTodo
});
// return response;
})
.catch((err) => {
res.status(500).json({
success: false,
message: 'Server error. Please try again.',
error: err.message,
});
});
}
// module.exports = {createTodo, getAllTodo}
Route.js
const express = require("express");
const cors = require("cors");
const todolist_controller = require('../controllers/controller')
const app = express();
const router = express.Router();
router.post('/todos', todolist_controller.createTodo);
router.get('/todos', todolist_controller.getAllTodo);
module.exports = router;
Please guide me on what I’m doing wrong here.
The POST is working fine with Postman. I’m using the MVC pattern for the application. Also, the frontend and backend are two separate directories inside one main directory. Both are running on different ports. Frontend is running on port 3000 and backend on port 5035.
TIA! I’m stuck on this for day. Please help out here!
2
Answers
If you would like to whitelist for all API endpoints then cors middleware must be called before your route(and this recommended also) like following
Just use the cors middleware at the root of your api project with express for instance :