im tryng build crud app using MERN stack,
method add and get not got blocked by cors,
but patch method got blocked by cors
alredy install cors module on my server
and still didnt work
routes
import express from 'express';
import { createPost, getPost, updatePost } from '../controllers/posts.js';
const router = express.Router();
router.get('/', getPost);
router.post('/', createPost);
router.patch('/:id', updatePost);
export default router;
server/controllers
export const updatePost = async (req, res) => {
const { id: _id } = req.params;
const post = req.body;
if (!mongoose.Types.ObjectId.isValid(id))
return res.status(404).send(`no post with id ${id}`);
const updatedPost = postMessage.findByIdAndUpdate(_id, post, { new: true });
res.json(updatedPost);
};
client>src>api
import axios from 'axios';
const url = 'http://localhost:3001/posts';
export const fetchPosts = () => axios.get(url);
export const createPost = (newPost) => axios.post(url, newPost);
export const updatePost = (id, updatePost) =>
axios.patch(`${url}/${id}`, updatePost);
Certain CORS requests are considered ‘complex’ and require an initial OPTIONS request (called the “pre-flight request”)
If you are making requests other than GET/HEAD/POST (such as PATCH) you need to enable pre-flight request
Serverside add these lines
app.options('/posts/:id', cors()) // enable pre-flight request
Source - [ExpressJs Docs][1]
[1]: https://expressjs.com/en/resources/middleware/cors.html#:~:text=on%20port%2080%27)%0A%7D)-,Enabling%20CORS%20Pre%2DFlight,-Certain%20CORS%20requests
Related
My fetch takes too long until it fails
I tried chrome, edge and postman
other fetch requests from pixabay api are working great
I compared the code to other projects I've made and found nothing
I also added a proxy to "package.json" as suggested on some places and it didnt work
posting below parts of my code:
controller:
import axios from 'axios'
export const getAll = async () =>{
const response = await axios.get('https://pixabay.com/api/?key=25540812-faf2b76d586c1787d2dd02736')
.then(resp=>resp)
.catch(err=>console.log(err));
return response;
}
router:
import express from "express";
import * as homeController from '../controllers/home.controller.js'
const homeRouter = express.Router();
homeRouter.get('/all', homeController.getAll)
export default homeRouter
indexjs:
import express from "express"
import dotenv from "dotenv"
import homeRouter from './routers/home.router.js'
dotenv.config();
const PORT = 3000 //process.env.PORT
console.log(PORT);
const app = express();
app.use(express.json());
app.use(homeRouter)
app.listen(PORT, ()=>{console.log(`server is connected on port ${PORT}`)})
fetch:
const getAll = async()=>{
try {
const response = await fetch (`http://localhost:3000/all`)
console.log("hu");
if (!response.ok) {
throw new Error();
}
else{
console.log("ok");
}
const responseObj = await response.json();
console.log(responseObj);
}
catch (error) {
console.log(error);
}
}
useEffect(()=>{
getAll();
},[])
Posting the answer by #Jaromanda X for everyone to see:
"see this app.get('/', (req, res) => { ... where's you req and res ??? nowhere, that's where - hint: export const getAll = async (req, res) =>{"
Apparently EVERY controller made with express needs to send a response back (in the form of res.send)
Should be obvious but somehow I missed it
Thanks everyone!
I have an app made with React, Node.js and Socket.io
I deployed Node backend to heroku , frontend to Netlify
I know that CORS errors is related to server but no matter what I add, it just cant go through that error in the picture below.
I also added proxy script to React's package.json as "proxy": "https://googledocs-clone-sbayrak.herokuapp.com/"
And here is my server.js file;
const mongoose = require('mongoose');
const Document = require('./Document');
const dotenv = require('dotenv');
const path = require('path');
const express = require('express');
const http = require('http');
const socketio = require('socket.io');
dotenv.config();
const app = express();
app.use(cors());
const server = http.createServer(app);
const io = socketio(server, {
cors: {
origin: 'https://googledocs-clone-sbayrak.netlify.app/',
methods: ['GET', 'POST'],
},
});
app.get('/', (req, res) => {
res.status(200).send('hello!!');
});
const connectDB = async () => {
try {
const connect = await mongoose.connect(process.env.MONGODB_URI, {
useUnifiedTopology: true,
useNewUrlParser: true,
});
console.log('MongoDB Connected...');
} catch (error) {
console.error(`Error : ${error.message}`);
process.exit(1);
}
};
connectDB();
let defaultValue = '';
const findOrCreateDocument = async (id) => {
if (id === null) return;
const document = await Document.findById({ _id: id });
if (document) return document;
const result = await Document.create({ _id: id, data: defaultValue });
return result;
};
io.on('connection', (socket) => {
socket.on('get-document', async (documentId) => {
const document = await findOrCreateDocument(documentId);
socket.join(documentId);
socket.emit('load-document', document.data);
socket.on('send-changes', (delta) => {
socket.broadcast.to(documentId).emit('receive-changes', delta);
});
socket.on('save-document', async (data) => {
await Document.findByIdAndUpdate(documentId, { data });
});
});
console.log('connected');
});
server.listen(process.env.PORT || 5000, () =>
console.log(`Server has started.`)
);
and this is where I make request from frontend;
import Quill from 'quill';
import 'quill/dist/quill.snow.css';
import { useParams } from 'react-router-dom';
import { io } from 'socket.io-client';
const SAVE_INTERVAL_MS = 2000;
const TextEditor = () => {
const [socket, setSocket] = useState();
const [quill, setQuill] = useState();
const { id: documentId } = useParams();
useEffect(() => {
const s = io('https://googledocs-clone-sbayrak.herokuapp.com/');
setSocket(s);
return () => {
s.disconnect();
};
}, []);
/* below other functions */
/* below other functions */
/* below other functions */
}
TL;DR
https://googledocs-clone-sbayrak.netlify.app/ is not an origin. Drop that trailing slash.
More details about the problem
No trailing slash allowed in the value of the Origin header
According to the CORS protocol (specified in the Fetch standard), browsers never set the Origin request header to a value with a trailing slash. Therefore, if a page at https://googledocs-clone-sbayrak.netlify.app/whatever issues a cross-origin request, that request's Origin header will contain
https://googledocs-clone-sbayrak.netlify.app
without any trailing slash.
Byte-by-byte comparison on the server side
You're using Socket.IO, which relies on the Node.js cors package. That package won't set any Access-Control-Allow-Origin in the response if the request's origin doesn't exactly match your CORS configuration's origin value (https://googledocs-clone-sbayrak.netlify.app/).
Putting it all together
Obviously,
'https://googledocs-clone-sbayrak.netlify.app' ===
'https://googledocs-clone-sbayrak.netlify.app/'
evaluates to false, which causes the cors package not to set any Access-Control-Allow-Origin header in the response, which causes the CORS check to fail in your browser, hence the CORS error you observed.
Example from the Fetch Standard
Section 3.2.5 of the Fetch Standard even provides an enlightening example of this mistake,
Access-Control-Allow-Origin: https://rabbit.invalid/
and explains why it causes the CORS check to fail:
A serialized origin has no trailing slash.
Looks like you haven't imported the cors package. Is it imported anywhere else?
var cors = require('cors') // is missing
Currently I'm increasing body size for all requests like this:
import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
...
const app = new Koa();
...
app.use(
bodyParser({
jsonLimit: '150mb',
})
);
...
I'm struggling to find a way to increase body size just for single Koa route not for all routes. Does anyone has a solution?
I've ended up doing it in this way:
Prevent body parser for specific route for which you need bigger body size:
app.use(async (ctx, next) => {
if (ctx.path === '/my/big/body/route') ctx.disableBodyParser = true;
await next();
});
app.use(bodyparser());
Parse body with co-body on actual endpoint:
import { json } from 'co-body';
export default async function uploadImage(ctx, next) {
try {
const body = await json(ctx, { limit: '150mb' });
...
I am new to graphql. I am building a react site with graphql on the backend. I am trying to figure out how to limit the number of objects (or items) returned by the resolver. Documentation is very scarce and i did not see clear examples for filtering or limiting or sorting things.
my index file looks like this:
import express from "express";
import mongoose from "mongoose";
import {ApolloServer, gql} from "apollo-server-express";
import {resolvers} from "./resolver"
import {typeDefs} from "./typeDefs"
const bodyParser = require('body-parser');
const server = async () => {
const app = express();
app.use(bodyParser.json());
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST,GET,OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
const server = new ApolloServer({
typeDefs,
resolvers
})
server.applyMiddleware({app})
await mongoose.connect("mongoaddr...",{useNewUrlParser:true})
app.get('/', (req,res)=> res.send('hello'))
app.listen({port:4001}, ()=>{
console.log('connected')
})
}
server()
My model:
import mongoose from "mongoose";
export const Post = mongoose.model("Post",{
word:String,
)
my typeDefs:
import {gql} from "apollo-server-express";
export const typeDefs = gql`
type Query{
getPosts(limit:Int):[Post!]!
}
type Post {
id:ID!
word: String!
}
And my resolver:
import { Post } from "./models/Post";
export const resolvers = {
Query:{
async getPosts(_,{ limit },context){
const post = Post.find()
console.log(limit)
return(post)
}}
}
Mutation:{...}
I do not understand at all how to limit the getPosts query. With Posts.find() i get all the items in my website but when i console.log it it gives me a huge chunk of metadata.
Could anybody please give an example of how to filter for lets say first 10 objects based on my situation. The data that i am filtering is in mongo db. so basically a standard json like :
{
"data": {
"getPosts": [
{
"word": "test"
},
{
"word": "test1"
}
]
}
}
It's not related to grapql at all! You have to slice the array of documents you are getting from your your mongoose model. In your case the getPosts function will return an array of Post documents. So, you just have to slice & return the array.
async getPosts(_,{ limit },context){
const post = Post.find()
return post.slice(0, limit)
}}
Or even better, you could use mongoose limits:
async getPosts(_,{ limit },context){
const post = Post.find().limit(limit)
return post
}}
That's it 😉.
I am a beginner in VueJs and Expressjs. I am trying to make frontend side by Vuejs and backend by ExpressJs. I send a post request to the backend (expressJs) and :
1- Response is undefined
2- At the same time I can see 2 requests in chrome development tools. One is Option and another one is Post.
3- With postman there is no problem at all.
Here is the code of app.js in express
console.log('Server is running')
const express = require('express'),
bodyParser = require('body-parser'),
cors = require('cors'),
morgan = require('morgan');
app = new express();
//Setup middleware
app.use(cors());
app.use(morgan('combined'))
app.use(bodyParser.json())
app.post('/register', (req, res, next) => {
res.send({
message: `Hello ${req.body.email}! your user was registered!`
})
});
app.listen(8081);
And here is the code in VueJs :
// Api Setting
import axios from 'axios'
export const HTTP = axios.create({
baseURL: `http://localhost:8081`
});
// AuthenticationService
import { HTTP } from '../services/Api'
export default {
register(credentials) {
HTTP.post('register', credentials);
}
}
// Register Component
export default {
data() {
return {
email: '',
password: ''
};
},
methods: {
async register() {
const response = await AuthenticationService.register({
email: this.email,
password: this.password
});
console.log(response); // the value is undefined
}
}
};
I really don't know what I missed here that I get an undefined response and 2 requests at the same time. I appreciate any hint.
Whole code on github repo : here
Maybe. Authentication.register is not returning anything or more specifically a Promise which should be used to populate const response in the await call.
Try returning something like so: return HTTP.post('register', credentials); inside register.
For this to work though, HTTP.post('register', credentials) should also return something.
I use JSON.stringify to send the data, you are sending the objects directly, so
register(credentials) {
HTTP.post('register', credentials);
}
becomes
register(credentials) {
HTTP.post('register', JSON.stringify(credentials));
}