Node.js Express show a Json file with Class Method - javascript

Just started with node.js and express and i was trying to show a json file containing an array of 3 objects with a class method
Here is the Class structure
const fs = require('fs')
class GrupoArchivo {
constructor(ruta) {
this.ruta = ruta
this.productos = []
}
_leer() {
return fs.promises.readFile(this.ruta, 'utf-8')
.then(texto => {
const productosComoArray = JSON.parse(texto)
this.productos = productosComoArray
})
}
async obtenerTodas() {
await this._leer()
return [...this.productos]
}
}
module.exports = GrupoArchivo
And here is the Js file with the express server
With the second "app.get" i was trying to get the method showing the json file with no luck
const express = require("express");
const GrupoArchivo = require('./GrupoArchivo.js')
const path = require("path");
const app = express();
app.get("/", (req, res)=>{
res.sendFile(path.join(__dirname + "/index.html"))
})
const grupo = new GrupoArchivo('./productos.json')
app.get("/productos", (req, res)=>
res.json(grupo.obtenerTodas()) //this returned me an {}
)
app.listen(8080, ()=>{
console.log("server listening on port", 8080)
})

All async functions return a promise, so when you call it, you have to use await or .then() to get the resolved value from that promise. You can add async and await like this:
app.get("/productos", async (req, res) => {
try {
res.json(await grupo.obtenerTodas());
} catch(e) {
console.log(e);
res.sendStatus(500);
}
});
Note, this also adds error handling so you can catch any errors from grupo.obtenerTodas().

Related

Node: Route.get() requires a callback function but got a [object Undefined]

Im trying to create a simple CRUD app in node js and i get Route.get() requires a callback function but got a [object Undefined] on the router.get("/:id", userController.getUser); line
Routes.js
const express = require('express')
const userController= require('../controllers/userController.js')
const router = express.Router()
/* READ */
router.get("/:id", userController.getUser);
module.exports = router
Controller.js
const getUser = async (req, res) => {
try {
const { id } = req.params;
const user = await User.findById(id);
res.status(200).json(user);
} catch (err) {
res.status(404).json({ message: err.message });
}
}
const Function..
const AnotherFunction..
module.exports = {
getUser,
Function,
AnotherFunction,
}
console.log(userController.getUser.toString()) prints:
async (req, res) => {
try {
const { id } = req.params;
const user = await User.findById(id);
res.status(200).json(user);
} catch (err) {
res.status(404).json({ message: err.message });
}
}
I don't have correct access rights to push into your repo so explaining the issue here.
In your auth.js you have exported verifyToken function as default export.
module.exports = verifyToken.
But you are destructuring when importing in postsController.js
const {verifyToken} = require ('../middleware/auth.js')
Importing like this will get the correct function =>
const verifyToken = require("../middleware/auth.js");
Change your postsController file as below. It should work.
const express = require("express");
const verifyToken = require("../middleware/auth.js");
module.exports = verifyToken;

How do I make Axios show css?

I am using axios to practice Web Scraping by making a Web Viewer, and I noticed that the CSS Wasn't Loading.
I used this code:
console.log("Tribble-Webviewer is starting!")
const express = require('express')
const app = express()
const port = 3000
const publicDir = app.use(express.static('public'))
var cheerio = require('cheerio'); // Basically jQuery for node.js
const axios = require('axios').default;
const rp = require('request-promise');
const url = 'https://pointless.com/';
app.get('/', (req, res) => {
app.use('/static', express.static('public'))
})
app.get('/test', (req, res) => {
axios.get(url)
.then(({ data }) => res.send(data))
})
app.listen(port, () => {
console.log(`Tribble-Pro is listening on port ${port}`)
})
If you load the /test page, the CSS does not show.
Example of the CSS not loading below:
Image
I used this async function:
async function getCssTest() {
try {
const response = await axios.get(urlplusstyle);
res.send(response)
} catch (error) {
console.error(error);
}
}

How to query on start of server in mongoose?

Start.js:
const express = require('express')
const app = express()
const port = 3000
mongoose.connect('mongodb://localhost:27017/myapp', {useNewUrlParser: true}); //to connect with mongodb..not exact code I used but this
Now lets say I have stored some data in mongodb....in Books collection stored in model books
I call the model and fetch from it:
const bookdetails = Books.find({ }).exec()
I tried :
var respo;
bookdetails.then(function(result) {
console.log(result) //gives the value stored in bookdetails
respo = result;
})
console.log(respo) //...but value not stored in here...it gives undefined
But console.log(bookdetails) it gives....Promise { } instead of all the data stored inside book collection. How can I fetch data on start of server....if I'm using through routes or calling api it is working perfectly fine
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
You can add a callback that will execute after the promise is resolved or use async/await
let bookDetails ;
Books.find()
.exec(function (err, book) {
if(err)
throw new Error(err)
else
bookDetails = book
});
or
const bookdetails = await Books.find({ })

