I am trying to make a post request from postman but I'm receiving a 404 error: SyntaxError: Unexpected token n in JSON at position 4<br> at JSON.parse.
I have added the Content-Type: application/json header and defined the json body in the raw tab.
This is the url: http://localhost:8000/api/signup.
I can't make this post request nor can I access the application in the browser as I receive cannot GET /api/signup.
How can I fix this?
controllers/user.js
const User = require('../models/user')
const { errorHandler } = require("../helpers/dbErrorHandler")
exports.signup = (req, res) => {
console.log("req.body", req.body)
// signs up new user
const user = new User(req.body)
user.save((err, user) => {
if(err) {
return res.status(400).json({
err: errorHandler(err)
})
}
res.json({
user
})
})
}
app.js
const express = require('express')
const mongoose = require('mongoose')
const morgan = require('morgan')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
require('dotenv').config()
// import routes
const userRoutes = require('./routes/user')
// app
const app = express()
// connect db - first arg is url (specified in .env)
mongoose.connect(process.env.DATABASE, {
useNewUrlParser: true,
useCreateIndex: true
}).then(() => console.log('DB connected'))
// middlewares
app.use(morgan('dev'))
app.use(bodyParser.json())
// used to save users credentials
app.use(cookieParser())
// routes middleware
app.use('/api', userRoutes)
const port = process.env.PORT || 8000
app.listen(port, () => {
console.log(`Server is running on port ${port}`)
})
models/user.js
const mongoose = require('mongoose')
const crypto = require('crypto')
const uuidv1 = require('uuid/v1')
const userSchema = new mongoose.Schema ({
...
}, {timestamps: true})
userSchema.methods = {
encryptPassword: function(password) {
if (!password) return '';
// hashes password
try {
return crypto.createHmac('sha1', this.salt)
.update(password)
.digest('hex')
} catch (err) {
return ''
}
}
}
module.exports = mongoose.model("User", userSchema)
routes/user.js
const express = require('express')
const router = express.Router()
const { signup} = require('../controllers/user')
router.post('/signup', signup)
module.exports = router
404 means NOT Found,
May be your URL or Method is wrong
Here is what you can try to diagnose:
Check if server is running
Check the port and URL you are accessing.
Check the postman method POST and URL.
Check the route, routes file and match it with postman URL
This seems like two different issues, for the POST request, the error seems like there is an invalid string in your JSON payload that your application cannot read and parse.
The second one is mainly due to the route is not found, without looking at your ./routes/user file, it seems like there are two possibilities:
You have a nested route of /user/.... If that is the case, try accessing your api via /api/user/signup instead of /api/signup
You did not create a GET route for you signup path. Normally signup is a POST path instead of GET.
It would be best if you can provide the source code of ./routes/user.js for us to properly answer this.
404 error is an HTTP status code that means that the page you were trying to reach on a website couldn't be found on their server. To be clear, the 404 error indicates that while the server itself is reachable, the specific page showing the error is not.
Make sure that your indexing is correct and your local server is running properly.
Related
Trying to set up my Express server on HTTPS but unable to access my api. Here is my code:
// server.js
const express = require('express');
const { readFileSync } = require('fs');
const https = require('https');
const app = express();
const key = readFileSync(
'/etc/letsencrypt/live/mydomain.com/privkey.pem',
'utf8'
);
const cert = readFileSync(
'/etc/letsencrypt/live/mydomain.com/fullchain.pem',
'utf8'
);
const ca = readFileSync(
'/etc/letsencrypt/live/mydomain.com/chain.pem',
'utf8'
);
const credentials = { key, cert, ca };
const port = 443
const server = https.createServer(credentials, app);
server.listen(port, () => console.log(`Server is running on port ${port}`));
The error I am receiving is a 502 Bad gateway on all calls to the server.
Everything worked perfectly before when I was running on HTTP like this:
const server = app.listen(8000, () => {});
Beside the URL on my site I can see the padlock icon and it says my site is secure so I believe my certifcate is valid.
Have seen a lot of similar questions posted on here and followed what I've seen in responses. I've even asked chatGPT to check my code and it doesn't see any errors. I've also tried reading my SSL keys as .env variables so I don't think the issue is an incorrect file path.
Can anybody please help me find the solution?
EDIT
Here is an example of a get request I am making to my backend using axios:
const fetchMembers = async () => {
await axios
.get(`/api/total-users`)
};
This invokes a function totalUsers with express.Router from a users file in my routes folder on the backend:
// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/total-users', totalUsers);
const totalUsers = async (req, res) => {
try {
const total = await User.find().estimatedDocumentCount();
res.json(total);
} catch (err) {
console.log(err);
}
};
I am using a middleware app.use with a prefix /api and importing the users file to make a connection to my endpoints:
// server.js
const userRoutes = require('./routes/users')
app.use('/api', userRoutes)
While editing this question I tried modifying the middleware prefix to `:443/api' however this still hasn't helped.
Where is User defined inside of routes/users.js? You need to import your DB models before accessing them like this:
const total = await User.find().estimatedDocumentCount();
Otherwise, generally when running fetch('/api...), React will try to access localhost:3000/api instead of localhost:443/api.
React needs to know where to proxy requests to the backend. One way is using the http-proxy-middleware library and by defining a setupProxy.js file.
client/src/setupProxy.js
/**
* Proxy most calls to the server
* #type {Array}
*/
/* eslint-disable #typescript-eslint/no-var-requires */
const { createProxyMiddleware } = require('http-proxy-middleware');
const proxy_urls = ['/api/*';
const target = 'https://localhost:443';
module.exports = function (app) {
proxy_urls.forEach((url) => {
app.use(url, createProxyMiddleware({ target }));
});
};
hello i have a issue i build a project when i start to add the server side
i am using node js express
i create fetch post to spesific url from the database (mongoDB)
and i want to add the users
now
its workd but i try to reconfigure the files and using router and now i get 404 when i try to make the post is upload some code
just need to know where is the bad request
the url i want to fetch is
http://localhost:5000/shopping-cart/user/sign-up
Axios.post("http://localhost:5000/shopping-cart/user/sign-up", user).then((response) => {
console.log(response);
});
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const path = require("path")
const productRouter = require("./routes/product.route");
const userRouter = require("./routes/user.route");
const { setServerConfiguration } = require("./config");
setServerConfiguration(app);
mongoose.connect('mongodb://localhost/shopping-cart-data-base');
app.use("/shopping-cart", productRouter);
app.use("/user/sign-up", userRouter);
app.listen(5000);
const router = require('express').Router();
const errorsHandler = require('../utils/errorsHandler');
const UserModel = require('../models/User');
router.post("/user/sign-up", async (req, res) => {
let body = req.body;
console.log(body)
try{
await UserModel.create({
name: body.name,
username: body.username,
password: body.password,
shoppingHistory: [],
});
res.send(body);
}catch(e){
return errorsHandler(e, req, res);
}
});
module.exports = router;
Your router is mounted on the /user/sign-up prefix:
app.use("/user/sign-up", userRouter);
Which means that all requests that start with /user/sign-up will get passed to your router.
Your router should be routing relative to that prefix, so to make it work, use this:
router.post('/', ...)
Try this url
"http://localhost:5000/user/sign-up"
If you want to use "http://localhost:5000/shopping-cart/user/sign-up" than you need to define route like that, for example:
router.post("shopping-cart/user/sign-up", async (req, res) => {
//Your code
})
404 route not found
app.use("/shopping-cart", productRouter) => route1
app.use("/user/sign-up", userRouter); => route2
route1 other route2
url http://localhost:5000/shopping-cart request route1
url http://localhost:5000/user/sign-up request route2
I've deployed my app on Heroku and after some tweaking, everything works except when I try to retrieve data from the Mongo database. The console error I get is: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0.
I have the feeling that it won't go into the get request while that should be the case. (Because it's not logging anything in the console)
Am I missing something in the way routes are handled in production?
Everything in development is working.
I'm very confused at this point, hope someone can help me
Server.js:
const bodyParser = require('body-parser')
const path = require('path');
const express = require('express');
const morgan = require('morgan');
const MongoClient = require('mongodb').MongoClient;
const cors = require('cors')
const compression = require('compression');
const helmet = require('helmet')
const app = express();
const port = process.env.PORT || 5000;
app.use(helmet())
app.use(compression());
if (process.env.NODE_ENV === 'production') {
const publicPath = path.join(__dirname, 'client/build');
const apiPath = path.join(__dirname, 'api');
app.use(express.static(publicPath));
app.use('/overview', express.static(apiPath));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/client/build/index.html'));
})
}
app.use(cors())
app.use(morgan('tiny'));
app.use(bodyParser.json())
const apiRouter = require('./api/api');
app.use('/overview', apiRouter);
// connect to the db and start the express server
let db;
const url = process.env.MONGODB_URI
MongoClient.connect(url, {useUnifiedTopology: true,useNewUrlParser: true,}, (err, client) => {
if(err) {
return console.log(err);
}
console.log('mongo connected')
db = client.db('kvdlaanmeldingen');
// start the express web server listening on port 5000
app.listen(port, () => console.log(`Listening on port ${port}`));
});
apiRouter, api.js in api/api.js:
const express = require('express');
const apiRouter = express.Router()
const MongoClient = require('mongodb').MongoClient;
const mongodb = require('mongodb');
const url = process.env.MONGODB_URI
console.log('api.js is activated') //this is logged to console, so file can be read.
let db;
MongoClient.connect(url, {useUnifiedTopology: true,useNewUrlParser: true,}, (err, client) => {
db = client.db('kvdlaanmeldingen');
});
let aanmeldingen = [];
// this is where I believe it gets stuck
apiRouter.get('/', (req, res) => {
console.log(db)
db.collection('kvdlaanmeldingen').countDocuments({}, function(err, result) {
console.log(result)
if (err) return console.log(err);
res.send(JSON.stringify(result));
})
});
module.exports = apiRouter;
The get request should be done as soon as this React component is rendered:
import React from 'react';
import './Aanmeldingen.css';
import { Link, Route } from "react-router-dom";
import XPress from './utils/Xpress.js';
import TaakComponent from './TaakComponent';
import { snakeCase } from "snake-case";
class Aanmeldingen extends React.Component {
constructor (props) {
super(props);
this.state = {
dataLoaded: 0,
taken: [// an array of different names that will be loaded as headers],
taakKlik: false,
taakData: null,
taakNaam: null,
}
}
componentDidMount(){
XPress.getTaken().then(data => {
console.log(data)
if (data) {
this.setState({
taakData: data,
dataLoaded: 1,
});
}
});
}
{...}
render(){
return (
<div className="Aanmeldingenpage">
<div className="statistics" onClick={this.aanmeldingen}>
<p className="statistics" id="counterAanmeldingen">{this.state.dataLoaded ? `Aantal aanmeldingen: ${this.state.taakData}` : 'Data aan het laden..'}</p>
</div>
</div>
);
}
}
and Xpress.getTaken is looking like this:
const XPress = {};
const baseUrl = window.location.origin;
XPress.getTaken = () => {
const url = `${baseUrl}/overview`;
return fetch(url, {method: 'GET'}).then(response => {
if (!response.ok) {
return new Promise(resolve => resolve([]));
}
return response.json().then(jsonResponse => {
return jsonResponse
}
)
})
}
The error you posted is often seen when parsing JSON fails. I guess this happens when fetch fails to parse the result in the frontend at this line: return response.json().then(jsonResponse => {.
Instead of returning valid JSON, the backend returns a file that starts with "<" (the unexpected token). Your backend responds with an HTML page instead of JSON.
Issue comes from here most likely:
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/client/build/index.html'));
})
This basically says that all GET requests should serve index.html. That's why the request doesn't go to apiRouter.get('/'), it stops at the first match, which is the code above. It works on localhost because this code path is inside a conditional that checks NODE_ENV for production.
Not sure why you have it in there, but removing it would solve the issue.
Please try adding the heroku postbuild script to your json file in the root directory as same as the existence of the server.js file, that might help, using in react we must add heroku postbiuld so that the build is saved in the server, and that might not produce an issue,
problem with saving to MongoDB database
This is my second time trying to post to a database, still new to it. I am receiving string from a html form and trying to save into the database. I have connected to mongodb successfully, setup my post route, setup my model and now trying to send the http request to save it to db. before setting up the model, I was able to console.log the data I received from my form. but after setting up the model and trying to get the route to save it to db, it just hangs. If i comment out the main.save(), and console.log(main), alll I get back is an _id.
i cant figure out where im going wrong with it
index.js
const express = require('express')
const path = require('path')
const routes = require('../routes/routes')
const app = express()
const port = 3000
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(express.static(path.join(__dirname, '../public')))
app.use(routes)
app.listen(port, () => {
console.log('Server is up on port ' + port)
})
routes
const express = require('express')
const Main = require('../src/model')
const router = new express.Router()
router.post('/', async (req, res) => {
const main = new Main(req.body)
console.log(main)
try{
await main.save()
res.status(201).send(main)
} catch (e) {
res.status(400).send(e)
console.log('Not working!')
}
})
module.exports = router
model
const mongoose = require('mongoose')
const Main = mongoose.model('Main', {
total_check: {
type: String
}
})
module.exports = Main
receiving an _id, but hanging on .save()
This is because you are passing whole req.body to the database. Change this const main = new Main(req.body) to this
let main= new Main({
total_check:req.body.total_check
});
Just make sure you are receiving correct data from your frontend end or Postman.
Also save returns a callback so handle that as well
main.save((err,main)=>{
if(err) {console.log(err) }
else { res.status(201).send(main) }
});
I am using supertest to test get requests to mLab app. If I do a regular GET request with postman I receive this:
{"_id":"5b169a9951573c50d9682d52","text":"First test note","title":"Test1"}
But the response received in the test adds slashes before each quote:
{\\"_id\\":\\"5b169a9951573c50d9682d52\\",\\"text\\":\\"First test note\\",\\"title\\":\\"Test1\\"}
This is my test file:
const server = require("../../app/server");
const request = require("supertest")(server);
describe("routes: index", () => {
test("should respond as expected", async() => {
const app = request("http://localhost:8000");
const response = await app.get("/notes/5b169a9951573c50d9682d52");
expect(response).toEqual("First test note");
expect(response).toEqual("Test1");
});
});
This is my server
const express = require('express'); // node module
const MongoClient = require('mongodb').MongoClient;
const bodyParser = require('body-parser');
const db = require('./config/db');
const app = express();
const port = process.env.PORT || 8000;
app.use(bodyParser.urlencoded({
extended: true
}));
MongoClient.connect(db.testUrl, (err, database) => {
if (err) return console.log(err)
require('./routes')(app, database);
app.listen(port, () => {
console.log('We are live on ' + port);
console.log(process.env.PORT);
});
})
module.exports = app;
I haven't been using supertest myself, but a brief look at your code and documentation immediately shows several issues.
First of all, what you see is what your test framework reports to you - it is a string representation of the json object. It is correct.
What is not correct is how you try to handle the response. Check the documentation:
https://www.npmjs.com/package/supertest
I think, you may solve the problem by
1) setting the expected type
2) and by accessing the body member of the response
const response = await app.get("/notes/5b169a9951573c50d9682d52").set('Accept', 'application/json');
expect(response.body.text).toEqual("First test note");
I hope, this works.