express-resource custom mapping - node.js

I can't find any decent documentation on this that contains any depth when requiring with app.resource.
The only information that I can find is creating the variable within the current file. Here
The current code that I have is below:
var favs = app.resource('favs', require('./modules/favs'));
favs.map('get', '/user', favs.buses);
However it comes back saying that it is undefined?
In the module favs I have.
exports.buses = function (req, res) {
res.render('favs/buses', {
title: 'Bus Stops'
});
});

You have a syntax error in favs.js: The last right bracket ) is redundant.
Apart from that, you seem to conflate the actual module with the resource object you get back from app.resource. You want to pass a reference to the request handler you want to invoke when a visitor hits the path (in your case, /favs/user). So what you want is something like:
var favs = require('./modules/favs'),
favsResource = app.resource('favs', favs);
favsResource.map('get', '/user', favs.buses);
If you feel a little lost dealing with express-resource, I encourage you to begin with plain express, and only start using express-resource when you are more familiar with how express works. TJ's helper modules have a tendency to be lacking in documentation, and you should use them only if you feel comfortable reading the code, IMO.

Related

Expressjs higher order router vs appending to request

Let's say I want to pass to an ExpressJS route callback an object.
I know I can append to app:
// router.js
const getFoo = (req, res) => res.json(req.app.foo);
// index.js
const app = express();
app.foo = {};
app.get('/foo', getFoo);
or I can use a higher order function:
// router.js
const getFoo = foo => (req, res) => res.json(foo);
// index.js
const app = express();
const foo = {};
app.get('/foo', getFoo(foo));
Both are easy to write, extend and test.
But, I don't know the implications of the solutions and whether one is better.
Is there anyone knowing real differences between the two approaches?
I think the second solution is more correct, here's why.
imagine you get used to the first solution and one day you need to send something called post or get or anything with the name of app property and you forget that there is already a property named like that, so you override original property without even realizing and when you call app.post() program will crash.
Believe me, you don't want hours of research wasted on something like that and realizing that you simply overrode original method
Also, in my opinion, it's always a bad idea mutating original object which wasn't generated by you
As #vahe-yavrumian mentioned it is not a good idea to mutate the state of the object created by a third party library.
between you can also use app.get() and app.set() methods to pass any data to the other routers in the queue (seems those methods are there just for this purpose.)
more information at https://expressjs.com/en/api.html.
The second solution easily allows you to pass different value for foo on different routes, if you ever found a need to do that.
The first solution essentially puts the value on the app singleton, which has all the implications of using singletons. (And as mentioned by #Anees, for express specifically the app settings with get and set are the proper place to store this, not a custom property)

I tried nestjs but I realized it reduces code readability because of so many decorators, please take a second to visit this

I recently used nestjs, But I realized its overcomplicated, I mean look the following code:
#post('/products')
getAllProducts(#Body('title') title, #Body('price') price, #Body('description') description) { }
It makes function parameters much dirty, Also there could be more decorators above function like #Header, #Params, etc.. Which reduces readability in my opinion.
Same code in nodejs
const { title: title, price: price, description: description } = req.body
nodejs is much more readable...
Then I researched why developers use nestjs, Reason was Modularity. Why we don't implement this on our own...
See below:
See my directory sutructure
In app.js I just kicked the app:
const express = require('express');
const app = express();
// express config
require('./startup/config')(app);
// handling routes
require('./startup/routes')(app);
// db setup
require('./startup/db')(app);
In startup folder I did the basic work like mongoose configuration and connection to db etc..
However, In startup/routes, I just kicked the module as follow:
const shopModule = require('../shop/shop.module');
module.exports = app => {
app.use('/', shopModule);
};
In shop module, I just kicked the routes as follow:
const router = require('express').Router();
const productsRouter = require('./products/index');
const cartRouter = require('./cart/index');
// Products
router.use('/products', productsRouter)
// Cart
router.use('/cart', cartRouter)
module.exports = router;
Now in cart/index.js, I handled the routes related to cart and same for products as follow (I will just show cart):
const router = require('express').Router();
const { getCart } = require('./cart.controller');
router.get('/', getCart);
module.exports = router;
In controller, basically we will do validation stuff etc or extracting data.. Then controller will kick service for database work..
const { userCart } = require('./cart.service');
exports.getCart = (req, res, next) => {
const cart = userCart();
return res.status(200).json(cart);
};
And finally in cart service:
exports.userCart = _ => {
// ... go to database and fetch cart
return [{ prodId: 123, quantity: 2 }];
};
And cart.model.js is responsible for DB schema,
I know the question was too long, but I wanted to explain my question.
I am not saying nestjs should not be used, I am just saying, what about the following structure as it follows the same pattern as angular or nestjs, Right?
With your first point about making the code more readable, why not do something like
#Post('/products')
getAllProducts(#Body() body: any) {}
instead of calling for each part of the body individually, then you can deconstruct the body as you showed with
const {title: title, price: price, description: description} = body;
No need to specify each part of the body that you need as a new parameter, just grab the object itself. The same also goes for #Header(), #Param(), and #Query().
As for how you are setting up your express app, you are completely correct that you can do that; however, if you are working on an open source project, or collaborating with other developers there is nothing that says they have to follow the same format and it could eventually lead to a messy code base. Nest enforces these patterns, similar to how Angular does. Sure, it is still possible to write terrible code, but with an opinionated architecture it does make it more difficult.
NestJS also treats Typescript as a first class citizen, which in my opinion helps get rid of a lot of development problems as well. Plus you get some really cool packages to play with like class-validator and class-transformer to help with validation and transformation of your requests via pipes. You can write an Express server in Typescript, but it isn't necessary, and you can write a NestJS server in JavaScript, but I think you lose a lot of good functionality if you do.
The last point that I don't think has been touched too much it that Nest handles a lot of black boxing for your code through it's modules. If you define a service for a module, it is only available for that module. If you need it in another module you have options, but it helps cut down on the cross-contamination of code and keeps a separations of concerns ideology in mind.
In my opinion, the fact the NestJS gives us specified files for things like authentication (guards), validation and transformation (pipes and interceptors), and error handling (exception filters) makes it easier for anyone to pick up a NestJS server and have a quick understanding of how the request will flow through the server, even if by just looking at the file structure. Personally I know if I see an AuthModule or a guards folder I'm going to be dealing with authentication to some extent.
To answer your final question: there is nothing wrong with how you are showing the express example, especially as you are using Inversion of Control by passing the app into the router to make it work that way, you can absolutely write an Express server that way. Nest just makes you do it that way. (I mean, you could write an entire server using just AppController, AppService and AppModule, but that's really an anti-pattern)
In the end, definitely use what you're comfortable with, but there is a reason Nest has become so popular recently.
it's dirty because you write it in the wrong way
why not use it like this
#Get('/')
getAllProducts(#Body() product: Product) {}
and then destructure it
const {title, price, description} = product

How do you save the results of a mongoose query to a variable, so that its value can be used *later* in the code?

I know this question has been asked a few times, but none seem to answer the particular part of using the query results for later.
I also know the problem resides on the fact that queries are asynchronous, and perhaps this is the reason I cannot seem to find a satisfactory answer.
Here's what I'm trying to do:
I have a node project with several sections, each section with different content. These sections have individual properties, which I decided to store in a Model for later use.
So far (and for simplicity sake) I have the following schema:
const SectionSchema = new Schema({
name: String,
description: String
})
const Section = mongoose.model('Sections',SectionSchema)
I'd like to retrieve this data to be used in one of my layouts (a navigation header), so I tried something like this:
const express = require('express')
const app = express()
Section.find().then(function(docs){
app.locals.sections = docs
})
console.log(app.locals.sections) // undefined
This obviously doesn't quite work due to find() being asynchronous, or rather, it does work but the values are populated at a different time. I know that if I do the console.log check inside the function I'd get a result, but that's not the concern, I want to store the data in app.locals so that I could later use it in one of my layouts.
Ideally I'd like to load this data once, before the server begins to listen to requests.
Feel free to correct me if I've made any wrong assumptions, I'm very new to node, so I don't quite know how to approach things quite yet.
Thanks in advance.
EDIT: I should've mentioned I'm using express.
Your node app will likely be comprised of route handlers for http requests. app.locals.section will be undefined if you call it outside of the callback, but it will exist in the route handler.
Let's say you were using something like express or restify:
const app = restify.createServer()
app.get('/', (req, res) => {
return res.json(app.locals.sections)
})
Section.find().then(function(docs){
app.locals.sections = docs
})
console.log(app.locals.section) // is undefined
app.listen(8080-, ()=>{
console.log('Server started 🌎 ',8080)
})
Actually, it might be undefined if the database call took a long time and or a user hit the app super soon after startup. Starting the server in the callback would ensure app.locals.section existed under every scenario:
Section.find().then(function(docs){
app.locals.sections = docs
app.listen(8080-, ()=>{
console.log('Server started 🌎 ',8080)
})
})
You can use async/await within a function to make it seem like you aren't using promises. But you can't use it at the top level of your module. See here: How can I use async/await at the top level?
It really would be fairly idiomatic to do all your app startup in a promise chain. It's a style of coding you are going to see a lot of.
Section.find().then((docs)=>{app.locals.sections = docs})
.then (()=>{/*dosomething with app.locals.sections */})
.then(startServer)
function startServer() {app.listen(8080-, ()=>{
console.log('Server started 🌎 ',8080)
})}

Where should I put custom errors in sails.js?

I was wondering what's the best practice and if I should create:
a directory in which declare statically all the errors my application uses, like api/errors/custom1Error
declare them directly inside the files
or put the files directly inside the dir that needs that error, like api/controller/error/formInvalidError
other options!?
A neat way of going about this would be to simply add the errors as custom responses under api/responses. This way even the invocation becomes pretty neat. Although the doc says you should add them directly in the responses directory, I'm sure there must be a way to nest them under, say, responses/errors. I'll try that out and post an update in a bit.
Alright, off a quick search, I couldn't find any way to nest the responses, but you can use a small workaround that's not quite as neat:
Create the responses/errors directory with all the custom error response handlers. Create a custom response and name it something like custom.js. Then specify the response name while calling res.custom().
I'm adding a short snippet just for illustration:
api/responses/custom.js:
var customErrors = {
customError1: require('./errors/customError1'),
customError2: require('./errors/customError2')
};
module.exports = function custom (errorName, data) {
var req = this.req;
var res = this.res;
if (customErrors[errorName]) return customErrors[errorName](req, res, data);
else return res.negotiate();
}
From the controller:
res.custom('authError', data);
If you don't need logical processing for different errors, you can do away with the whole errors/ directory and directly invoke the respective views from custom.js:
module.exports = function custom (viewName, data) {
var req = this.req;
var res = this.res;
return res.view('errors/' + viewName, data);//assuming you have error views in views/errors
}
(You should first check if the view exists. Find out how on the linked page.)
Although I'm using something like this for certain purposes (dividing routes and so on), there definitely should be a way to include response handlers defined in different directories. (Perhaps by reconfiguring some grunt task?) I'll try to find that out and update if I find any success.
Good luck!
Update
Okay, so I found that the responses hook adds all files to res without checking if they are directories. So adding a directory under responses results in a TypeError from lodash. I may be reading this wrong but I guess it's reasonable to conclude that currently it's not possible to add a directory there, so I guess you'll have to stick to one of the above solutions.

Overloading functions for an api in node - Best practice?

I'm currently building a small express powered node app to power a RESTful API exposing data from a node module I wrote. One of the functions in the module takes three arguments, but I want to allow the usage of the API by specifying just one, two, the other two or all three arguments.
So even starting to write the routes like this already feels ridiculous.
app.get('/api/monitor/:stop/:numresults', apiController.monitorNum);
app.get('/api/monitor/:stop/:timeoffset', apiController.monitorOff);
app.get('/api/monitor/:stop', apiController.monitor);
Especially since I don't know how to specify the difference between the first two, as numresults and timeoffset are both just integers.
What would a best practice in this situation look like?
The first problem you face is that you have identical routes, which are not possible if you're using express (I'm assuming that's what you're using). Instead you probably want one route and utilise the query object instead:
app.get('/api/monitor/:stop/', function (req, res, next) {
var stop = req.params.stop,
numResults = req.query.numResults,
timeOffset = req.query.timeOffset;
yourFunc(stop, numResults, timeOffset);
});
That way you can call the api with the following url: http://example.com/api/monitor/somethingAboutStop/?numResults=1&timeOffset=2. It looks like the stop parameter can also be moved to the query object but it's up to you.
You can use a catchall route then parse it yourself.
Example:
app.get('/api/monitor/*', apiController.monitor);
Then in apiController.monitor you can parse the url further:
exports.monitor = function(req, res) {
var parts = req.url.split('/');
console.log(parts); // [ '', 'api', 'monitor', '32', 'time' ]
console.log(parts.length); // 5
res.end();
};
So, hit the /api/monitor/32/time, and you get that array above. Hit it with /api/monitor/something/very/long/which/you/can/parse and you can see where each of your params go.
Or you can help yourself, like /api/monitor/page/32/offset/24/maxresults/14/limit/11/filter/by-user
Though, as Deif has told you already, you usually do pagination with query parameters, maxResults & page being your usual params.

Resources