I am having trouble with a project I am working on. I want to create a database in which I can store dates and links to YouTube videos in a MongoDB database. I am using Mongoose as the ORM. The problem seems to be that the database and collection is created and I can read and update it outside the routes but not inside (if anyone can understand what I am saying). I want to be able to make a GET request for the current items in the database on the /database route as well as make a POST to the /database route.
My code is below. Please help:
//grab express and Mongoose
var express = require('express');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//create an express app
var app = express();
app.use(express.static('/public/css', {"root": __dirname}));
//create a database
mongoose.connect('mongodb://localhost/__dirname/data');
//connect to the data store on the set up the database
var db = mongoose.connection;
//Create a model which connects to the schema and entries collection in the __dirname database
var Entry = mongoose.model("Entry", new Schema({date: 'date', link: 'string'}), "entries");
mongoose.connection.on("open", function() {
console.log("mongodb is connected!");
});
//start the server on the port 8080
app.listen(8080);
//The routes
//The route for getting data for the database
app.get("/database", function(req, res) {
Entry.find({}, function(err, data) {console.log(err, data, data.length); });
});
//The route for posting data on the database
app.post("/database", function(req, res) {
//test new post
var newMonth = new Entry({date: '1997-10-30', link: 'https://wwww.youtube.com/'});
newMonth.save(function(err) {
if (err !== null) {
//object was not save
console.log(err);
} else {
console.log("it was saved!")
};
});
});
//create an express route for the home page at http://localhost:8080/
app.get('/', function(req, res) {
res.send('ok');
res.sendFile('/views/index.html', {"root": __dirname + ''});
});
//Send a message to the console
console.log('The server has started');
Your GET request should have worked because a browser executes a GET request by default. Try the following.
app.get("/database", function(req, res) {
Entry.find(function(err, data) {
if(err) {
console.log(err);
} else {
console.log(data);
}
});
});
As far as testing your POST route is concerned, install a plugin for Google Chrome called Postman. You can execute all sorts of requests using it. It's great for testing purposes.
Related
I am writing a web application to display a web page with content from a PostgreSQL database using NodeJS, express and pg-promise.
I have a database javascript called "db/location.js" which query the location table.
var db_global = require('./db'); # db.js is for building the database connection
var db = db_global.db;
var locationList = [];
// add query functions
module.exports = {
getAllLocationList: getAllLocationList,
locationList: locationList
};
function getAllLocationList() {
db.any('select * from location')
.then(function (data) {
console.log(data);
locationList = data;
}
);
}
In the routes folder, I have a route javascript called "locationRoute.js".
var express = require('express');
var router = express.Router();
var db = require('../db/location');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
/* GET the map page */
router.get('/locations', function(req, res) {
db.getAllLocationList();
console.log(db.locationList);
res.render('locations', {
title: "Express and Leaflet API", // Give a title to our page
//jsonData: db.getAllLocations // Pass data to the View
jsonData: db.locationList // Pass data to the View
});
});
module.exports = router;
When "http://localhost:3000/locations" is called, this is supposed to render the "locations.jade" which is to display "db.locationList" in a table.
My issue is that "console.log(db.locationList);" is always called before the query was completed. This caused "db.locationList" (jsonData) to be empty.
I don't want to mess the controller layer with the database layer but how to fix the issue?
I think you should change your db/location.js to be something like this...
function getAllLocationList() {
return db.any('select * from location');
}
Then you would do something like this in your routes...
router.get('/locations', function(req, res) {
db.getAllLocationList()
.then(function(data) {
res.render('locations', {
title: "Express and Leaflet API", // Give a title to our page
jsonData: data // Pass data to the View
});
});
...
In your example console.log(db.locationList); runs before the data is available, because it's asynchronous. It doesn't work the way you're expecting it to work.
I'm building my first node/express app and am following this tut.
I am at a point where I am trying to get all JSON data and put it in an array to be sent to the template and rendered. When I try to run the app via CLI, I get the following error:
Directory Structure
The data output at the var blogsurlall location
hellotest.js
var routes = require('./routes/index');
var express = require('express');
var app = express();
var request = require("request");
var blogsurlall = "https://[JSON export URL location configured in a Drupal 8 view]";
app.set('view engine','ejs');
var server = app.listen (2000, function(){ console.log('Waiting for you on port 2000'); });
/* Get all global blogs data */
request({
url: blogsurlall,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
blogsdata_all = body;
}
// Create blogs array for footer.
var blogs = [];
// Fill up the array with blogs.
blogsdata_all.blogs.forEach(function(item){
blogs = blogs.concat(item);
});
app.locals.blogsdata = blogs;
});
app.use('/', routes);
index.js
var express = require('express');
var routes = express.Router();
routes.get('/', function(req, res){ res.render('default',{title: 'Home', body: 'blogsdata'}); });
routes.get('/about-us', function(req, res){ res.send('<h1>Lucius Websystems</h1>Amsterdam, The Netherlands'); });
routes.get('/about/:name?', function(req, res){ var name = req.params.name; res.send('<h1>' +name +'</h1>About text'); });
/* GET Blog detail page. */
routes.get('/blog/:blogid', function(req, res, next) {
// Place json data in a var.
var blogsdata = req.app.locals.blogsdata;
// Create array.
var blogItem = [];
// Check and build current URL
var currentURL = '/blog/' + req.params.blogid;
// Lop through json data and pick correct blog-item based on current URL.
blogsdata.forEach(function (item) {
if (item.title == currentURL) {
blogItem = item;
}
});
if (blogItem.length == 0) {
// Render the 404 page.
res.render('404', {
title: '404',
body: '404'
});
} else {
// Render the blog page.
res.render('blog-detail', {
blog: blogItem
});
}
});
module.exports = routes;
From the CLI error, it appears no blog data is even returned to be read into the array.
I have carefully gone through the tutorial several times and I think there are steps that may be implied that I am missing.
Can someone please help me understand how to get the blog data so that it can be read into the array and output to my template?
Also open to troubleshooting suggestions in comments.
Thanks for reading!
The error is raising in this line:
blogsdata_all.blogs.forEach(function(item){
As the error says, blogs is undefined.
If there is an error in the request or status code isn't 200, the body is not assigned to the variable, but you are not finishing the execution, so the variable in that case would be undefined.
Other possible problem is the json received doesn't have blogs as key of the body.
Check this both things and let us know if you found the problem
I've built a simple RESTful API using NodeJS, Mongoose, and Express. I am using the database to store simple string quotes and am not planning to allow access to any other users to the database nor to the api.
I've read up on securing my RESTful API but it seems as if most methods focus on using a username and password to limit access. However, that seems like an overkill for such a simple API especially since i do not consider on allowing anyone else access except for requests that come from the server itself.
So I want to make it so that if anyone else tries to access the API he would be denied access. The only way the API should be accessible is from requests from the server itself i.e from the JavaScript files on the server.
I am currently learning all those things so sorry if i am not using the proper technical terminology :)
I am considering doing something like checking the IP of the person/thing trying to access the API and if that is not the ip of the server then deny access. Would something like this work and how would I got about implementing it.
EDIT: I am looking for something simple since I dont think that most people will take the time to 'hack' the API just so they can access a database of quotes.
Here is my server.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var Quote = require('./mongodb/models/mainModel.js');
mongoose.connect('mongodb://localhost:27017/myappdb');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var port = process.env.PORT || 8080;
var router = express.Router();
function grantAccess(req) {
if(req.ip === '::1' ||
req.ip === '127.0.0.1' ||
req.ip === '::ffff:127.0.0.1') {
return true;
}
return ["IP Address Unknown " + req.ip]
}
router.get('/', function(req, res) {
res.json({ message: 'hooray! welcome to our api!' });
});
router.route('/maindb')
.post(function(req, res) {
var quote = new Quote();
quote.name = req.body.name;
quote.severity = req.body.severity;
quote.createdAt = new Date();
quote.updatedAt = new Date();
quote.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Quote created!' });
});
})
.get(function(req, res) {
if(grantAccess(req) !== 'boolean')
Quote.find(function(err, quotes) {
if (err)
res.send(err);
res.json(quotes);
});
});
router.route('/maindb/:quote_id')
.get(function(req, res) {
Quote.findById(req.params.quote_id, function(err, quote) {
if (err)
res.send(err);
res.json(quote);
});
})
.put(function(req, res) {
Quote.findById(req.params.quote_id, function(err, quote) {
if (err)
res.send(err);
quote.name = req.body.name;
quote.severity = req.body.severity;
quote.updatedAt = new Date();
// save the bear
quote.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Quote updated!' });
});
});
})
.delete(function(req, res) {
Quote.remove({
_id: req.params.quote_id
}, function(err, quote) {
if (err)
res.send(err);
res.json({ message: 'Successfully deleted' });
});
});
app.use('/api', router);
app.listen(port);
console.log('Magic happens on port ' + port);
you can add apiKey in your project. It will be required if anyone hits any of your api.
exmaple:
"apiKeys": {
"web": "7fe642cabe6855cd4175937fa8fadd876c1af6b499ab941db6a8a362c0f30f97"
}
similarly you can set apikey for mobile user or accordance to requirment of project.
Link to genrate RandomKey
By this you will allow only those users who have your api key.As api key is shared by you so you will provide it to only appropriate user.
Api key checking:
You can check api key as first middleware before any request to server
example:
router.use(function(req,res,next){
var apiKey = req.get('api_key'); // assuming user will send api key in headers
// code to check api key basic comparison
})
So im trying to get a name with a click from the client, and send the name ( which i changed to json in order to actually be able to send the info) it to the server . Right now the server sends it back, and the client posts it to the index page (which im doing just so i can see the data that the server is getting). When i see the data its showing up as [object Object]. So Something is going wrong, im hoping someone can help me out.
index.html
<body>
<div ng-app="myApp" ng-controller="customersCtrl">
<table style="width:100%">
<tr ng-repeat="contact in databases.databases">
<td>{{ contact.name }} <button type="button"ng-click="addContactlist(contact.name)">Click Me</button></td>
<td>{{ contact.sizeOnDisk }} </td>
<td>{{ contact.empty }} </td>
</tr>
</table>
DB name clicked: <p ng-bind="DB_NAME"></p>
</div>
</body>
client.js
var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope, $http) {
console.log("controller connected");
function refresh(){
// create contacklist route
$http.get('/databases').success(function(response) {
console.log("recived data requested");
$scope.databases = response;
});
}
// Call refresh to init cantacklist
refresh();
// add Doc to table
$scope.addContactlist = function(contactItem) {
alert("Working ");
$http.post('/collection', JSON.stringify({'contactItem': contactItem})).success(function(response) {
$scope.DB_NAME = response ;
});
console.log("posted: "+contactItem);
};
});// Controller
server.js
var express = require('express');
var path = require('path'); //core module
var databaseUrl = "localhost:27017/DB"; // default env
var bodyParser = require('body-parser');
var Db = require('mongodb').Db,
MongoClient = require('mongodb').MongoClient,
Server = require('mongodb').Server,
ReplSetServers = require('mongodb').ReplSetServers,
ObjectID = require('mongodb').ObjectID,
Binary = require('mongodb').Binary,
GridStore = require('mongodb').GridStore,
Grid = require('mongodb').Grid,
Code = require('mongodb').Code,
assert = require('assert');
//configure app
var app = express();
var db = new Db('DB', new Server('localhost', 27017));
db.on('error', function (err) {
console.log('database error', err)
});
db.on('connect', function () {
console.log('database connected')
});
// store all html files in views
app.use(express.static(__dirname + '/views'));
// parses recived json input
app.use(bodyParser.json());
// store all js in Scripts folder
app.use(express.static(__dirname + '/scripts'));
// Technology not needed but good practice, especailly when serval people are working on it
app.get('/', function (req, res) {
res.sendFile('index.html');
});
// listen for contactlist get request, aka transfers the contacklist in mongo to client
app.get('/databases', function (req, res) {
console.log("-- recived GET request --");
db.open(function(err, db) {
// Use the admin database for the operation
var adminDb = db.admin();
// List all the available databases
adminDb.listDatabases(function(err, dbs) {
assert.equal(null, err);
assert.ok(dbs.databases.length > 0);
console.log(dbs);
res.json(dbs);
db.close();
});
});
});
// listen for contactlist get request
app.post('/collection', function (req, res) {
console.log("-- recived collection post request --");
console.log('req ' + req.body);
res.json(req.body);
db.open(function(err, db) {
// Grab a collection without a callback no safe mode
// once request is working will switch to re.body
var col1 = db.collection('DB');
});
});
// Implement a web server to listen to requests
app.listen(4444, function(){
console.log('ready on port 4444');
});
With fix
The response is an object, try this:
DB name clicked: <p ng-bind="DB_NAME | json"></p>
json filter converts the object in JSON notation: https://docs.angularjs.org/api/ng/filter/json
I'm using Node.JS + Express.JS + Multer to handle file uploads. The problem is that I need to query the database to see if a file with this name has been uploaded in the past. If it hasn't been uploaded, then it should be accepted. Otherwise, the file should not be accepted. I'm trying to get this to work using the onFileUploadStart function; however, the database query is asynchronous and I see no way to return false given that the result of the query appears in a callback. If there is a way to execute the query synchronously, my goal will be easy to accomplish. Here is the code:
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var connection = mysql.createConnection({
//connection details
});
router.post('/upload', multer({
onFileUploadStart: function(file, req, res) {
var queryString = "SELECT count(fileName) as count FROM table WHERE fileName = ?;",
queryInserts = [file.originalname];
queryString = mysql.format(queryString, queryInserts);
connection.query(queryString, function(err, rows) {
if (err) {
// handle error
} else {
if (rows[0].count > 0) {
// file should not be accepted
} else {
// file should be accepted
}
}
});
},
dest: "./uploads/"
}), function(req, res) {
// do other stuff
});
Any ideas of how I can accomplish this will be greatly appreciated. Thanks.
My quick reaction would be to use promises. You could have your onFileUploadStart handler create a deferred, assign its promise to the active request object and handle the resolution or rejection of the promise. Then in the main handler for the upload route, you could use then.
I believe this would basically be the new code as applied to your current code. I Note that I am using the Q promises library, but there are other options (promises are also built into ES6 if you are using it).
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var Q = requires('q');
var connection = mysql.createConnection({
//connection details
});
router.post('/upload', multer({
onFileUploadStart: function(file, req, res) {
var deferred = Q.defer();
req.fileUploadPromise = deferred.promise;
var queryString = "SELECT count(fileName) as count FROM table WHERE fileName = ?;",
queryInserts = [file.originalname];
queryString = mysql.format(queryString, queryInserts);
connection.query(queryString, function(err, rows) {
if (err) {
// handle error
deferred.reject('You had an error...');
} else {
if (rows[0].count > 0) {
// file should not be accepted
deferred.reject('You had a duplicate file');
} else {
deferred.resolve(file); // ?? or something useful
// file should be accepted
}
}
});
},
dest: "./uploads/"
}), function(req, res) {
req.fileUploadPromise
.then(function(successResult){
// do other stuff
res.status(200).send('success');
})
.catch(function(errorResult){
// read the error result to provide correct code & error message for user
})
.done();
});