node axios as middleware - express

I am trying to construct a middleware and then use it within the app.get route.
I know it's looks very "pioneer" but i am learning.... How can io get it to work?
const BooksMiddle = async (req, res, next) => {
axios
.get(`https://www.googleapis.com/books/v1/volumes/? q=${term}&keyes&key=${process.env.GBOOKSKEY}`)
.then((result) => {
const data = result.data;
const books = data.items;
return books;
});
next();
}
module.exports = textMiddle;
app.get("/", textMiddle, (req, res, next) => {
res.render('index');
});

If the point of this middleware is to get some book data and make that available for your template rendering, then you can put that data into res.locals where templates called from res.render() will automatically look for data:
const bookMiddle = async (req, res, next) => {
axios
.get(`https://www.googleapis.com/books/v1/volumes/?q=${term}&keyes&key=${process.env.GBOOKSKEY}`)
.then((result) => {
res.locals.books = result.data.items;
next();
}).catch(next);
}
module.exports = bookMiddle;
And, then after you import bookMiddle, you can use it like this:
app.get("/", bookMiddle, (req, res, next) => {
res.render('index');
});
If you refer to the books data structure in your template, the template engine will look in res.locals.books for that data (where the middleware puts the data).

Related

Cleaner way to write api route handlers in NextJS

Currently most of the api route handlers are in the following shape(api/test.js):
export default function handler(req, res) {
if (req.method === 'POST') {
// Process a POST request
} else {
// Handle any other HTTP method
}
}
where we constantly compare req.method with ifs
Is there a way to write it similar to ExpressJS:
app.get(...)
import nextConnect from 'next-connect';
const handler = nextConnect();
//handler.use(middleware);
handler.get(async (req, res) => {
...your code
})
...
handler.post(async (req, res) => {
...your code
})
...
So in theory you can have /api/product where you have .get .post .delete (etc) in 1 api route
Clean solution (/api/product.js)
const handler = async (req, res) => {
try {
}
catch(e){
}
}

how to insert a express middleware after app init?

app = express();
I established a socket connection after app.use(), and I want to insert another middleware after socket is connected:
const app = express();
app.use('/', () => {});
const wss = new ws.Server({ port: 8086 });
wss.on('connection', (ws) => {
app.use((req, res, next) => {
ws.send(JSON.stringify({ req, res }));
next();
});
});
app.listen(8080);
but it doesn't work,can Express insert a middleware after app init?
one solution is to make a middleware that checks if a new middleware is added. check the following example.
//this is an array of functions which will work as a middlware.
let listOfMiddlewareFunctions = [];
app.use((req, res, next) => {
//this middleware will loop through all elements in listofMiddlewareFunctions
//and pass the parameters req, res, next to each middlewares.
listOfMiddlewareFunction.foreach(middleware => middleware(req, res, next));
});
wss.on('connection', (ws) => {
//on socket connection, the following will add the middleware to the array made before.
const newMiddleware = (req, res, next) => {
ws.send(JSON.stringify({ req, res }));
next();
};
listOfMiddlewareFunction .add(newMiddleware);
});
finally, I fixed this problem:
wss.on('connection', function (ws) {
app._mockUsedWsSend = ws.send.bind(ws);
});
// in router
const wsSend = req.app._mockUsedWsSend;
if (wsSend) {
wsSend(JSON.stringify({
path: req.path
}));
}

Static files inside `public` folder not being served (NextJS custom server using ExpressJS)

