Adding custom middleware - node.js

I have a route with a req.param of :groupIndex in it. I would like to process this index as middleware in order to get a specific id.
Node and express are new to me, so I'm possibly missing something simple but reading docs and looking at other implementations hasn't seemed to work.
Any idea where I might be going wrong?
// routes.js
const express = require("express");
const router = express.Router();
const customMiddleware = ('./customMiddleware.js');
const db = require('./mysqlCon.js');
router.get('/person/:groupIndex(\\d+)', customMiddleware(), function (req, res) {
let id = req.params.id;
let query = `
SELECT
*
FROM
data
WHERE
id = ?
`;
let query_params = [id];
db.query(
query,
query_params,
function(error, result, fields) {
if ( result.length == 1 ) {
res.status(200).json( result[0] );
} else {
res.status(401).json({});
}
}
);
});
// customMiddleware.js
const db = require('./mysqlCon.js');
module.exports = (req, res, next) => {
let groupIndex = parseInt(req.params.groupIndex);
let query = `
SELECT
id
FROM
listofids
LIMIT 1
OFFSET ?
`;
let query_params = [groupIndex];
db.query(
query,
query_params,
function(error, result, fields) {
if ( result.length == 1 ) {
req.params.id = result[0].id;
} else {
res.status(401).json({});
}
}
);
next();
}

I would review the middleware guide, but generally all middleware functions have the following signature:
function myMiddleware(req, res, next)
Where req, res, next are passed in from Express itself. You do not invoke the function, you simply pass it in as an argument (higher-order functions) to your route definition:
router.get('/person/:groupIndex(\\d+)', myMiddleware, ...)

Related

Query was already executed: User.find({}), why iam getting this error?

**
filtersRouter.js:-
filtersRouter.get('/search', getEmployeesByKey)
filterController.js
//?find employees by search key
export const getEmployeesByKey = async (req, res, next) => {
try {
const filters = req.query;
// filters.clone();
// const expr= req.query. expr;
// const {location, role} = req.query
const filterdusers = await User.find(user =>{
let isValid = true;
for(let key in filters){
console.log(key, user[key], filters[key]);
isValid = isValid && user[key] == filters[key]
}
return isValid;
});
if (!employees) {
return res_failed(res, "Employees are not found");
}
res_success(res, "search done", filterdusers);
console.log(res.query);
res.status(200).json(
{filterdusers}
)
}catch(error){
res_catch(res, error);
}
};
**search the employees by giving the values dynamically like "location":"hyderabad", "skills":"nodeJS" like this.
if i give the values like "location: Hyderabd", "skills:nodeJS", it should have to print the details of employees according to given input.

API logic to get latest weather information

I'm writing weather API which fetches METAR and TAFS data from aviation weather stations.
Data changes once an hour.
Need to fetch latest weather information, but in my code I cannot make it to fetch it after an hour.
var express = require('express');
var router = express.Router();
const ADDS = require('adds');
var moment = require('moment');
// adds moment to the locals
router.use((req, res, next)=>{
res.locals.moment = moment;
next();
});
const avWet = Promise.all([
ADDS('metars', {
stationString: 'KCRX,KMSL,KSNH,KTUP',
hoursBeforeNow: 1,
mostRecentForEachStation: true
}),
ADDS('tafs', {
stationString: 'KTUP,KMSL',
hoursBeforeNow: 1,
mostRecentForEachStation: true
})
])
.then(results => {
const parsedData = results;
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('wet_av', {
parsedData
})
})
});
module.exports = router;
You don't have to restart Your app to get data, so You don't have to use nodemon or another watcher which will restart the app too.
Simply write Your method which will get data and store it in variable
Schedule it to check for new data
Call that method to get data and push to render
const express = require('express');
const router = express.Router();
const ADDS = require('adds');
const moment = require('moment');
// adds moment to the locals
router.use((req, res, next)=>{
res.locals.moment = moment;
next();
});
let weatherInformation = null;
let weatherInformationParsedAt = 0;
async function getWeatherInformation() { // [1] method that will get data from api
const startOfHour = moment().startOf('hour').format('YYYY-MM-DD hh:')+'00';
const currentTimeString = moment().startOf('minute').format('YYYY-MM-DD hh:mm');
// if there is no data then need to parse
let needToParse = !weatherInformation;
// forcing to parse if it's 00'th minute of hour
if (startOfHour === currentTimeString &&
Date.now() - weatherInformationParsedAt > 30000
) { // if start of hour
needToParse = true;
}
// forcing to parse if data is old more than 2 mins, making sure we have fresh data
if (!needToParse &&
weatherInformation &&
Date.now() - weatherInformationParsedAt > 120000
) {
needToParse = true;
}
try {
// if need to parse so let's fetch again (that's for caching)
if (needToParse) {
const query = {
hoursBeforeNow: 1,
mostRecentForEachStation: true,
};
const results = await Promise.all([
ADDS('metars', {
...query,
stationString: 'KCRX,KMSL,KSNH,KTUP',
}),
ADDS('tafs', {
...query,
stationString: 'KTUP,KMSL',
}),
]);
weatherInformation = results;
weatherInformationParsedAt = Date.now();
}
}
catch (error) {
console.error(error);
}
return weatherInformation;
}
setInterval(getWeatherInformation, 1000); // [2] every second call method which checks for changes
router.get('/', async (req, res, next) => {
const parsedData = await getWeatherInformation(); // [3] calling method to get weather information
res.render('wet_av', {
parsedData,
});
});
module.exports = router;

