I just went through a tutorial and made a simple restful api. Afterwards, I added an admin user to my database. When I run the server, the authentication works, but if I try to access data via the api from the browser I get the eternal "waiting for response from localhost". I'm not sure what else I need to do for the request to be processed now that I've included a user authentication in mongodb.
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://admin:password#localhost/bookstore?authSource=admin");
app.get("/", function(req, res){
res.send("Hello World");
});
When going to localhost:3000/ I see hello world, but localhost:3000/api/books won't return anything
app.get("/api/books", function(req, res){
Genre.getBooks(function(err, books){
if(err){
throw err;
}
res.json(books);
});
});
Here's the getBooks function
module.exports.getBooks = function(callback, limit){
Book.find(callback).limit(limit);
};
You're not in any way handling the callbacks from Node correctly. You also haven't defined what Genre or Book is in your answer.
That said, a couple notes. First, if you are in a callback, you never want to throw an error (as in don't use the syntax throw err), instead you want to either handle it or pass it back to your calling code.
A common approach I use would be like this:
app.get("/api/books", function(req, res, next){ // note adding next here
Genre.getBooks(function(err, books){
if(err){
return next(err);
}
return res.json(books);
});
});
// sometime later, a generic error middleware. You can make yours more useful
app.use((err, req, res, next) => {
return res.status(500).send({ message: 'An error has occurred' });
});
Your mongoclient connection and getBooks syntax are also probably wrong, but I can't advise you the best way to fix it without knowing if you're using Mongoose or if you're doing something else.
Ok, so since you're using Mongoose, you should remove the MongoClient code you have. Instead, add at app startup:
const mongoose = require('mongoose');
mongoose.connect('your connectionstring here');
and your getBooks should look like this:
module.exports.getBooks = function(callback, limit){
Book.find({}).limit(limit).exec(callback);
};
As a sidenote, node apps typically use the callback as the final argument in a parameter list, so you might want to change the function signature to (limit, callback) and adjust the calling code accordingly.
I figured out the problem. I didn't have mongoose properly set as the client, so when referencing the exported code for finding the book data nothing happened.
Related
I am currently using app.get and app.post for input and output from my database. This works perfectly fine, but when I go to the /login page for my web application, I am able to see all of the data for all of the players in a large array. I tried this on multiple computers, and it seems that anyone can view it. Is there any way to make app.get and app.post pages unreachable?
My code snippet:
app.use(express.json());
app.use(express.urlencoded());
app.post('/login', (req, res) => {
var query = { username: req.body.username };
dbo.collection("data").find(query).toArray(function(err, result) {
if(result.length == 0){
var myobj = { username: req.body.username, password: req.body.password };
dbo.collection("data").insertOne(myobj, function(err, res) {});
}
res.send(result);
});
});
app.get('/login', (req, res) => {
dbo.collection("data").find({}).toArray(function(err, result) {
if (err) throw err;
res.send(result);
});
});
I am using mongodb's serverless instance, and node.js to run the code.
On the /login page(example.com/login):
The passwords were changed for privacy sake.
With everyone's comments, I was able to figure out how to fix it!
The way to fix the problem, is to use app.post() functions to transfer data from the index.html file to the index.js file. This allows everything to be done behind the scenes. With this information, I was able to only res.send() a boolean instead of the entire array. This made it so that the page only showed "true" or "false" instead of everyone's data. Furthermore, I used bcrypt to encrypt passwords, so even if hackers could see the data, they could not hack anyone.
I have a server that is fully functioning, but I only want it to be accessable when I say. I do this via a discord bot which works fine. I currently have a boolean variable server_on and an if (server on) { do } in all of my app.get and app.post functions. Is there a cleaner way to do this, or is this if statement in every function the only way?
Edit:
Final working code
var block_server_middleware = function (req, res, next) {
if (!server_on) { res.send("server is currently unavailable") }
else { next() }
}
app.use(block_server_middleware)
and the other app.get and app.post functions were not changed at all
This was the only few lines added that made the whole idea work
You can define one middleware function that goes before all your routes are defined:
app.use((req, res, next) => {
if (!server_on) {
// stop all routing
res.send("server not on!");
} else {
// let routing continue
next();
}
});
This will keep your routes from ever getting run until server_on is back to true. If you have any routes you want to leave open all the time, then just place them before this middleware.
You can replace res.send("server not on!"); with whatever is appropriate for your use. You can return a single web page or you can send back a 4xx or 5xx error status (perhaps a 503 error).
I am trying to access my application-level middleware from router in a project generated with express application generator.
Middleware is used to query database with user ID received from router.
I feel like I'm missing something very simple (or fundamental) but can't get around the problem (this being my first Node.js project). So more than best practice I'm looking for a simple solution
I've tried using different app methods including post.
/app.js
var MyAppMidW = function (req, res, next) {
res.send(queryDB(req));
next()
}
app.use(MyAppMidW);
/routes/index.js
router.get("/dbquery", (req, res) => {
if (req.header('auth-header')) {
res.send(req.app.get.MyAppMidW(req.header('auth-header'))); //The problem
}
else {
res.send(req.app.get('defaultData')); //This works
}
});
Error messages include "$middleware is not a function" and "$middleware is not defined".
Solution
/app.js
app.MyAppMidW = function (req) {
queryDB(req);
}
/routes/index.js
router.get("/dbquery", (req, res) => {
if (req.header('auth-header')) {
req.app.MyAppMidW(req.header('auth-header'))); //Makes a database query
res.send(req.app.get('defaultData')); //Fetches database query result
}
else {
res.send(req.app.get('defaultData'));
}
});
If you do it like this
app.use(MyAppMidW);
Every request will query your db, and thats not what you want. I guess you use the MVC design pattern.
In your route folder you have something like this:
import appController from "../controllers/app.js"
router.get("/dbquery", appController.MyAppQuery)
And in your controllers folder you have your logic that querys the db
exports.MyAppQuery = (req, res){
//If u use mongodb for example
YourModel.find().then(data => {
res.json(data)
})
}
You need to call app.set("MyAppMidW", MyAppMidW) and then you can use get. Or do this inside the app.js file
app.MyAppMidW = function (req, res, next) {
res.send(queryDB(req));
next()
}
Then call it by req.app.get('MyAppMidW')(req.header('auth-header')) or req.app.MyAppMidW(req.header('auth-header')) inside the routes file.
But middleware is called automatically when you say app.use(MyAppMidW) the function is called by default on each request. So no need to call it explicitly inside the router function.
var express = require('express');
var router = express.Router();
var mongojs = require('mongojs');
var db = mongojs('mongodb://******:********#********.mlab.com:*****/XXXXXXXX_XXXX', ['XXXX']);
router.get('/tasks', function(req, res, next){
db.tasks.find(function(err, tasks){
if(err){
console.log('connection error!');
res.send(err);
}
res.json(tasks);
});
});
module.exports = router;
I have this simple code in node in which I am trying to connect to Mongo. I believe the process is quite straight-forward and I am following it right. Howver I get Authentication failed error every time. I checked the id password and they are just fine. Could someone tell me where I am going wrong?
router.get('/tasks', (req, res)) {
db.tasks.find()
.then(tasks => res.json(tasks))
.catch(err => res.status(500).json(err);
});
try that. you had it set up like the get was using a custom middleware component, and you were then passing a function into the .find() call. .find() will get all documents and returns a promise. .then() executes once the promise has been returned, and .catch() executes if .find() had an error.
I was wondering how to get this done in nodejs.
I have a .get that looks like this
app.get('/someurl', function(req, res) {
response = somefunc_call_to_server();
res.send(response);
});
But this will be a blocking call, how to change this to handle parallel requests at /someurl?
thanks,
vik.
Node does not expose any APIs that allow you to synchronously request data from a server. The key thing that you seem to be assuming is that a response must be sent to the server synchronously in the callback, but that is not the case. The socket open to the browser will stay connected until it either times out, or the application triggers .end either directly, or via Express's helper methods such as .send.
Generally you would accomplish your task with something like this:
app.get('/someurl', function(req, res, next) {
somefunc_async_call_to_server(function(err, data){
if (err) return next(err);
res.send(data);
});
});