I'm working on a project which has a quite simple endpoint:
app.get('/transactions',
listTransactions(connectionPool),
addUser(connectionPool),
sendTransactions);
We get a list of MySQL rows, merge user-data into the response, and send it back to user. My question is, is there a "commonly accepted" place to store the response of listTransactions (in this case)? Do I store it on the req object?
Here's my take. I think you're abusing middleware in this case. The middleware is better at decoding, authenticating, etc. I think your example has reached the point where it would make a lot of sense to wrap these things in a function like so.
app.get('/transactions', function(req, res, next){
var transactionPromise = listTransactions(connectionPool)
.then(function(transactions){
return listTransactions(transactions, connectionPool);
})
.then(function(listedTransactions){
return addUser(connectionPool);
})
.then(function(addUserResponse){
res.send(addUserResponse);
});
transactionPromise.catch(function(error){
res.status(500).send("Something went wrong: " + error.toString());
}
}
I use promises here, but this could easily be done with something like async as well. This approach does a few things:
Allows you to handle errors at the router level, rather than inside each function. If you think about it, should a function called listTransactions really know how to respond to a server request?
In combination with the first point, it allows for better reusability by removing the dependency on the (req, res, next) signature.
Testability. Now you can test all the individual pieces without a reliance on the previous middleware, or a specific req format.
My 2ยข. Hope it helps!
Related
I am learning node.js and express.js in pursuit of becoming a full-stack javascript developer. Currently, I am learning express.js and the idea of middleware.
As I understand it, middleware is basically functions that have access to modify the request and response within the req-res cycle. Is this correct?
However, I am a bit gray in the idea of the next() function. I understand that it is designed to call the next middleware function in the flow of middleware functions, however, where does it come from. Where can I find it in the express.js package.
When you have, more middlewares, they will run in order, and each middleware will pass the result to next middleware. imagine you have a route that can be accessed only by authenticated users.
router.get("/products", adminController.getProducts);
this says, whenever a user makes a request to /products, run the controller for this route. However, if you want to show this route, only to authenticated users, you will write a custom middleware, check that a user is autenticated, is user authenticated you will let the adminController.getProducts otherwise you will show an error message. So you will be placing the middleware between.
router.get("/products", isAuth, adminController.getProducts);
Note that you could pass more than one middleware. (adminController.getProducts is also a middleware but I mean besides isAuth you could place as many as you want)
isAuth will be something like this:
export const isAuth = (req, res, next) => {
if (!req.session.isLoggedIn) {
return res.redirect("/login");
}
next();
};
Imagine you setup a session based project. When user logs in, express-session (you will get familiar) will add session.isLoggedIn=true to the req obj. So before user attemps to react "/products", you will be checking if req.session.isLoggedIn is true. If yes you will let the next middleware to run, if not you will be redirecting the user to "/login" route.
I've been asked to help write some server-side scripts that update calendars, contacts, e-mail and other company services from other internal services for compliance reasons. The code needs to access the LDAP server, an SQL database and e-mail server, compile and merge information in a peculiar way and then go through information in the calendars, contacts and update those depending on what's there and in the LDAP/SQL databases. This needs to be done a couple of times a day, so performance isn't particularly important.
I wanted to try to use node.js for this and after spending a few days with it, I'm having second thoughts as to whether node.js is the right tool to do this. I'm an old school programmer, have C, C++, Unix, SQL, LDAP, TCP/IP in my small finger but I've learned JavaScript/Node.js in a few days out of curiosity.
I use LDAP, SQL and CalDav/CardDAV modules from npm. These are based on Promises.
Thanks to promises, the code is super ugly, unreadable and buggy if there's any kind of network problem. Things that are very easy in classic language such as C or Java are suddenly a massive headache, such as the fact that (say) LDAP information will arrive at a later stage, but there's no point in async operations as nothing can be done in parallel while waiting for those. This pattern repeats itself throughout the code - async operations complicating matters incredibly for zero benefit. It's incredibly difficult to calculate any sort of aggregate values and apply them elsewhere when using these async functions.
My question is this: is there a simple way to invoke async functions that will simply return the value instead of invoking callbacks?
in javascript - no. Waiting async call to complete would block the only thread and so would stop all the work, and so such waiting is not implemented.
But there exists async/await mechanism - syntactic sugar over asynchronous calls, which mimics synchronous calls.
First of all, the vast majority of I/O calls in Node.js are asynchronous. So if you're totally uncomfortable with this, it may not be the right fit for what you're doing.
It is a (IMHO) brilliant language, and you'll find it more comfortable to use as you get used to it.
However, you can write code using Promises that looks very much like synchronous code using the async/await syntax. I find this much easier to deal with compared to using lot's of .thens and .catch.
You can also use try and catch in this context and it will work as you would expect.
This makes for much cleaner, more readable code.
Most Node.js modules support Promises, for those that don't you can often convert functions to returning a Promise rather than expecting a callback to be passed.
NB: Don't forget to await calls to async. functions. I find this is one of the most common errors one makes when using this syntax.
For example:
function callApi() {
return new Promise(resolve => setTimeout(() => resolve({ status: 'ok'}), 500))
}
async function testApi() {
try {
console.log("callApi: Calling function...");
let result = await callApi();
console.log("callApi result:", result);
} catch (err) {
console.error("callApi: Error:", err.message);
}
}
testApi();
Then a further example to show catching an error (say the api fails for some reason):
function callApi() {
return new Promise((resolve, reject) => setTimeout(() => reject(new Error("Api error")), 500))
}
async function testApi() {
try {
console.log("callApi: Calling function...");
let result = await callApi();
console.log("callApi result:", result);
} catch (err) {
console.error("callApi: Error:", err.message);
}
}
testApi();
Individually, I have verified that the two functions in fact work properly. However, they do not execute when the /dashboard route is loaded. Only res.render works and does its task.
I have tried using promises and such but I just keep getting errors and I do not understand them. Do they need to be in the functions themselves or the code I provided?
// Display the Dashboard Page and Verify User Profile
router.get("/", (req, res) => {
verifyUser.checkUserExists;
verifyUser.loadProfileInfo;
res.render("dashboard");
});
Only res.render("dashboard"); happens and the other two functions dont send anything to my console
You need to call your functions.
verifyUser.checkUserExists();
verifyUser.loadProfileInfo();
I am trying to write a middleware that creates a new method on app created with express(). For example, I would like to achieve the following:
app.use(myMiddleware())
// ...
app.newMethod() // added through the previous middleware
Is there a way to achieve this? A way I have thought of, as referenced in some other questions, is to pass in app itself as a param to my middleware so that I could tweak it:
app.use(myMiddleware(app))
// ...
app.newMethod() // ok, definitely doable
However, this does not seem elegant enough.
Also, req.app and res.app references won't work for me in this case, since the (req, res, next) => {} function returned by myMiddleware() only executes when receiving requests, while I possibly want to access the method before even app.listen() is called.
Is there a way I can achieve this?
It really doesn't make sense to add an app method in middleware. The purpose of middleware is to process an incoming request, either in preparation for later middleware or later request handlers or to just handle the request itself in the middleware.
Middleware gets called over and over during incoming requests. It should never be used for something that should just happen once and it should only be used for processing related to an incoming request.
while I possibly want to access the method before even app.listen() is called
So, that definitely has nothing to do with an incoming request then so using middleware is just not the right design choice.
If all you're trying to do is to add your own method to the app object, you can do that when you are initializing your server:
const app = require('express')();
// add my own method to the app object
app.myMethod = function(myArg1, myArg2) {
// put the implementation here
}
app.use(...);
app.get(...);
app.get(...);
app.listen(...);
Then, anywhere you want, you can call app.myMethod(...).
Does there exist a thirdparty middleware or a way to create such middleware for Express.js that allows for intercepting all requests and inspecting the request's body content without affecting subsequent middleware such as bodyParser or route endpoints which may rely on the raw body such as express-http-proxy?
From what I can tell bodyParser itself seems to work in a somewhat obtrusive way that does not allow a route to override the default parsing behavior. The express documentation describes how request.body is filled in by middleware such as bodyParser. This behavior of bodyParser makes sense from simplicity and performance perspective but doesn't make it a great candidate for creating middleware which needs to inspect the contents of a request and let the remaining portion of the app working without modification. This is especially true seeing that depending on the parsing middleware the results may be in entirely different formats. After some digging I'm left wondering if it's generally possible to pull this off with express or perhaps once you read the request body you eliminate the ability to make use of further middleware such as bodyParser or express-http-proxy which expect to access the body directly.
Possibly related:
express req.pipe() does not work
You could always use the raw-body package with express middleware like so:
var getRawBody = require('raw-body');
var typer = require('media-typer');
app.use(function (req, res, next) {
getRawBody(req, {
length: req.headers['content-length'],
limit: '1mb',
encoding: typer.parse(req.headers['content-type']).parameters.charset
}, function (err, string) {
if (err) return next(err)
req.text = string
next()
})
})
If your only concern is performance, I wouldn't worry too much about body-parser as it's unlikely to have a massive performance impact. If you can, I'd suggest you just use body-parser with a typical express middleware app.use(..) to inspect the request body.