KoaJS middleware and database access - node.js

If I had this to show an index for a users model:
app.use(route.get('/user', list));
function *list() {
var res = yield users.find({});
this.body = res;
};
Is it possible to put the database access part into its own middleware and then call next?
How could you pass the resulting list of users down to the next middleware? And somehow pass next through the route?
So the first middleware is any DB access needed, and the second middleware is presentation?

Essentially you attach the information to the request context or the this keyword within the middleware.
I created a screencast on writing middleware that might be helpful:
http://knowthen.com/episode-4-writing-middleware-in-koajs/
Here is an example of how you would pass information to downstream middleware.
let koa = require('koa'),
users = require('./users'),
app = koa();
function *firstMiddleWare (next) {
this.session = {
user: yield users.find({});
}
yield next;
}
function *secondMiddleware (next) {
// this.session.user is available here
yield next;
}
app.use(firstMiddleWare);
app.use(secondMiddleware);
app.use(function *(){
// this.session.user is available here as well
this.body = this.session.user;
});
app.listen(3000);

Related

Pass parameter to middleware function and return result

So guys, what I want to accomplish and not manage to get is to write a function that performs a query against database as a middleware, using req and res objects, and also can be used in a socket connection, to pass parameters to it and not use the req and res objects. Also I want it to return the result of the query. I tried using a middleware wrapper
function myFunc(param1, param2){
return (req, res) => {
here query
}}
works when hitting the endpoint with or without args i send, but dosnt work when i call the function from somewhere else
When you call myFunc you get returned a new function. You need to invoke that funcion, something like
myFunc('value1', 'value2')()
This will cause an error since you have no request or response object. These are express objects.
A better way to re-use the database code would be to put it in a function and inject that function to the middlewere.
E.g.
function getArticleById(id) {
return db.query('select * from articles where id = $1', [id])
}
Then create a middlewhere that takes this function in as dependency
function makeMiddlewere (getArticleById) {
return (req, res) => {
return articleById(req.query.id).then(articles => {
res.json(articles)
})
}
}
Then in your code you can do
Normal way
getArticleById(5).then(articles => {
console.log(articles)
})
Create the middlwere an
const express = require('express')
const getArticleById = require('./articlebyid')
const makeMiddlewere = require('./makemiddlewere')
const middlwere = makeMiddlwere(getArticleById)
const app = express.app
app.get('/article', middlewere)

Pass object initialized via express middleware to next middleware

Below is my setup, I am trying to pass an object that is initialized in express middleware to a different middleware function. In my router, Invoke helper.getValues() and get an error that I cannot invoke function getValues of undefined
let helper; // no initial value
const getConfig = async () => {
config = await service.getConfig(configName);
helper = new Helper(config); // Helper is correctly initialized here
};
// declare a new express app
let app = express();
app.use(async function (req, res, next) {
try {
await getConfig(); // invoke the code that initializes my helper
next();
} catch (e) {
console.error(e);
}
});
app.use('/path', MyRouter(helper)); // Pass helper to router - it's undefined in router code
My Router Constructor looks like this
function MyRouter(helper) {
...
... const values = helper.getValues();
}
What is the correct way to pass the helper that is created in getConfig to my router?
Pass it via req or res depending on your intent.
If the data relates to the request such as the requesting user's identity, the session attributes, geoIP or parsed request body then attach it to the req object:
If the data relates to response processing such as variables used by templates/views or requested response format then attach it to the res object.
Assuming you want to pass it via req:
req.helper = await getConfig();
Then to use it:
function router (req, res) {
const values = req.helper.getValues();
// ...
}

Express require a query parameter

Let's say I have a route /ressource. I can call this route with a query parameter /ressource?param=ABCwhich I can retrieve in Node with:
app.get('/ressource', function (req, res) {
const parameter = req.query.param
})
Now, is there a predefined way I can require the parameter which throws an error for request to /ressource without ?param=ABC.
You can use req.query to get the query parameter and use next callback function to throw an error like
app.get('/ressource', function (req, res, next) {
if(!req.query.param) {
const err = new Error('Required query params missing');
err.status = 400;
next(err);
}
// continue
const parameter = req.body.param
})
In express, query is automatically parsed and put into the req.query object, not the req.param object.
So you can access it like this:
const parameter = req.query.parameter;
read req.query on expressjs docs.
There are no predefined way to.
You can choose to check it yourself inside the callback function:
if (!req.query.parameter) {
res.send('parameter is missing');
}
or to use a router middleware which would serve the same purpose