I am working on NextJS app. And I have made a custom server using ExpressJS. The problem is when I run the app using the custom server the app cannot find the static files inside the public folder.
Note: I don't have any problem When I run the app using next dev
My server
const express = require('express');
const next = require('next');
const path = require('path');
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const prefix = (path = '') => `/:lang(en|tr)?`.concat(path);
app.prepare().then(() => {
const server = express();
server.get(prefix('/'), (req, res) => app.render(req, res, '/', req.query));
server.get(prefix('/agency'), (req, res) => app.render(req, res, '/agency', req.query));
server.get(prefix('/cases'), (req, res) => app.render(req, res, '/cases', req.query));
server.get(prefix('/blog'), (req, res) => app.render(req, res, '/blog', req.query));
server.get(prefix('/contact'), (req, res) => app.render(req, res, '/contact', req.query));
server.get(prefix('/image.png'), (req, res) => app.render(req, res, '/public/images/avatar01.jpg', req.query));
server.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
});
It is because you are not implementing a fallback for when there is no match:
server.all('*', async (req, res) => {
return handle(req, res);
}
will handle all the other routes for you (API routes, public/static folder, etc).

routes in exported router not available in app

I'm trying to export a router 'Accounts' to use in my app. The 'Accounts' router has the paths '/login' (POST), '/register'(POST), 'login' (GET), and '/logout' (POST). In my index app I am using the router with the path '/account'. So the paths should be:
/account/login (POST)
/account/login (GET)
/account/register(POST)
/account/logout (GET)
But when I call these paths they aren't found by the app:
How do I get the paths in the 'accounts.js' router to work in the 'index.js' app?
My file structure is like this:
my account.js file looks like this:
const express = require('express');
const passport = require('passport');
const Account = require('../models/Account');
const Branch = require('../models/Branch')
const router = express.Router({mergeParams: true});
const registerAccount = (req, res, next) => {
//register the account
};
const createUser = (req,res) => {
//create a user in another db
}
router.post('/register',
[registerAccount, createUser]);
router.get('/login', function(req, res) {
res.json(user);
});
router.post('/login', passport.authenticate('local', { successRedirect: '/',
failureRedirect: 'account/login' }));
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
});
module.exports=router;
and my index.js looks like this:
// index.js
var express = require("express");
var bodyParser = require("body-parser");
var jwt = require("jwt-simple");
var auth = require("../auth/auth.js")();
var users = require("./users.js");
var cfg = require("../config.js");
const accountController = require('./account');
var app = express();
app.use(bodyParser.json());
app.use(auth.initialize());
app.use('/account',accountController);
app.get("/", function(req, res) {
res.json({
status: "My API is alive!"
});
});
app.post("/token", function(req, res) {
//some token stuff that doesn't matter here
});
module.exports = app;
For starters, you don't pass an array to a router.post(), so change this:
router.post('/register', [registerAccount, createUser]);
to this:
router.post('/register', registerAccount, createUser);
And make sure that registerAccount calls next() when it's done and wants createUser() to get called.
In the doc, for this syntax:
app.post(path, callback [, callback ...])
the brackets in [, callback] mean that parameter is optional. The brackets are not supposed to be used.

Express: Render partially in each handler?

I have a modest little site that uses Express and Pug. Every page has a navbar that contains the user's name drawn from a user parameter and the main content of the page is below which uses a data parameter. The main content is rendered from a template that extends the root template. Both need their own parameter to render properly.
Is there a way to partially render a view in each handler?
var app = require('express')()
app.set('view engine', 'pug')
app.get('/', (req, res, next) => {
var userdata = '...'
req.render('/index', {user: userdata}
next() // the request is for /page
})
app.get('/page', (req, res, next) => {
var moredata = '...'
req.render('./page/index', {data: mroedata})
})
AFAIK that's not possible, but as an alternative, you can use res.locals to achieve something similar:
let userMiddleware = (req, res, next) => {
let userdata = '...';
res.locals.user = userdata;
next();
});
app.use(userMiddleware);
// This can stay the same:
app.get('/page', (req, res, next) => {
var moredata = '...'
req.render('./page/index', {data: mroedata})
})
This is a middleware that will make the user variable available to all of your templates, which seems to me is what you want.
Instead of applying it globally, you can also use it for specific routes:
app.get('/page', userMiddleware, (req, res) => ...);