In Sails.js 0.10.5, I want to replace bodyParser for specific paths. For example, use a different body parser for path '/app/upload' and for the rest use the default. How do I do this?
You can do this by overriding config/http.js. Add your custom parser to the middleware, and replace bodyParser in the order with your custom parser.
Something like this should work
module.exports.http = {
middleware: {
superBodyParser: function (req, res, next) {
if (req.path === '/app/upload') {
// your custom parser
}
else {
require('skipper')(req, res, next);
}
},
order: [
'startRequestTimer',
'cookieParser',
'session',
'myRequestLogger',
// 'bodyParser', <-- not required anymore
'superBodyParser'
'handleBodyParserError',
'compress',
'methodOverride',
'poweredBy',
'$custom',
'router',
'www',
'favicon',
'404',
'500'
]
}
};
Related
I want to use the Ltijs library (https://cvmcosta.me/ltijs) in our Sails application.
The way to deploay Ltijs as part of another express server is this (from Ltijs documentation):
const app = express()
lti.setup('EXAMPLEKEY', { url: 'mongodb://localhost/database' })
// Start LTI provider in serverless mode
await lti.deploy({ serverless: true })
// Mount Ltijs express app into preexisting express app with /lti prefix
app.use('/lti', lti.app)
The way to put middleware into Sails is something like that (without app.use(...)!):
// config/http.js
const lti = require('ltijs').Provider;
lti.setup(
'8swieleivBef',
{url: 'mongodb://localhost:27017/mysailsapp'},
);
lti.deploy({serverless: true});
module.exports.http = {
middleware: {
order: [
'cookieParser',
'session',
'bodyParser',
'ltiExpressAdapter', //<-------- my middleware adapter -----------------
'compress',
'poweredBy',
'router',
'www',
'favicon',
],
ltiExpressAdapter: lti.app, //<-------- my middleware adapter -----------------
.
.
.
The latter works, but it works to "good", because now every request is caught by Ltijs and the application doesn't work anymore.
My Question is, how do I bring the path '/lti' from app.use('/lti', lti.app) into the sails game?
I tried lots of things like this that didn't work:
ltiExpressAdapter: (function () {
return async function (req, res, next) {
if (req.path.match(/^\/lti.*$/)) {
return lti.app;
}
return next();
};
})(),
Thanks in advance for help!
Seems I found a solution using app.use(...):
// config/http.js
const express = require('express'); //<------ NEW -----
const app = express(); //<------ NEW -----
const lti = require('ltijs').Provider;
lti.setup(
'8swieleivBef',
{url: 'mongodb://localhost:27017/ltijsdb'}, //<------ (NEW) -----
);
lti.deploy({serverless: true});
module.exports.http = {
middleware: {
order: [
'cookieParser',
'session',
'bodyParser',
'ltiExpressAdapter', //<-------- my middleware adapter -----------------
'compress',
'poweredBy',
'router',
'www',
'favicon',
],
ltiExpressAdapter: app.use('/lti', lti.app), //<------ NEW -----
.
.
.
Now I get the expexted error message from Ltijs only when I call the /lti path (http://localhost:1337/lti) and the rest of the application runs like before.
Now I hopefully can go on setting up Ltijs and try to connect from a test consumer.
(I also changed the Ltijs DB so that it isn't mixed up with my App's DB.)
So I am sending data of a mission, the startdate and the finish date. However I am not able to put any changes into the database as it believes I get an immutable error with mongoDB... I would like to stick with using the .then method for my js code.
My other methods are working properly, I just can't get this update method right...
app.put('/missions/:id', function (req, res) {
if (req.user) {
model.Mission.findById(req.params.id).then(function(Mission){
console.log("req.body.secret_mission: ",req.body.secret_mission)
Mission['secret_mission'] = req.body.secret_mission;
Mission['start'] = req.body.start;
Mission['complete'] = req.body.complete;
Mission.update().then(function(){
res.set('Access-Control-Allow-Origin', '*');
res.sendStatus(201);
});
});
}else{
res.sendStatus(401);
}
});
Error I receive in the command line
I was able to use all the help provided to come up with a working solution and keep consistent to how I am calling the rest of my code. A big thanks to those that responded!!
Rather than setting the elements in my collection beforehand I am supposed to do it in the update request. Instead of calling 2 methods I used the findOneAndUpdate.
app.put('/missions/:id', function (req, res) {
if (req.user) {
model.Mission.findOneAndUpdate(
{'_id' : req.params.id},
{ $set: {"secret_mission" : req.body.secret_mission,
"start" : req.body.start},
"complete" : req.body.complete
}).then(function(err, missions){
if (err) return res.json({Error: err});
res.json(missions);
});
} else {
res.sendSatus(401);
}
});
I've cleaned up Your code:
removed req.user check to middleware,
included cors module to not to play with CORS headers in every handler
used async/await stuff to give it more synchronous look
mission/:id route handler just have concrete logic without garbage
Check this solution:
const cors = require('cors'); // install: npm i --save cors
const _ = require('lodash'); // install: npm i --save lodash
app.use(cors());
const isUserAuthorized = (req, res, next) => {
if (!req.user) return res.status(401).send();
next();
}
app.put(
'/missions/:id',
isUserAuthorized,
async (req, res) => {
try {
const mission = await model.Mission.findById(req.params.id);
if (!mission) return res.status(404).send();
mission.set(_.pick(req.body, ['secret_mission', 'start', 'complete']);
await mission.save();
res.status(201).send();
}
catch (error) {
console.log(error);
res.status(500).send();
}
});
or if You don't care if record in db exist or not, so You can just push update directly:
app.put(
'/missions/:id',
isUserAuthorized,
async (req, res) => {
try {
const data = _.pick(req.body, ['secret_mission', 'start', 'complete']);
await model.Mission.update({_id: req.params.id}, {$set: data});
res.status(201).send();
}
catch (error) {
console.log(error);
res.status(500).send();
}
});
I'm creating a simple app to practice connecting Vue to an Express server. I have a form that I'm attempting to send to the back end, but I can't seem to get my data to the back-end.
The error I'm receiving is:
POST http://localhost:8080/login 404 (Not Found)
My best guess is that the method in my Vue can't find a matching route on my server? If so, I'm confused as I have a route for login.
In my Vue script:
const axios = require('axios');
export default {
data: function() {
return {
user: {
email: '',
password: ''
}
}
},
methods: {
sub() {
var user = {
email: this.user.email,
password: this.user.password
}
axios.post('/login', user)
.then(res => console.log(res))
.catch(err => console.log(err))
}
}
}
On by back-end:
const path = require('path');
const express = require('express');
const app = express();
app.use(express.static(path.join(__dirname, '..')));
app.post('/login', function(req, res) {
console.log("Server HIT!!!!!!!!!!!!!!!!!!!!")
})
app.get('*', function (req, res) {
return res.sendFile('../index.html');
});
app.listen(3000);
console.log('Express server listening on port 3000');
Express is running on another port than your vue application. Vue is standard http which is 8080, but express runs on 3000 with this line:
app.listen(3000);
You are sending the request to /login, which from the point of view of your frontend is http://localhost:8080, but that's not where express is available.
Basically all you have to do is send the request to http://localhost:3000/login, simple as that.
By default express do not allow cross origin request i.e CORS. You have to enable it by setting middleware. add below lines in you server file and must be before declaring any routes
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
I am trying to use connect-flash with sails.js, according to middleware documentation of sailsjs http://sailsjs.org/documentation/concepts/middleware , this is what I did
passportInit : require('passport').initialize(),
passportSession : require('passport').session(),
flash : require('connect-flash'),
order: [
'startRequestTimer',
'cookieParser',
'session',
'passportInit',
'passportSession',
'flash',
'myRequestLogger',
'bodyParser',
'handleBodyParserError',
'compress',
'methodOverride',
'poweredBy',
'$custom',
'router',
'www',
'favicon',
'404',
'500'
]
and this is how my AuthController.js looks ( as I am using connect-flash with passport )
module.exports = {
_config: {
actions: false,
shortcuts: false,
rest: false
},
'login': function(req, res,next) {
passport.authenticate('local', { successRedirect: '/user/dashboard',
failureRedirect: '/login',
failureFlash: true })(res,req,next);
},
'logout': function(req, res) {
req.logout();
res.redirect('/');
}
};
But after adding flash in the queue pages never finish loading and it never renders. Please can anybody assist me with this? I am not sure how to make this work. Thanks in advance.
I've had more success with Express' flash module.
In my config/http.js:
middleware : {
flash : require('flash')(),
...
order : [
...
'passportInit',
'passportSession',
'flash',
'bodyParser',
...
],
...
}
I spent quite some time and was not able to get this package working with sales, I am sure I must be missing something, However I found another package sails-hook-flash that is plug and play for sails app.
I'm trying to integrate opbeat with sails.js. They have a node.js client which includes middleware support for Connect and Express.
I've tried to create a custom middleware in http.js
module.exports.http = {
middleware: {
opbeat : require('opbeat')({
organizationId: '...',
appId: '...',
secretToken: '...'
}),
order: [
'opbeat',
'startRequestTimer',
'cookieParser',
'session',
'myRequestLogger',
'bodyParser',
'handleBodyParserError',
'compress',
'methodOverride',
'poweredBy',
'$custom',
'router',
'www',
'favicon',
'404',
'500'
],
}
};
Unfortunately it doesn't work. If you could please help point me in the right direction.
The value returned from the initializer function isn't a proper middleware function (it's just an Opbeat client). To get the middleware function, call middleware.connect() on the client:
var opbeat = require('opbeat')({
organizationId: '...',
appId: '...',
secretToken: '...'
})
module.exports.http = {
middleware: {
opbeat: opbeat.middleware.connect(), // get the Opbeat middleware function
order: [
... // put the bulk of your middleware here
'opbeat'
]
}
}
P.S. The function is called middleware.connect() because it was the connect module that set the standard of having a middleware function that expects the 3 arguments; Request, Response and Callback. An alias exists that is called middleware.express() - but it's just that: An alias.
Update:
I reversed the order of the middleware in the example above so that Opbeat is placed at the end. This is important to that that it can catch errors tickling down the middleware-chain.