Getting "Function: Bound" when trying to call a method

I'm using the Sails.js MVC and I'm trying to setup a service so I can make a call to an Active Directory server and pass the data for a user back to my controller.
I'm using some internal company modules for this which connect to our servers and pass back a user array with all the data for a selected user.
If I do this by making a function directly in the API controller it works fine, but when doing it by calling through a function from a separate file, rather than returning an array of [Function: bound].
Code from controller (LabController.js):
var adGet = require('../services/adGet');
module.exports = {
test: function (req, res) {
console.log(adGet.userData);
res.view({
user: adGet.userData
});
}
}
Code from the service (adGet.js):
module.exports = {
userData: function (req, res) {
var ad = require('active-directory');
ad.setCredentials({
user: 'username_removed',
password: 'password_removed'
});
ad.getUser(req.session.sisso.idsid).then(function (user) {
return (user);
});
}
}
Any help is greatly appreciated.
There's a few issues here.
First, you're trying to use return in your userData service method to return data, but it's an asynchronous function so that return statement is sending the data anywhere. You need to pass in a callback function as an argument to userData that can be called when the data is ready (i.e. when the database query returns):
module.exports = {
// note the new `cb` argument
userData: function (req, res, cb) {
var ad = require('active-directory');
ad.setCredentials({
user: 'username_removed',
password: 'password_removed'
});
ad.getUser(req.session.sisso.idsid)
.then(function (user) {
// Still nice to use `return` to make sure nothing
// gets executed after this statement, but it's the
// callback function that actually gets the data.
// Note the `null` first argument, indicating no errors.
return cb(null,user);
})
.catch(err) {
return cb(err);
});
}
}
Second, you're sending the adGet.userData function to your view as a local variable, but you're not actually calling it to get the data. And since it's an asynchronous function, you won't be able to call it from your view. You need to call it from within the controller and send the result to the view:
var adGet = require('../services/adGet');
module.exports = {
test: function (req, res) {
// Call service function, passing callback function in as argument
adGet.userData(req, res, function(err, user) {
// Handle errors
if (err) {return res.serverError(err);}
// If all goes well, send user data to view
return res.view({
user: user
});
});
}
}
Less importantly, you could refactor the userData method to not accept req and res as arguments--it's overkill. Save req and res for your controllers whenever possible. It would be better to have userData just expect userId and callback as arguments. Also, unless you've turned global services off using the config/globals.js file, you don't need to require the services file at the top of your controller; the adGet variable will be made available to you automatically.

Access another module.exports function from the same file node.js

To make it a bit more clear to what I'm trying to achieve.
I have a server running which includes many module, and one of the module use to check if the user role is an admin or not.
in Server.js
var loginAPI = require('myModule')(argStringType),
express = require('express');
var app = express();
Now that in the myModule.js I have few functions that already been implemented and just wanted to add one more, but this function really doesn't need to be call from the server.js instead it will be call once the person visit the URL, so I want to add something like this to the myModule.js
in myModule.js
app.get( "/post/:postid", function( req, res ) {
var id = req.param('postid');
return getContent( postid );
});
// Module.exports
module.exports = function ( arg ) {
return {
getContent: function ( id ) { },
getHeader: function ( id ) { };
};
So as you can see from the above, I have two function which is in the module.exports and they worked fine no problem except the one which is outside the module.exports that one work if I don't try to call the getContent, but that is what I'm trying to achieve. When someone visit the site by entering the URL in that format the app.get should be fire and do whatever is implemented to do.
Make sure you realize each module in Node.js has its own scope. So
ModuleA:
var test = "Test output string";
require('ModuleB');
ModuleB:
console.log(test);
Will simply output undefined.
With that said, I think this is the style of module you're looking for:
server.js:
var app = //instantiate express in whatever way you'd like
var loginApi = require('loginModule.js')(app);
loginModule.js:
module.exports = function (app) {
//setup get handler
app.get( "/post/:postid", function( req, res ) {
var id = req.param('postid');
return getContent( postid );
});
//other methods which are indended to be called more than once
//any of these functions can be called from the get handler
function getContent ( id ) { ... }
function getHeader ( id ) { ... }
//return a closure which exposes certain methods publicly
//to allow them to be called from the loginApi variable
return { getContent: getContent, getHeader: getHeader };
};
Obviously, adjust to fit your actual needs. There are lots of ways to do the same type of thing, but this fits closest with your original example. Hopefully that helps.

Resources