I'm trying to make a "MEVN" application (MongoDB, Express, Vue, NodeJs).
On the client side, I have a vue component which provides a form to create a post. The post is basically a title and a description. So I have something like this :
methods: {
async addPost () {
await PostsService.addPost({
title: this.title,
description: this.description
})
this.$router.push({ name: 'Posts' })
}
}
My PostsService is a helper to handle posts :
import Api from '@/services/Api'
export default {
addPost (params) {
return Api().post('posts', params)
},
}
My Api is a simple axios constructor :
import axios from 'axios'
export default() => {
return axios.create({
baseURL: `http://localhost:8081`
})
}
On the server side, I have an entry point :
var express = require('express')
, app = express()
app.use(require('./controllers'))
app.listen(8081, function() {
console.log('Listening on port 8081...')
})
Which initiate a controller loader :
var express = require('express')
, router = express.Router()
router.use('/posts', require('./posts'))
module.exports = router
The post controller looks like this :
var express = require('express')
, router = express.Router()
, Post = require('../models/post')
// Add new post
router.post('/posts', function(req, res) {
var title = req.title;
var description = req.description;
post = Post.create(title, description);
if(post) {
res.send({flag: 'SUCCESS', content: post})
} else {
res.send({flag: 'ERROR', content: 'Failed to create the post'})
}
})
module.exports = router
As you can see there is some action with models/post which will make a db connection and save the post.
When I start my server using npm start, I have the confirmation I'm listenning on port 8081.
When I call the addPost() function, I get two XHR requests :
Request URL: http://localhost:8081/posts
Request Method: OPTIONS
Status Code: 204 No Content
Remote Address: [::1]:8081
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 0
Date: Sun, 15 Jul 2018 18:20:01 GMT
Vary: Access-Control-Request-Headers
X-Powered-By: Express
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en,fr-FR;q=0.9,fr;q=0.8,en-US;q=0.7,en-GB;q=0.6
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: localhost:8081
Origin: http://localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Request URL: http://localhost:8081/posts
Request Method: POST
Status Code: 404 Not Found
Remote Address: [::1]:8081
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 145
Content-Security-Policy: default-src 'self'
Content-Type: text/html; charset=utf-8
Date: Sun, 15 Jul 2018 18:20:01 GMT
X-Content-Type-Options: nosniff
X-Powered-By: Express
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en,fr-FR;q=0.9,fr;q=0.8,en-US;q=0.7,en-GB;q=0.6
Connection: keep-alive
Content-Length: 35
Content-Type: application/json;charset=UTF-8
Host: localhost:8081
Origin: http://localhost:8080
Referer: http://localhost:8080/posts/new
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
{title: "test", description: "test"}
The second XHR fails and tells me : Cannot POST /posts
Can you explain me what happens and how to fix it ?
Thanks
Your route handler is for /posts/posts
so you don't actually have a route handler for just /posts
. The first part of the /posts/posts
path comes from here:
router.use('/posts', require('./posts'))
The second /posts
that adds onto the first comes from:
router.post('/posts', function(req, res) {...}
These two are additive so the URL you have a handler for is /posts/posts
.
I'm guessing that the OPTIONS
request works because you have some generic CORS middleware installed that is approving all routes when requested with OPTIONS. The second request fails because there is no route handler for just /posts
, only one for /posts/posts
.
You can fix this by either changing this:
router.use('/posts', require('./posts'))
to:
router.use(require('./posts'))
Or, by changing this:
router.post('/posts', function(req, res) {..}
to this:
router.post('/', function(req, res) {..}
Which ones to choose depends upon whether you want every route on your post controller router to inherit /posts
as the root of the path or whether you want to define multiple routes at the top level in your post controller router.