I would use sockets in a separate route file .
I'm using the method mentioned in this answer : Express 4 Routes Using Socket.io
I have copied exactly the same logic. In server file :
var http = require("http");
var admin = require('firebase-admin');
var firebase = require("firebase");
var express = require("express");
var app = express();
var bodyParser = require("body-parser");
var port = process.env.app_port || 8080; // set our port
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var server = app.listen(port);
var io = require("socket.io")(server);
var routerProj = require("./routes/routes")(io);
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT ,DELETE');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,*");
next();
});
var config = {
.... DB Configuration ....
};
firebase.initializeApp(config);
var serviceAccount = require("./ServiceAcountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://datatable-18f93.firebaseio.com"
});
io.on("connection", function (client) {
console.log("Un client est connecté !");
//routerProj(client);
});
app.use("/v1", routerProj, function (req) {
//Create HTTP server and listen on port 8000 for requests
});
My connection socket is working and the console.log runs in terminal
routes.js file
var express = require("express"); // call express
var router = express.Router(); // get an instance of the express Router
var admin = require("firebase-admin");
var returnRouter = function (client) {
router.use(function (req, res, next) {
// do logging
client.on('save-message', function (socket) { console.log("heheyy") })
});
router
.route("/")
.get(function (req, res, err) {
// Get a database reference to our posts
var db = admin.database();
var ref = db.ref("/");
// Attach an asynchronous callback to read the data at our posts reference
ref.once("value", function (snapshot) {
var list = [];
snapshot.forEach(function (elem) {
list.push(elem.val());
})
list = JSON.stringify(list);
//list = JSON.parse(list)
console.log(err);
//console.log(JSON.stringify(list))
res.send(list);
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
res.status(500).send(errorObject.code);
});
});
router
.route("/")
.post(function (req, res, err) {
console.log(req.body);
// Get a database reference to our posts
var db = admin.database();
var ref = db.ref("/");
ref.push(
{
"text": req.body.text
}
);
});
return router;
}
module.exports = returnRouter;
save-message is emit in Angular when my arr is running :
ngOnInit() {
this.socket.emit('save-message', { room: "hello" });
}
Save-message event is not getting read neither the routes file, In my angular application services does not get data from routes. and console.log in get and post routes does not work.
My question is how to get sockets working in a reparate file ?
You should move the socket.io listener outside of the express use route. It's not really clear why you would want it there as it will register a new listener every time someone makes a request to your v1 endpoint.
You likely aren't seeing the messages because the listener does not register until someone makes a request to the v1 endpoint and the client already sent its message.
var returnRouter = function (client) {
// do logging
client.on('save-message', function (socket) {
console.log("heheyy");
});
...
};
Related
I am trying to develop an API that allow POST request of file data, but the POST request only functions using curl curl -X POST --data file= mouse.fa "http://localhost:3000/api/data?file=mouse.fa" . When I trying a POST request in the browser, I get a GET error Cannot GET /api/data. Please could you advise me on how to get the POST request to work in the browser in addition to curl.
router.js
const fs = require('fs');
const express = require('express');
const bodyParser = require('body-parser');
fileParser = require("./fileParser")
router.use('./fileParser', fileParser.parse);
// middleware
router.use(function (req, res, next) {
console.log('Received request');
next();
});
router.post('/data', function (req, res) {
//Check file is valid
if (!req.body.file.toString().endsWith('.fa')) {
res.status(400).json({ message: "Bad Request" });
} else {
fileParser.parse(`./${req.body.file.toString()}`);
res.json({ message: "File parsed and data submitted.", location: "/data/" });
}
});
server.js
const express = require('express');
// create server
const app = express();
const port = 3000;
app.listen(port, function () {
console.log(`Server running at ${port}`)
});
// import router
const router = require('./router');
app.use('/api', router)
I am using cookie-parser in my express app. When the root page is requested I set a random number on the cookie using res.cookie(name, value) and it sets it fine (I checked on my browser console). But when I try to log req.cookie it always returns undefined.
Here's my code:
routes.js
var express = require('express')
var router = express.Router()
var movieTrailer = require('movie-trailer');
var Promise = require('bluebird');
var logs = require('log-switch');
var fs = require('fs');
//var cookieParser = require('cookie-parser');
//Setup x-ray for scraping
var Xray = require('x-ray');
var x = Xray();
var debug = false;
router.get('/', (req, res) => {
console.log('Page requested!');
console.log('Cookies: ', req.headers.cookies); // For some reason this returns undefined
var scrapeMovies = function(){
return new Promise((resolve, reject) =>{
fs.readFile('moviesRT.json', (err,data) =>{
var movies = JSON.parse(data);
resolve(movies);
});
});
};
scrapeMovies().then(
movies => {
var randomInt = Math.floor(Math.random() * movies.length);
res.cookie('randomInt', randomInt);
var randomMovie = movies[randomInt];
movieTrailer(randomMovie.title, (err, url) =>{
console.log('Requesting trailer: ', randomMovie.title);
if(err) throw err;
var embedUrl = url.replace('watch?v=','embed/');
console.log('Video ID: ', url.slice(32,url.length));
randomMovie.trailerURL = embedUrl; //Add the embed URL to the randomMovie object before rendering it
res.render('main',randomMovie,
(err, html) =>
{
if(err) throw err;
console.log('Rendering...');
res.send(html);
console.log("Done!");
});
});
});
});
module.exports = router;
app.js
const express = require('express');
//Define app and settings
const app = express();
const exphbs = require('express-handlebars');
var cookieParser = require('cookie-parser');
const port = 3000;
var routes = require('./routes');
var debug = true;
app.use('/', routes);
app.use(express.static('public'));
app.use(cookieParser());
//app.use(cookieParser());
//View engine
app.engine('handlebars', exphbs({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
app.listen(port, function () {
console.log(`Server Starts on ${port}`);
if(!debug) logs.disable(); //Disable logging if debug variable is false
});
You either want to check req.headers.cookie which will be set by express.
Or if you want to use the the parsed result of the cookie-parse middleware that is stored inreq.cookies then your problem is the order in which you register your routes and the middleware.
app.use('/', routes);
app.use(express.static('public'));
app.use(cookieParser());
The parsing of the cookie is done after the routes in routes have ben executed.
You need to move the cookieParser() before the route where you want to use it.
app.use(cookieParser());
app.use('/', routes);
app.use(express.static('public'));
This solved my problem:
Basically when you are sending a request to the server from client-side, make sure you add withCredentials: true. For example
{
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json'
}),
'withCredentials':true
};
This happened to me, when I sent a PUT request from the client-side (Angular) without passing the body object.
I was doing this (second argument missing):
requestBranchEditPermission() {
return this.http.put<IPutProfile>(`${this.api}/some-endpoint`, this.options).toPromise();
}
instead of this:
requestBranchEditPermission() {
return this.http.put<IPutProfile>(`${this.api}/some-endpoint`, {}, this.options).toPromise();
}
You will need to read the cookies as req.cookies['cookie-name'] and set the cookies as resInit.cookie('cookie-name', 'cookie-value')
This worked for me
in the frontend add credentials : 'include' as an option to your fetch API
A more elaborated code below for a get request
fetch('url', {credentials: 'include'})
.then(res => res.json())
.then(data => //do something with the data)
.catch(err => console.log(err.message));
I have a really simple backend with a couple routes. I want to keep the route logic outside the server.js file but for some reason when I do a POST request to the route it gives me a 404.
server.js
// Call packages
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var morgan = require('morgan');
var config = require('./config.js');
var mongoose = require('mongoose');
var path = require('path');
var mandrill = require('mandrill-api/mandrill');
var mandrill_client = new mandrill.Mandrill(config.mandrillApi);
var favicon = require('serve-favicon');
// Set up morgan to log HTTP requests
app.use(morgan('dev'));
// Set up mongo database
mongoose.connect(config.database);
// Parse body
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Server favicon
app.use(favicon(path.resolve('../client/content/images/logos/website-brand.png')));
//Routes
app.use('/sendMail', require(__dirname + '/routes/sendMail.js'));
// Default Routes
app.get('/', function (req, res) {
res.sendfile(path.resolve('../client/views/index.html'));
});
app.get('/:name', function (req, res) {
res.sendfile(path.resolve('../client/views/index.html'));
});
//Serve static files
app.use(express.static(path.resolve('../client')));
app.use('/scripts', express.static(path.resolve('../node_modules/angular-ui-bootstrap')));
app.use('/scripts', express.static(path.resolve('../node_modules/requirejs')));
//Log requests
app.use(function (req, res, next) {
console.log(req.method, req.url);
next();
});
//Start server
app.listen(config.port, function() {
console.log('I\'m listening on port ' + config.port);
});
And sendMail.js
var config = require('../config.js');
var express = require('express');
var router = express.Router();
var mandrill = require('mandrill-api/mandrill');
var mandrill_client = new mandrill.Mandrill(config.mandrillApi);
// Routes
router.post(sendMail);
module.exports = router;
function sendMail(req, res, next) {
console.log("Receiving in sendMail");
var name = req.body.name;
var email = req.body.email;
var message = req.body.message;
var toSend = {
"html": "<p>"+message+"</p>",
"text": message,
"subject": "From Website",
"from_email": email,
"from_name": name,
"to": [{
"email": "",
"name": "",
"type": "to"
}]
};
mandrill_client.messages.send({"message": toSend}, function(result) {
console.log(result);
var status = result[0].status;
if (status == 'sent') {
res.send({success: true});
} else {
res.send({success: false, reason: status});
};
}, function(e) {
console.log("Mandrill Error: "+e.message);
res.send({success: false, error: e});
});
next();
};
But when I do a POST request to /sendMail it gives me a 404
enter image description here
In sendMail.js remove at the end of file :
next();
because in this route your responses are in async callback, and before they are invoke, node.js get next() and therefore it move to next router. Because there is no more accurate routes it return 404.
One offtopic in server.js:
Move your log request before sendMail router.
I am pretty new with node.js and express so bear with me please.
I am wondering how i can get a mysql instance and use it in my controller. I have 4 files that look like this:
see my comment in the controller.js file
server.js :
var express = require('./config/express');
var app = express();
module.exports = app;
app.listen(3000);
console.log('server running');
express.js :
var express = require('express'),
bodyParser = require('body-parser'),
mysql = require('mysql');
module.exports = function() {
var app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.set('views','./app/views');
app.set('view engine','ejs');
//NOT SURE WHAT TO DO HERE OR WHERE TO PUT THE CONNECTION DETAILS
var dbConnection = mysql.createConnection({
host : 'localhost',
user : 'someuser',
database : 'somedb',
password : 'somepass'
});
//connection.connect();
//
//connection.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
// if (err) throw err;
// console.log('The solution is: ', rows[0].solution);
//});
//
//connection.end();
require('../app/routes/index.server.routes.js')(app);
app.use(express.static('./public'));
return app;
};
routes.js :
module.exports = function(app) {
var index = require('../controllers/index.server.controller');
app.get('/', index.render);
app.post('/', index.stuff);
};
controller.js :
exports.render = function(req, res) {
//DO DB STUFF HERE
res.render('index', {
title: 'this is the title'
});
};
exports.stuff = function(req, res) {
res.render('index', {
title: 'this is the title post'
});
};
To use the connection instance in your controller, you'll need to pass it from the express.js file to the controller.js file. The first step is to pass the connection instance to the router:
express.js
require('../app/routes/index.server.routes.js')(app, connection);
This will make it available in the routes.js file. You then need to pass the same connection instance to the controller.
index.server.routes.js
module.exports = function(app, connection) {
var index = require('../controllers/index.server.controller')(connection);
app.get('/', index.render);
app.post('/', index.stuff);
};
The controller will need to be refactored so it takes a connection instance as an argument:
index.server.controller.js
function IndexController(connection) {
controllerMethods = {};
controllerMethods.render = function (req, res) {
// You can use the connection instance here.
connection.connect()
// Run your query
connection.end()
...
};
// Define other methods for the controller
// Return the object that holds the methods.
return controllerMethods;
}
module.exports = IndexController;
I have loads of router.get functions in my code which I think, could be reduced to a single switch-case function. Here is what I have tried:
function handlerA(req, res) {}
function handlerB(req, res) {}
var routes = {
'/url-one': handlerA,
'/url-two': handlerB
}
router.get('/*', function(req, res) {
var url = req.url;
if (routes[url]) {
routes[url](req, res);
}
});
This works but also, significantly slows my application. Is there any other solution which would not hit the performance of my app?
Thanks
Is there a reason you don't want to use router.get functions? I would guess express.js is internally performing the same logic that you are doing anyway. You are just replacing get functions with handlers.
If you are using similar logic between multiple routes, that may be worth abstracting.
I usually go with a setup like this:
app.js
routes.js
api/
user/
index.js
user.controller.js
user.model.js
image/
index.js
image.controller.js
image.model.js
/api/user/index.js:
var express = require('express');
var controller = require('./user.controller');
var router = express.Router();
router.get('/', controller.index);
router.post('/', controller.create);
module.exports = router;
/api/user/user.controller.js:
var User = require('./user.model');
exports.index = function(req, res) {
// Show list of users
};
exports.create = function (req, res, next) {
// Create user
};
/routes.js:
module.exports = function(app) {
// Insert routes below
app.use('/api/users', require('./api/user'));
app.use('/api/images', require('./api/image'));
// All undefined asset or api routes should return a 404
app.route('/:url(api|auth|components|app|bower_components|assets)/*')
.get(errors[404]);
// All other routes should redirect to the index.html
app.route('/*')
.get(function(req, res) {
res.sendfile(app.get('appPath') + '/index.html');
});
};
And lastly, the /app.js:
// Set default node environment to development
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var express = require('express');
var mongoose = require('mongoose');
var config = require('./config/environment');
// Connect to database
mongoose.connect(config.mongo.uri, config.mongo.options);
// Populate DB with sample data
if(config.seedDB) { require('./config/seed'); }
// Setup server
var app = express();
var server = require('http').createServer(app);
require('./config/express')(app);
require('./routes')(app);
// Start server
server.listen(config.port, config.ip, function () {
console.log('Express server listening on %d, in %s mode', config.port, app.get('env'));
});
// Expose app
exports = module.exports = app;
Most of this is directly from the Yeoman Generator Angular-Fullstack and it has a really nice setup!