How to update content in dynamic URLs in Express? - javascript

Below have I created 3 URL's from the fn array. In real life, this would be approx 200 different filenames.
After I have created them, would I like to be able to update the content of the URL's to be either 1 or 0.
With the below PoC, the content doesn't change.
Question
Does anyone know how I can change the content of the URL's on-the-fly?
const express = require('express');
const app = express();
const fn = ['filename1', 'filename2', 'filename3'];
for (const e of fn) {
app.get(`/${e}`, (req, res) => {
res.send(e);
});
};
app.get(`/filename1`, (req, res) => {
res.send('test');
});
const port = 1900;
app.listen(port, () => {
console.log(`http://localhost:${port}/`);
});

You can create one wildcard route listener and add your logic inside of it
const express = require('express');
const app = express();
const fn = ['filename1', 'filename2', 'filename3'];
app.get("/*", (req, res) => {
// Do your logic inside
if(fn.includes(req.url.replace('/',''))) return res.send('ok');
res.status(404).send('Not Found');
});
const port = 1900;
app.listen(port, () => {
console.log(`http://localhost:${port}/`);
});

Related

How can we implement an admin panel in nodeJS with express?

I am making a Portfolio application with nodeJS and express. I want to implement an admin panel which I can create,delete, update and edit my skills,experience,about etc, but I don't know how can I keep those admin routes secret and what kind of authentication to make.If we can do by putting Basic authentication on post,patch,delete route then how will we implement basic authentication on routes.
index.js
const express = require('express');
const app = express();
var cors = require('cors');
require('./db/mongoose')
const menuRouter = require('./routers/menu')
const skillRouter = require('./routers/skill')
const aboutRouter = require('./routers/About')
const experienceRouter = require('./routers/Experience')
const resumerouter = require('./routers/Resume')
const userRouter = require('./routers/user')
const port = process.env.PORT || 4000;
app.use(express.json());
app.use(cors());
app.use(menuRouter);
app.use(skillRouter);
app.use(aboutRouter);
app.use(experienceRouter);
app.use(resumerouter);
app.use(userRouter)
app.listen(port, () => {
console.log("Server is runing on port" + port)
});
skill.js
const express = require('express');
const Skill = require('../model/skill');
const router = new express.Router();
router.post('/skill', async (req, res) => {
const skill = new Skill(req.body);
try {
await skill.save();
res.status(201).send(skill);
} catch (e) {
console.log(e);
res.status(400).send(e);
}
})
router.get('/skill', async (rq, res) => {
try {
const skill = await Skill.find({});
res.status(201).send(skill);
} catch (e) {
res.status(400).send(e);
}
})
module.exports = router;
As specified in the comments, I would refactor your code a bit, seems messy and you're kind'a repeating yourself every line you import a route, so, you should do it better as well...
have an index.js file in your /routers folder with the content of the demo repo I've made for other StackOverflow question
then, to separate things, I would do something like:
const routes = require('./routes')
...
const protectRouteWithApiKey = (req, res, next) => {
const auth = req.headers['x-apikey']
if (auth && auth === '<YOUR API KEY>') return next()
return next(new Error('403 | Authorization is missing or value is wrong'))
}
...
app.use('/api', protectRouteWithApiKey, routes) // point to your routes and protect access
app.use('/', defaultEngine) // your engine to render html
you would then have a protected route in /api/* and normal routes for everything else
A middleware where you detect if the logged user is the admin?
In this sample checking by the email, and you can save the adminemail as a global variable
ensureAdmin: function(req, res, next) {
if (req.isAuthenticated()) {
if (req.user.email === adminemail) {
return next();
} else {
return res.redirect('/adminsecretroute');
}
}
res.redirect('/');
}

While running a MOCK API server in Node.js, getting an error message CANNOT GET /

I am getting "CANNOT GET/" error message while running a MOCK API server opening my localhost on port 3000 via my browser (http://localhost:3000) using the following index.js file. It's listening to the port at 3000 when I do the npm start run. When I try to open the browser it comes up with the error message above. Can you please tell me what I am doing wrong?
I have tried to replace const fixtures = require('./data/fixtures'); with app.use(express.static('./data/fixtures')); Run npm install and npm start run but it's still same error. Can someone please help?
"use strict";
const express = require('express');
const bodyParser = require('body-parser');
const port = 3000;
const hostname = '127.0.0.1';
const app = express();
app.use(bodyParser.json());
const fixtures = require('./data/fixtures');
let fixturesDB = JSON.parse(JSON.stringify(fixtures));
const HTTP_STATUS_CODE_NOT_FOUND = 404;
const getFixtureById = id =>
fixturesDB.find(fixture => fixture.fixtureId === id);
const getFixtureIndex = id =>
fixturesDB.findIndex(fixture => fixture.fixtureId === id);
const randomIntBetweenMinMax = (min, max) =>
Math.floor(Math.random() * max) + min;
const secondsToMillis = seconds => seconds * 1000;
const betweenOneAndFiveSecondsInMillis = () =>
secondsToMillis(randomIntBetweenMinMax(1, 5));
const delayPutAction = fixture =>
new Promise((resolve, reject) => {
setTimeout(() => {
fixturesDB.push(fixture);
resolve();
}, betweenOneAndFiveSecondsInMillis());
});
const checkIfFixtureExists = fixtureId => getFixtureIndex(fixtureId) !== -1;
const fixtureNotFound = res =>
res.status(HTTP_STATUS_CODE_NOT_FOUND).send("Fixture not found");
app.get("/fixtures", (req, res) => res.json(fixturesDB));
app.get("/fixture/:id", (req, res) => {
const fixtureId = req.params.id;
checkIfFixtureExists(fixtureId)
? res.json(getFixtureById(fixtureId))
: fixtureNotFound(res);
});
app.post("/fixture", async (req, res) => {
await delayPutAction(req.body);
res.send("Fixture has been added");
});
app.delete("/fixture/:id", (req, res) => {
const fixtureId = req.params.id;
if (checkIfFixtureExists(fixtureId)) {
fixturesDB = fixturesDB.filter(fixture => fixture.fixtureId !== fixtureId);
res.send("Fixture has been deleted");
} else {
fixtureNotFound(res);
}
});
app.listen(port, hostname, () => console.log("Server is listening on port 3000"));
The url http://localhost:3000 should display the content of the ./fixtures which are the reponse Json data instead of the error message "CANNOT GET/"
You don't have a '/' route, hence CANNOT GET /. If you want it to point to an existing '/fixture' route, you can do something like app.get('/', (req, res) => res.redirect('/fixtures'))
You could use static middleware (although it's not very appropriate in your case):
you need to point it to a directory, e.g. app.use('/', express.static('./data/fixtures'))
the files in ./data/fixtures/ directory are made available at the specified route, e.g. http://localhost:3000/fixtures/list.html points to './data/fixtures/list.html'
you can override a default index file for static middleware, e.g. app.use('/', express.static('./data/fixtures', {index: 'list.html'})) will make http://localhost:3000 show ./data/fixtures/list.html

Route.delete() requires a callback function but got a [object Object]

I have node-express app where I have bunch of Routes for login, logout and signup and one Route for checking authorised Route which can be accessed only through providing authToken. I moved the Routes to separate Route file and I got the above error.
This is my Users Routes File:
const express = require('express');
const authenticate = require('./../middleware/authenticate');
const router = express.Router();
const {User} = require('./../models/user');
router.post('/',(req, res) => {
var body = _.pick(req.body,['email','password']);
var user = new User(body);
user.save().then(() => {
return user.generateAuthToken()
}).then((token) => {
res.header('x-auth', token).send(user);
}).catch((e) => {
res.status(400).send(e);
});
});
router.post('/login',(req, res) => {
var body = _.pick(req.body, ['email', 'password']);
User.findByCredentials(body.email, body.password).then((user) => {
return user.generateAuthToken().then((token) => {
res.header('x-auth', token).send(user);
});
}).catch((e) => {
res.status(400).send(e);
});
});
router.delete('/logout',authenticate, (req, res) => {
req.user.removeToken(req.token).then(() => {
res.status(200).send();
},(e) => {
res.status(400).send(e);
}) ;
});
router.get('/me',authenticate, (req,res) => {
res.send(req.user);
});
module.exports = router;
Following is my main server.js file:
const express = require('express');
const _ = require('lodash');
var app = express();
const usersRoutes = require('./routes/users');
app.use(express.json());
app.use('/users', usersRoutes);
var {mongoose} = require('./db/mongoose');
var {User} = require('./models/user');
var {authenticate} = require('./middleware/authenticate');
const port = process.env.PORT || 3000 ;
app.listen(port, () => console.log(`Listening on ${port}...`))
I have a model/Schema(mongoose) file for User so If You feel you need that I am ready to edit my question. Thanks.
The problem is that router.delete is expecting a function on the middleware parameter (like you did in your server.js file with app.use(express.json())) so it can be used like a callback which gets called whenever a request reach your route.
Try changing authenticate to authenticate().
It seems like in your users routes file you are importing the entire module who contains the authenticate function, so when try to access it like a function you'll get an error. You need to import it like you did in your server.js file.
Change the line const authenticate = require('./../middleware/authenticate'); for const {authenticate} = require('./../middleware/authenticate');.

How to save a variable before serving a file in nodejs

given the following code:
const https = require('https');
const fs = require('fs');
var path = require('path');
const express = require('express');
const app = express();
const router = express.Router();
const pool = require('./mysqldb.js');
const pathView = __dirname + "/views/";
const IMGPath = "/public";
var bodyParser = require("body-parser");
const listenPort = 8010;
var id = null ;
router.get('/details/:id', async function (req, res, next) {
id = req.params.id;
if ( typeof req.params.id === "number"){id = parseInt(id);}
res.render('details.ejs' );
});
The main goal is to save that req.params.id(the id from the url) in the id variable before serving the details.ejs file.I tried to remove the async but didn't work.Can you help me please?
You can make use of the await keywords inside your async function like so:
router.get('/details/:id', async function (req, res, next) {
await (() => { id = req.params.id; })(); // Will run first
await (() => { res.send(id); })(); // Will run second
})
res.send(id) or res.render('details.ejs') ( in your case ) will run after the id is retrieved
It seems to be working fine for me. Below, I launch this server, then I go to http://localhost:3050/123 and suddenly I'm console.logging '123' over and over again, and the correct text displays on the screen.
So... idk what else if going on for you, but it might help if you try your best to distill your code down to the simplest possible iteration to try to debug. Just try to replicate it elsewhere. You might find one of your additional modules is causing an issue.
const express = require('express')
const app = express();
const port = 3050;
let id = null;
app.get('/:id', (req, res) => {
return res.send('Hello World!')
});
app.get('/details/:id', (req, res) => {
if (req.params.id){
id = req.params.id;
}
// 'id' will appear in browser
return res.send(`See details for id: ${id}`);
});
// console logs of 'id'
setInterval(() => { console.log(`id is currently ${id}`); }, 1000);
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
I don't think async/await will have any effect on this specific issue. I doubt they're related.
This seems to work for me,
router.get('/details/:id', async function (req, res, next) {
id = typeof req.params.id === 'number' ? parseInt(id) : req.params.id;
console.log(id);
res.send('details.ejs' );
});

Node.js node-postgres get JSON objects from API call

I have followed the node-postgres.org instruction at https://node-postgres.com/guides/async-express to connect via async/await to my postgres table users.
Navigating to localhost:3000/users/1 will return the JSON string for user 1 in the browser. I have extended this a bit to return all users at localhost:3000/users. My routes/user.js script is:
const Router = require('express-promise-router')
const db = require('../db')
// create a new express-promise-router
// this has the same API as the normal express router except
// it allows you to use async functions as route handlers
const router = new Router()
// export our router to be mounted by the parent application
module.exports = router
router.get('/:id', async (req, res) => {
console.log('Where id = ');
const { id } = req.params
const { rows } = await db.query('SELECT * FROM users WHERE id = $1', [id])
res.send(rows[0])
})
router.get('/', async (req, res) => {
console.log('*');
const { rows } = await db.all('SELECT * FROM users')
res.send(rows)
})
the index for this route at routes/index.js is simply:
const users = require('./user')
module.exports = (app) => {
app.use('/users', users)
}
and the db.query() and db.all() functions that I am awaiting are in db/index.js:
const { Pool } = require('pg')
const pool = new Pool()
module.exports = {
query: (text, params) => pool.query(text, params),
all: (text) => pool.query(text)
}
The routes are required in my main app.js file:
// ./app.js
const express = require('express')
const mountRoutes = require('./routes')
const cons = require('consolidate')
const path = require('path')
const bodyParser = require('body-parser')
const app = express()
mountRoutes(app)
// Assign Dust Engine to .dust files
app.engine('dust', cons.dust);
// Set .dust as the default extension
app.set('view engine', 'dust');
app.set('views', __dirname + '/views');
// Set Public Folder
app.use(express.static(path.join(__dirname, 'public')));
//Body parser and Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.get('/', function(reg, res) {
console.log('Root');
res.render('index', {hallo:'test'})
});
//Server
app.listen(3000, function() {
console.log('Server Started on Port 3000');
});
So far this works beautifully! I get the JSON strings that I want and I can build upon this sort of API by extending my routes and queries.
Question:
How can I return my JSON object rows back to app.js to res.render() it there?
or
Can I do something like this anywhere in my app:
jsonVar = GetMyJson('/users/1');
console.log(jsonVar);
returns:
[
{
"id": 1,
"usr_name": "Michael"
},
{
"id": 2,
"usr_name": "Thomas"
},
{
"id": 3,
"usr_name": "Paul"
}
]
I could then pass whatever route and parameters I want into GetMyJson() and deal with the resulting JSON.
This may be a trivial question for javascript devs ...
Thanks!
EDIT 21/12/2017
I have created a frontend script called graphs.js that simply logs my result when i call the fuction api('/user/1').
var el = document.getElementById("clickMe");
if (el.addEventListener)
el.addEventListener("click", api, false);
else if (el.attachEvent)
el.attachEvent('onclick', api);
var api = function(what){
// Action
sendRequest(what, function(result){
if(result){
log(result);
}
})
}
var apiEndpoint = 'http://localhost:3000/'
function sendRequest(_path, cb) {
var oReq = new XMLHttpRequest();
oReq.open('GET', apiEndpoint+_path);
oReq.onreadystatechange = function() {
if (this.readyState === 4) {
cb(JSON.parse(this.response));
}
else{
cb(null);
}
}
oReq.send();
}
function log(msg){
console.log(msg);
}
BUT
Is that a proper way of doing it in javascript?
The way to go about it would be something like this:
router.get('/', async (req, res) => {
console.log('*');
const { rows } = await db.all('SELECT * FROM users')
res.render('user', rows)
});
Instead of res.send you do res.render
You have to get it from database. Making self call will not be an ideal solution. So you can do following
const db = require('../db') // fix the location of db.js
app.get('/', function(req, res) {
db.all('SELECT * FROM users').then(function({ rows }) {
res.render('index', rows)
})
})
Best would be to make an userRepository.js and add code related to db over there. Then use that repository at both places.

Categories