I'm fairly new to JS especially Node and Express. I am following some tutorials on how to build an API and at the same time learning about JS special features such as let/const/var, arrow functions etc.
In many tutorials I have seen things likes this :
somecode.then((result) => {someothercode})
With: "somecode" being for example a get request
Is "result" the name of the returned value or is it a convention that JS developper use?
By that I mean, does this for example work?
somecode.then((foo) => {someothercode})
Also for req, res variables what does this mean?
app.get("/users/:userId", [
usersController.getById
]);
Here is the getById function (using once again the "result"):
exports.getById = (req, res) => {
userModel.findById(req.params.userId).then((result) => {
res.status(200).send(result);
});
};
the getById method defined in the controller needs (req, res), does that mean, when i call it like the code above, the req and res arguments are implicitly used?
Also it needs a parameter :
req.params.userId
which is in the url of the route, how does it pass to another file?
I have a route.js file that uses a controller.js file that uses a model.js. How does the param go from route to controller?
And it won't work if I change the param name right? for example:
req.params.id
Sorry for long post, I'm trying to understand JS logic to get some good habits and write clean code.
Thanks!
Is "result" the name of the returned value or is it a convention that JS developper use? By that I mean, does this for example work?
From my experience, yes - result is often used. Often times you'll see thing like value, response, but ultimately it can be whatever you define. I would recommend sticking to convention, and also check out the MDN Promise tutorial if you are starting out with understanding NodeJS asynchronous operations.
Also for req, res variables what does this mean?
app.get("/users/:userId", [
usersController.getById
]);
That is a middleware chain. Check out the Express docs for more information.
the getById method defined in the controller needs (req, res), does that mean, when i call it like the code above, the req and res arguments are implicitly used? Also it needs a parameter :
req.params.userId
which is in the url It won't work if I change the param name right? for example:
req.params.id
Yes, that is using a named parameter. Without the full router code, it is hard to know how the getById method is linked to the defined route. The Express routing documentation will likely be a good start on that.
Is "result" the name of the returned value or is it a convention that JS developper use?
result is the name of a new variable you are creating to represent the value passed in from the Promise resolution. Yes, your foo example will work.
(req, res) => {} is the same (mostly) as a function that looks like this:
function getById(req, res) {...}
req, and res are just representational of the values that will be passed to this function. They could just as easily have been called (foo, bar).
It looks like you're struggling with understanding callback functions. Consider the following code then please crack open the source code for the packages that you are using. and it looks like you are using express.js
function something(callback) {
var x = 5;
var y = 'anything';
callback(x, y);
}
something(function(req, res) {
console.log(req);
console.log(res);
});
the something function is created and inside of that function scope, var x and y are created with any type. then when we invoke or use something function we are passing a function as a variable that gets passed in as variable callback then it can be used since it is a function so we call callback with x and y which can literally be any value and for effect, I am passing back a number and a string as req and res.
It's just a convention. Note that the code:
somecode.then((result) => {someothercode});
Is actually:
somecode.then(myFunction);
Since somecode is a Promise, your function may be called with zero or one argument. It is up to you to name this argument:
function myFunction (foo) {
// use foo here
}
somecode.then(myFunction);
Of course, unlike some other languages, javascript does not force you to name your function. You can just use a nameless (anonymous) function:
somecode.then(function(mango) { /* use mango here */ })
Arrow functions is a new syntax allowing you to write anonymous functions in a shorter style (it also behaves slightly differently with regards to scope and the value of this)
Express.js and http.Server
In node's http.Server library and Express.js framework, each server request will call a function you define and pass it two arguments: the request object and the response object. The variables req and res are just conventions people use when writing their own request handler functions. You can name them anything you like. For example you may prefer to use request and response instead or rx and tx:
app.get('/say/hello', (rx, tx) => tx.send('Hello'));
How many arguments do I write a callback function with??
The best way to know is to read the documentation of the module you are using. It is not the only way to know - you can of course read the source code instead. But it is often easier to read the documentation. Because of this, javascript modules tend to have really good documentation (otherwise they would be unusable and ignored by the community).
Express.js will actually pass three arguments to your callback (not two!!) - request, response and next where next is a function you can call if you want Express to continue processing instead of replying to the request. One interesting feature of javascript is that you are allowed to call functions with fewer or more arguments and it is not considered a syntax error:
function example (x) {}
example(); // not an error
example(1); // not an error
example(1,2,3,4); // also not an error
Express uses this feature by always calling your callback with three arguments while allowing you to declare said callback with only two arguments if you don't need the third, next argument.
Related
In NodeJS, using Javascript I have a "res" object that can be either an Express or Fastify response, is there any way to check which of the two is this response?
There are 3 ways to solve this problem: the bad way, the less-awful way, and the way that results in actual clean code.
1. The bad way: duck typing
The most intiutive way is using a technique called "duck typing" to tell what kind of object you're dealing with. Look at res, check what properties it has, and infer the type based on that. In particular, you'll be interested in the differences between the objects to be able to tell them apart, so search for special features that the other framework doesn't have.
Example checks:
function isExpress(res) {
return (typeof res === 'object' && typeof res.sendFile === 'function');
}
function isFastify(res) {
return (typeof res === 'object' && typeof res.hasHeader === 'function');
}
However, there's a problem: what if you get a res that is extended by a middleware for express.js or for fastify, which adds the property? Then, depending on the ordering of your if-elses, you may confuse one for the other.
2. The less-awful way: decorating the object yourself
It would be better if we could tell the objects apart regardless of what middlewares are applied - so that a feature being added doesn't break our type recognition logic.
Instead, we can purposefully extend the res object using a special, additional property, so that it's obvious from looking at that property whether we're dealing with express or fastify. To do this, we need to make sure that:
express will decorate res with a property that says "I'm express"
fastify will decorate res with a property that says "I'm fastify"
Quite literally:
const FRAMEWORK_TYPE = Symbol('type of framework that res comes from');
expressApp.use(function(req, res, next) {
res[FRAMEWORK_TYPE] = 'express';
next();
});
fastifyApp.decorateReply(FRAMEWORK_TYPE, 'fastify');
Then, you can refer to res[FRAMEWORK_TYPE] and check the hint that you've left for yourself directly.
3. The clean way: design patterns
The way you've formulated the original problem is: how to check what type of instance we're dealing with. However, the purpose of this check is most likely to be able to integrate different frameworks (express and fastify) with a single piece of code that does something else (a handler).
This problem is usually solved with the Adapter design pattern - have a layer that speaks a common API and hides the complexity of having different possible implementations. For instance, say your handler needs the request body and headers, and you need to be able to respond via JSON regardless of framework. Then, you could define the handler signature to be:
({ body, headers }) => responseObject
Next, call that handler from both frameworks. You'll notice that you need to refer to different parts of req and res in case of express and fastify in order to call the handler properly. Also, in case of fastify, you'll be able to just Promise.resolve(responseObject), but for express, you may need to do res.json(responseObject) instead.
This way, you decouple your business logic (handler) from the infrastructure layer (web server).
I want to use method getPlayers(callback) which is defined as:
getPlayers(callback)
callback - Required. Called with an object of players
players - An object containing all the players connected to the server, with their name as the key
Retrieve all players connected to the server.
Here is the link to complete module for further details :
https://www.npmjs.com/package/hltv-livescore#getplayerscallback
If you want to use it and access the data, you'll need to do something like this:
getPlayers(function(players) {
// Here your players will be available
console.log(players)
})
Bonus: If you're using ES6, you can use Arrow functions, that are more elegant, like this (single line):
getPlayers(players => console.log(players))
or (multi line):
getPlayers(players => {
console.log(players)
})
You can read more about the async nature of Javascript here
If you refer source code of npm package you can see this code
https://github.com/andrewda/hltv-livescore/blob/master/lib/index.js#L78
Livescore.prototype.getPlayers = function(callback) {
callback(self.players);
};
You can use getPlayers like this :
Livescore.getPlayers(function(players){
// you will get players here
});
I posted this question yesterday but I guess I just confused everyone. I got responses like "what exactly is your question?" So I am expanding and reposting today.
The following node.js snippet is from the file "accounts.js" which is in an ETrade api library that exists in the path /lib. It should return json containing data about the accounts of the authenticated user. The authentication part is working great. I'm confused about what exactly is being done in the last line of this function:
this._run(actionDescriptor,{},successCallback,errorCallback);
Ten years ago (the last time I was coding), we didn't have the construct "this" and I haven't a clue about "_run" and Google searches have not been helpful. Here is the function.
exports.listAccounts = function(successCallback, errorCallback) {
var actionDescriptor = {
method: "GET",
module: "accounts",
action: "accountlist",
useJSON: true,
};
this._run(actionDescriptor, {}, successCallback, errorCallback);
};
I understand that the function is accessed with "et.listAccounts ...." but then my understanding goes all to hell. It's pretty obvious that a get is being executed and json data returned. It's also obvious that the result is passed back through the successCallback.
In my app.js file, I have the following:
var etrade = require('./lib/etrade');
var et = new etrade(configuration);
Can someone please suggest a snippet to be used in app.js that will output the accounts data to the console?
It seems like the json data must be passed back through the successCallback but I'm lost on how to access it on the app.js side.
Suppose in app.js I want to put the accounts data in a variable called myAccounts. The exports.listAccounts function does not specify a return value, so I doubt I can do var myAccounts = et.listAccounts(). Likewise, myAccounts will be undefined if I try to do this: et.listAccounts(){myAccounts, error}. Finally, the listAccounts function contains two possible variable names I could use, "accounts" and "accountlist" but these turn out to be undefined at app.js.
When I put a function in successCallback in app.js to write a generic message to the console, the message appears in the log so I know I am making it into the listAccounts function and back successfully. In this case, the log also shows
"Request: [GET]: https://etwssandbox.etrade.com/accounts/sandbox/rest/accountlist.json"
From this I deduce that the data is actually being returned and is available at that end point.
Ten years ago (the last time I was coding), we didn't have the construct "this" and I haven't a clue about "_run"
this refers to the current object, further reading here. _run is just what they chose to call the function.
I have no experience with this module, but with a cursory glance at the git repo I suspect you will want to expand your app.js like so:
et.listAccounts(function(response) {
console.log(response);
});
In javascript functions are first order and so can be passed around like variables see here. listAccounts wants a function passed to it, and when it is complete it will call it with one parameters, as can be seen in etrade.js.
There is also the function errorCallback which is much the same but is called on an error. You could expand the above snippet like so:
et.listAccounts(function(response) {
console.log(response);
}, function(error) {
console.log(error);
});
I just brought up this issue with Express and I am interested in what StackOverflow thinks about it:
https://github.com/strongloop/express/issues/2831
my question is why Express opts to disallow the developer from passing data directly between middleware functions and basically forces you to assign temporary data to the request object in what I have always considered to be a quite awkward assignment.
to be more specific:
passing data between middleware functions usually involves doing this
req.specialData = {}
next();
however, it would be perhaps much easier and more performant (!) if this were possible
next(null,data);
or
function mySpecialMiddleWare(req,res,next,data){}
//now, call the above function
mySpecialMiddleWare(req,res,next, {some:data});
the problem is that Express uses a, what I believe to be, stupid way of determining if the call is to a normal middleware function or the next error first middleware function, by checking to see if the function.length > 3 or function.length === 4...
is there any chance what I am saying makes any sense?
wouldn't it be better/easier/faster/stronger to allow direct passing of data via middleware functions instead of assigning data awkwardly to req ??
perhaps Express already has this capability and I am just misinformed?
my question is why Express opts to disallow the developer from passing data directly between middleware functions and basically forces you to assign temporary data to the request object in what I have always considered to be a quite awkward assignment.
So I think the API is the way it is to encourage most middleware to be modular, re-usable, and loosely coupled. That means the generally should do something without being concerned too much about what other middleware might run before them or after them. In order to achieve this and create an ecosystem of loosely-compatible middleware functions, express keeps the API fairly generic. There are pros and cons to this. But as a direct answer to your first question, I would say to keep the interface simple, consistent, and flexible as well as try to avoid strict ordering dependencies.
As in your case, there might be implicit dependencies between middlewares. Another common example would be typically your session middleware has an implicit dependency that your cookie middleware runs before it. Having these all be implicit can be argued to create bugs and unnecessary troubleshooting. On the other hand, it enables application developers to more easily mix and match middlewares that might otherwise have no awareness of one another.
In hindsight I think both I as well as some of the express maintainers would agree that using function arity (number of expected arguments) for semantic API reasons was an odd and poor choice on TJ's part. I think if the project were to be rewritten a more explicit API would be defined for error handling.
wouldn't it be better/easier/faster/stronger to allow direct passing of data via middleware functions instead of assigning data awkwardly to req ??
Better - this is highly arguable and opinion based. There is a lot to be said for the simplicity of it and the evidence is the huge ecosystem and usage. There are alternatives available such as hapi, restify, etc, though so you might consider them.
Easier - probably not. What's there is pretty easy.
Faster - probably not in any meaningful way. Not sure why you think your version would be faster, but best to bring metrics when you make such claims.
Stronger - If by "stronger" you mean more explicit that's probably true but there's a reason some people still prefer JavaScript even though TypeScript all the way up through Haskell exist and are definitely "stronger" in some sense of the word.
There might be advantages to what Express is doing, however, it is worth noting that Express allows passing data between middlewares using res.locals. With that said, your question inspired me to make this library. Expressjs-plus.
With it, you will be able to pass data between your middlewares easily without having to use the request nor the response object.
You can use regular javascript functions e.g. function(varInResLocals, varInReqParams, callback) instead of express middleware signature.
Here is a working example for you.
var express = require('express');
var ExpressPlus = require('expressjs-plus').ExpressPlus;
var app = express();
// simple handler example
var userHandler = function(param, paramsArray, req, res){
if(param !== 'user') return false;
paramsArray.push("USER WAS FOUND!");
return true;
};
// this handler allows you to pass res.locals properties between your middlewares seemingly,
// it the parameter was found in locals, it attaches it to paramsArray.
var resLocalsHandler = function(param, paramsArray, req, res){
if(param in res.locals){
paramsArray.push(res.locals[param]);
return true;
}else return false;
};
var appPlus = new ExpressPlus(app, [userHandler, resLocalsHandler], []);
var regularFunction = function(user, id, cb){
return cb(null, { response: {user: user, id: id}, status: 200, resLocalsVar: "passVar" });
};
// resLocalsVar was passed in a previous method
var regularFunction2 = function(resLocalsVar, user, id, cb){
// now you can have access to it
console.log(resLocalsVar);
return cb(null);
};
// the responder at the end will use res.locals.status and res.locals.response to issue an HTTP response
app.use(appPlus.GMV(regularFunction), appPlus.GMV(regularFunction2), appPlus.responder);
// adds error handlers, it will add a default error handler along with the list of error handlers passed
// in this case, no error handlers were passed
appPlus.setErrorHandlers();
app.listen(3001, function(){
console.log('Listening!');
});
I am currently starting with node.js, so I am for the first time using Js beyond dom manipulation.
I came across a code piece like below. I cant understand it. What is happening? is it a key value object? Is an anonymous function being passed to 'new'?
module.exports = {
'new': function(req, res) {
res.view();
},
/**
* Overrides for the settings in `config/controllers.js`
* (specific to UserController)
*/
_config: {}
};
As others have said, this is ultimately just creating an object called module.exports then assigning two properties to it. One is another object called _config and the other is a function called new that expects two arguments.
That's the plain JavaScript explanation.
In node.js, you're also seeing a few conventions in play, which I'll describe below.
One convention is module.exports.
This is the object that will be made available when some other code loads this file using require(). It would work something like this:
var m = require('yourmodule.js');
m.new(req, res);
Another convention is the pair of arguments: req, res.
These are usually parameters that represent a request (like an http.IncomingMessage) and a response (like a http.ServerResponse).
Putting it all together, this module is probably defining a Controller that will receive http requests, and render them as responses. It currently does this for new, and there are probably routes configured elsewhere that call this method when a user requests something like 'http://server.come/user/new'.
Looks like basic JavaScript.
An object named module has a property named exports that is an object.
This object has a property named new whose value is an anonymous function.
In theory you could invoke the method like this:
module.exports.new(someRequest, someResponse);