I am trying to test my newly written api to send messages. It catches a message and sends it to a database. I am using https://apitester.com/ to test it. When I try to read req.body, I get undefined.
SERVER
app.route('/message')
.post(createMessage);
var createMessage = (req, res) => {
console.log(req.body)
var newMessage = new Message(req.body)
mlab.insertDocument({database:'databasename', collectionName:'collectionname', documents:newMessage.getCreatePack()})
.then(result => {
res.json(result)
})
}
When I try to log(req.body), I get undefined
This is the request data. Any help is appreciated
As it turns out, I need body parsing middleware, such as body-parser.
Related
I was working on admin registration and admin data retrieving react app. The registration works fine but retrieving admin data is crushing my backend. I have encountered this error when call the given endpoint from my react app. But when I call it from Postman it works very fine. And when I see the console on my browser my react app sends two calls simultaneously instead of one. On these calls my app crushes. If any one can show me how to solve this problem?
For backend = Node.js with express.js framework
For frontend = React
This is the error I am getting
node:internal/errors:465
ErrorCaptureStackTrace(err);
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot remove headers after they are sent to the client
at new NodeError (node:internal/errors:372:5)
at ServerResponse.removeHeader (node:_http_outgoing:654:11)
at ServerResponse.send (C:\Users\Momentum\Documents\The Technologies\Madudi-App-Api\node_modules\express\lib\response.js:214:10)
at C:\Users\Momentum\Documents\The Technologies\Madudi-App-Api\api\index.js:22:72
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
code: 'ERR_HTTP_HEADERS_SENT'
}
[nodemon] app crashed - waiting for file changes before starting...
This is how I setup my endpoint and changed the data to a string in order to get simple response but it crushes
const makeHttpRequest = (controller, helper) => {
const makeRequest = (req, res) => {
try {
var data = "Trying response";
res.status(200).send({ status: true, data: data });
} catch (error) {
console.log(`ERROR: ${error.message}`);
res.status(400).send({ status: false, error: error.message });
}
};
return { makeRequest };
};
const makeApi = ({router, controller, helper}) => {
router.get("/test", (req, res) => res.send("Router is Woking..."));
router.get("/admin/get_all_admins", async (req, res) => res.send(await makeHttpRequest(controller, helper).makeRequest(req, res)));
}
module.exports = { makeApi }
And this is the call from my react app
export default function GetAllUsers() {
useEffect(() =>{
try{
const response = axios.get('http://localhost:5000/admin/get_all_admins').then(async (response) => {
console.log('response ', response)
return response.data;
});
}catch(error) {
return [];
}
}, [])
I'm not familiar with this method of responding to requests, but in my own opinion the error you are facing happens when you're sending multiple response.
This may be the asynchronous nature of JavaScript, there by causing another request to be sent after the function is done.
You should also try to return the response, so that once it's done it cancels out of the function. You can use the example below
const handler = (req,res) => {
return res.status(200).json(data)}
This particular error happens when you try to send more than one response for the same incoming request (something you are not allowed to do).
You are calling res.send() more than one for the same request on your server.
The first happens in the makeRequest() function.
The second time happens in this line of code:
router.get("/admin/get_all_admins", async (req, res) => res.send(await makeHttpRequest(controller, helper).makeRequest(req, res)));
You can't do that. You get ONE response per incoming request. So, either send the response in makeRquest() and don't send it in the caller. Or, don't send the response in makeRequest() and just return what the response should be and let the caller send it. Pick one model or the other.
I am not familiar with this way of setting up the server. Looks strange to me. However, in router.get("/admin/get_all_admins" your sending a response which calls a function makeHttpRequest that also sends a response. Thus you get an error Cannot remove headers after they are sent to the client because you're sending a response twice.
Guys!
Expected some bug with my socket.io.
So, all work fine. Below you can see the code example:
Server (Node.js):
controller:
.put('/user', jwtMiddleware, (req, res, next) => userService.updateUser(req.user.id, req.body.imageId, req.body)
.then(data => res.send(data))
.catch(err => {
console.log(err.message); <------ LOOK AT THIS (1)
req.io.to(req.user.id).emit('user_data', err.message); // notify a user if username or email isn't unique
res.status(400).send();
next();
}));
P.S. io injected to the request object.
userService.updateUser.js:
export const updateUser = async (userId, imageId, user) => {
const userByName = await userRepository.getByUsername(user.username);
if (userByName !== null && userByName.id !== userId) {
throw new Error('Username should be unique');
}
const { id } = await userRepository.updateById(userId, {
...user,
imageId
});
return getUserById(id);
};
Below you can see client code (React.js):
socket.on('user_data', message => {
console.log(message); <----- LOOK AT THIS (2)
NotificationManager.info(message);
});
And now time for explaining the problem.
a) When I send my user object from client to controller with 'username' that has already existed in the DB, I wonderful receive response on the client and my socket on the client in the places (1) (2) well work.
b) But when I send my user object from the client to the controller with 'username' that doesn't exist in the DB, it will fine save in the DB and after that, if I send a request as in point (a), I won't receive a response on the client. My socket on the server in a place (1) WORK CORRECTLY and in a place (2) ISN'T WORK.
Why has it happened?
These are the reasons I can think of why you wouldn't receive the message from when you do this:
req.io.to(req.user.id).emit('user_data', err.message);
req.user or req.user.id is not what you expect it to be and thus req.io.to(req.user.id) doesn't find a valid user connection to send to.
The target page does not yet have an appropriate socket.io connection with the selected id value
When the request receives back the 400 status, it is not then in a state where it can receive your socket.io message (we'd have to see the client-side code to comment more on that). For example, if it reloads the page, then that old socket.io connection would be torn down and a new one with a different socket.id would be created.
FYI, you can step into req.io.to(req.user.id) in the debugger and see exactly how many matching socket.io connections it finds.
Also, FYI, you should not be called next() after doing res.status(400).send();. That will probably generate a warning as you will end up trying to send two responses to the same request. Remove the call to next().
I guess it is because in the success response you're not emitting any socket event.
.put('/user', jwtMiddleware, (req, res, next) => userService.updateUser(req.user.id, req.body.imageId, req.body)
.then(data => {
req.io.to(req.user.id).emit('user_data', 'User Created Successfully')
res.send(data)
})
.catch(err => {
console.log(err.message); <------ LOOK AT THIS (1)
req.io.to(req.user.id).emit('user_data', err.message); // notify a user if username or email isn't unique
res.status(400).send();
next();
}));
I am currently doing Colt Steele's Web Developer bootcamp and have came across this issue...
In this particular tutorial we are using axios as 'request' has since become discontinued so I'm trying to follow along with this.
What I want to do is set up a Get route for a '/results' page, in this I want to pull information from the OMDB Movie Database and just now, simply show the JSON file when I go onto this Url.
I'm sure there's an obvious solution but I can't seem to figure it our after having searched for hours.
Here is my code;
const express = require('express');
const app = express();
const axios = require('axios').default;
app.listen(3000, () => {
console.log('Im listening');
});
app.get('/results', (req, res) => {
axios.get('http://www.omdbapi.com/?t=california&apikey=thewdb')
.then((response) => {
res.send(response);
}).catch((err) => {
console.log('This isnt right');
})
});
As you can see I am also using express, everything is installed correctly. In fact, when I do a console.log(response) like so:
axios.get('http://www.omdbapi.com/?t=california&apikey=thewdb')
.then((response) => {
console.log(response);
}).catch((err) => {
console.log('This isnt right');
})
It works, I can see the API JSON in my console, which makes me think there is a problem with using res.send(response) in the promise.
Any help would be greatly appreciated. Apologies if I've missed any info out, still fairly new to this...
To get response data for a OMDb request use data property:
app.get('/', function (req, res, next) {
axios.get('http://www.omdbapi.com/?t=california&apikey=thewdb')
.then(result => res.send(result.data))
.catch(err => res.send(err));
});
For more information, see Axios's Response Schema documentation.
I started working on a MERN App today and am trying to write a restful api. First I am using mlab to store my mongodb database. I have succesfully connected to this database after creating a user. I can manually create a collection and inject some data into this collection. From my server.js file I can then get the data stored in here.
MongoClient.connect(db_url, (err, database) => {
if (err) return console.log(err);
var collection = database.collection('memories'); // Collection called memories
app.listen(3000, () => {
console.log("Listening on 3000");
});
});
Thats all fine and dandy but I want to take it to the next level. I want to write a CRUD api for the collection Memory. Coming from django, I would like to create my model first. Therefore, in my models/memory.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var MemorySchema = new Schema({
name: String,
description: String
});
module.exports = mongoose.model('Memory', MemorySchema);
Then I went ahead and started working on my routes/api/api.js:
let router = require('express').Router();
let Memory = require('../../../models/memories');
router.use(function (req, res, next) {
console.log("Something is happening");
next(); // Request stops at middleware without next()
});
router.route('/memory')
.post(function (req, res) {
let memory = new Memory();
memory.name = req.body.name;
memory.description = req.body.description;
memory.save(function (err) {
if (err) {
res.send(err);
}
res.json({message: 'Memory Created'});
});
})
.get(function (req, res) {
res.json({message: 'First memory'});
});
module.exports = router;
And in my server.js I call this module:
const apiRoutes = require('./routes/api/api');
app.use('/api/', apiRoutes);
However, after testing the post api with postman, it the POST request just takes forever before showing up as Could not get any response. However, the GET request works. What am I missing?
EDIT: So the post function is having trouble saving the model instance...
Try adding results as the first parameter in the callback of the save function, then res.json(results, { message: "Memory Created" }) to see if you are returned anything.
The main difference between the post and the get method is that the post method uses Mongoose, while the get doesn't. If you fail to connect to the database then the response can time out due to memory.save(...) not working as it should. And there are no responses sent outside the callback to save, so if your program never enter it, you will never send a response. The request will time out eventually.
In your model file you register a model on the following line:
module.exports = mongoose.model('Memory', MemorySchema);
Mongoose will then look for data in the memorys collection. If you change it to
module.exports = mongoose.model('Memory', MemorySchema, 'memories');
it will use the memories collection instead. This will make it consistent with the connection-to-db snippet you posted. I don't know if that will fix your issue though. I would suggest changing the connection code to
mongoose.connect(dburl, {
useMongoClient: true
});
instead of the native mongo client. You can add these lines too
mongoose.connection.on('connected', function () {
console.log('Mongoose connected');
});
mongoose.connection.on('error', function (err) {
console.log('Mongoose connection error: ' + err);
});
mongoose.connection.on('disconnected', function () {
console.log('Mongoose disconnected');
});
right after the connection code to help with debugging. Make sure you get connected when starting the app.
If you see an error similar to this Error: Can't set headers after they are sent. in the node terminal window, it might be because you are sending two responses in the post function. If an error occurs while saving it will enter the if(err) block, send a response async then go to the res.json(...) response and send that too.
So you have to return after sending the response to exit the function. Either like this
res.send(err);
return;
or like this
return res.send(err);
Same for the json response.
If that doesn't fix the problem you should either fire up the debugger (node --inspect or nodemon --inspect), or insert a console.log('inside post'); inside the post function to see that you're actually entering it.
I'm trying to log all the data and then return it as a response.
app.post('/data', (req, res) => {
const data = req.body
console.log(data)
return res.json({
data
})
})
I'm sending data with Postman. In the Body tab I have "raw" selected and "JSON (application/json)". Headers tab is Content-Type application/json. I'm sending this:
{
"aa": 23
}
When I click send button all I get is an empty object and the data variable is undefined in my console.log. How to fix it? I double checked everything. It should work, but it doesn't.
It seems like you're passing an invalid value to res.JSON(). Try:
return res.json(data);
Alright, I found the solution.
"As body-parser module is used to parse the body and urls, it should be called before any call to 'req.body...'."
So I did this:
import bodyParser from 'body-parser'
const app = express()
app.use(bodyParser.urlencoded())
app.use(bodyParser.json())
app.post('/data', (req, res) => {
const data = req.body
console.log(data)
return res.json({
data
})
})
And now it works fine.