How to access next.js rendered HTML via custom server

I want a server side generated page in next.js to be served as a file. So I wanted to grab the rendered content inside a custom server.js file:
const express = require('express');
const next = require('next');
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({dev});
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.get('/', async (req, res) => {
const nextResponse = await app.renderToHTML(req, res, '/', req.query);
console.log('nextResponse', nextResponse);
console.log('res.body', res.body);
});
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
});
Oddly enough every console.log returns null or undefined.
I thought that renderToHTML would just return the rendered HTML string. Is there any way to do this?
This one is a bit tricky but achievable.
The idea is to override res.end function in order to catch rendered HTML there. The tricky part is that Next.js gzips and streams response using the compression library that's overriding res.end somewhere in the middle of the handle function.
The compression library is initialized using the handleCompression function of the Next.js's Server object (which is accessible using the app.getServer()), so that function needs to get overridden too.
So it should be looking something like this:
const { parse } = require('url');
const next = require('next');
const express = require('express');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const port = process.env.PORT || 3000;
const handle = app.getRequestHandler();
app.prepare()
.then(() => {
const server = express();
server.get('*', async (req, res) => {
const parsedUrl = parse(req.url, true);
const nextServer = await app.getServer();
const _handleCompression = nodeServer.handleCompression.bind(nodeServer);
nextServer.handleCompression = (req, res) => {
_handleCompression(req, res);
const _resEnd = res.end.bind(res)
res.end = function (payload) {
console.log('Rendered HTML: ', payload);
return _resEnd(payload);
}
}
return handle(req, res, parsedUrl);
});
server.listen(port, err => {
if (err) throw err;
console.log('> Ready on http://localhost:' + port);
});
});
After you get rendered HTML you don't have to use the saved _resEnd function. Feel free to manipulate, serve as a file, or whatever you want with it.

Returning undefined object when doing a query

I'm building an application on Node.js that works with MongoDB through mongoose. The connection is perfect, I can add new documents, the problem is definitely not in the connection.
I'm building all the functions that work with mongoose in a separate .js file, which I called from dbconfig.js.
dbconfig.js
const mongoose = require('mongoose');
// Models
const User = require('./models/User');
const Category = require('./models/Category');
var database_name = "htm";
mongoose.Promise = global.Promise;
// Connection with database_name
var connect = () => {
mongoose.connect("mongodb://localhost/"+database_name, {useNewUrlParser: true}).then(() =>{
console.log("Conectado ao database: " + database_name);
}).catch((erro) => {
console.log("Erro ao se conectar ao database: " + database_name +" - "+ erro);
});
mongoose.model('users', User);
mongoose.model('categories', Category);
}
var getCategory = () => {
const Ref = mongoose.model('categories');
Ref.find().then((categories) => {
return categories;
})
}
module.exports = {
connect: connect,
getCategory: getCategory
}
The problem is in the getCategory () function, when I call it in my app.js (my main file of this project node.js), it returns only undefined. And I know that the variable categories are filled out because I inserted a console.log (categories); and got the following result:
[ { _id: 5c7ea6fb91526418ec3ba2fd,
name: 'UNHAS',
slug: 'unhas',
__v: 0 } ]
app.js
const express = require('express');
const app = express();
const categoriesRouter = require('./routes/categories');
const handlebars = require('express-handlebars');
const path = require('path');
const configDB = require('./dbconfig')
// Config
// Template Engine
app.engine('handlebars', handlebars({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
// Start Database Connection
configDB.connect();
// Public
app.use(express.static(path.join(__dirname, "public")));
// Routes
app.use('/categorias', categoriesRouter);
app.get('/', (req, res) => {
var categories = configDB.getCategory();
res.render('home', categories);
});
app.listen(3001, () =>{
console.log("Servidor iniciado na porta 3001");
});
Whenever the variable categories is received in my app.js it arrives as undefined.
Can someone help me?
You are not properly using the Promise object returned from getCategory() in your express router:
app.get('/', (req, res) => {
var categories = configDB.getCategory(); <-- this is a Promise, not a synchronous value
res.render('home', categories);
});
Instead, you can use async/await to help bridge the gap between your currently synchronous code and the asynchronous Promise-based database interface you have:
app.get('/', async (req, res) => {
var categories = await configDB.getCategory();
res.render('home', categories);
});
Inspired by a response given by #jakemingolla who suggested async-await, I started using callback to return the 'categories' object and everything worked perfectly.
function in my file dbconfig.js
const getCategoryList = (callback) => {
CategoryRef.find().then((categories) => {
callback(categories);
})
}
calling the function in my app.js file
app.get('/', (req, res) => {
database.getCategoryHomeList((categories) => {
res.render('home', {categories: categories});
})
});

Categories

Resources