Get param in URL without callback function

so I know how to get params from URL the normal way:
router.get('/products/:id', (request, response, next) => {
let id = request.params.id;
But when I want to refactor the code to many files, the code becomes something like:
const productService = require('../services/productService');
router.get('/products/:id', productService.getProductList);
How can I get the "id" from URL now?
The productService.js file:
var mongodb = require('mongodb');
const db = require('../models/mongoUtil.js').getDb();
const getProductList = async (request, response) => {
try {
let id = request.params.id;
let object_id = new mongodb.ObjectId(id);
const result = await db.collection('product_list').findOne({ '_id': object_id });
response.json(result);
console.log(result);
} catch (err) {
console.log(err);
}
};
module.exports = {
getProductList
};
Thank you. I am new to Node Js.

How to allow users to add in parameter in api?

How to allow users to add in parameter in api? i.e http://localhost:8080/amk_codes?collada_north=1.361692308&collada_east=103.8527273
I have the following codes:
app.get("/amk_codes", async (req, res) => {
const rows = await readamk_codes();
res.send(JSON.stringify(rows))
})
async function readamk_codes() {
try {
const results = await client.query("select collada_north,collada_south,collada_east from amk_codes");
return results.rows;
}
catch(e){
return [];
}
}
The parameters in url are located in req.query object. In your example you can access to collada_north and collada_south values with req.query.collada_north and req.query.collada_south.
app.get("/amk_codes", async (req, res) => {
var collada_north = req.query.collada_north
var collada_south = req.query.collada_south
const rows = await readamk_codes();
res.send(JSON.stringify(rows))
})
...
Of course you have to check if parameters are present in the request ( they could also be null I think ).

Save multiple model documents in one POST route with Mongoose/Express/Node

I have a one-to-many relationship with my Search model and Result model. My user will do a search, select the results that were helpful, and hit a save button. That save button will hit an app.post() request. This should save an instance of the Search and one (or more) instance(s) of the selected Results. I can successfully save the Search instance with the following code:
controllers/searchController.js
const Search = require('../models/search');
exports.search_create_post = (req, res) => {
let newSearch = new Search({ search_text: req.body.search_text });
newSearch.save((err, savedSearch) => {
if (err) {
console.log(err);
} else {
res.send(savedSearch);
}
})
routes/search.js
const express = require('express');
const router = express.Router();
const search_controller = require('../controllers/searchController');
//Search Routes
router.get('/', search_controller.search_home);
router.get('/results', search_controller.search_results_get);
router.post('/', search_controller.search_create_post);
module.exports = router;
How can I make it so that my user hitting the save button once will save the Search instance above and also the Results?
I ended up doing what I needed by passing two callbacks into my post() route and calling next() inside the first one along with passing the data the second one needed through the req object. My code is as follows:
routes/search.js
router.post('/', search_controller.search_create_post, result_controller.result_create_post);
controllers/searchController.js
exports.search_create_post = (req, res, next) => {
let newSearch = new Search({ search_text: req.body.search_text });
newSearch.save((err, savedSearch) => {
if (err) {
console.log(err);
} else {
req.searchData = savedSearch;
}
next();
})
};
controllers/resultController.js
exports.result_create_post = (req,
let newResult = new Result({ url: 'req.body.url', search: req.searchData });
newResult.save((err, savedResult) => {
if (err) {
console.log(err);
} else {
res.send(savedResult);
}
})
};

Resources