Why bodyParser returns undefined? - node.js

I can't get body of request for the POST http://127.0.0.1:3001/users?name=Slava.
Server responce 'name is required'. Method getUsers work correctly. RethinkDB works good, server.js works too. I searched for similar answers here, but there is nothing suitable. There are very old answers, but they are not relevant.
This is request: http://127.0.0.1:3001/users?name=bob (I use Postman for POST)
Why bodyParser don't work in my code? I have no idea why this happens.
const Koa = require('koa')
const logger = require('koa-morgan')
const bodyParser = require('koa-bodyparser')
const Router = require('koa-router')
const r = require('rethinkdb')
const server = new Koa()
const router = new Router()
const db = async() => {
const connection = await r.connect({
host: 'localhost',
port: '28015',
db: 'getteamDB'
})
return connection;
}
server.use(bodyParser());
const insertUser = async(ctx, next) => {
await next()
// Get the db connection.
const connection = await db()
// Throw the error if the table does not exist.
var exists = await r.tableList().contains('users').run(connection)
if (exists === false) {
ctx.throw(500, 'users table does not exist')
}
let body = ctx.request.body || {}
console.log(body);
// Throw the error if no name.
if (body.name === undefined) {
ctx.throw(400, 'name is required')
}
// Throw the error if no email.
if (body.email === undefined) {
ctx.throw(400, 'email is required')
}
let document = {
name: body.name,
email: body.email
}
var result = await r.table('users')
.insert(document, {returnChanges: true})
.run(connection)
ctx.body = result
}
router
.post('/users', insertUser)
server
.use(router.routes())
.use(router.allowedMethods())
.use(logger('tiny')).listen(3001)

Body parser is used to parse POST requests (for POST body), here you have to use req.query instead of req.body, follow up this question.

Related

caching query with redis

i need to cache a query with redis and node js , the database is aws s3 ,the problem here as a noob ,i will recive the query as a string, i need to encode the keys in the body request so when i will later try to fetsch the data i will use one of those keys(they need to be seperated with '/') can anyone help me with that and bunch of thanks.
here is what i' tried to do:
const { default: axios } = require('axios');
const express = require('express');
const redisClient = require('./helper/Client')
const app = express();
const port = process.env.PORT || 3000
app.use(express.json());
async function fetchApi(species){
const apiResponse = await axios.get(`https://www.fishwatch.gov/api/species/${species}`)
console.log('request sent successfully');
return apiResponse.data
}
async function getSpeciesData(req, res) {
const species = req.body;
const keys = Object.keys(species);
const encodedParams = {};
for (const key of keys) {
const encodedKey = Buffer.from(key).toString('base64');
encodedParams[encodedKey] = species[key];
}
const key = JSON.stringify(encodedParams);
let resultat;
let isCached = false;
const cachedResponse = await redisClient.get(key);
if (cachedResponse) {
isCached = true;
const decodedResponse = Buffer.from(cachedResponse, 'base64').toString('utf-8');
resultat = JSON.parse(decodedResponse);
res.send({
fromCache: isCached,
data: resultat
});
console.log(cachedResponse);
} else {
const responseData = await fetchApi(keys.join('/'));
const encodedResponseData = Buffer.from(JSON.stringify(responseData)).toString('base64');
redisClient.SETEX(key, 3600, encodedResponseData);
res.send(responseData);
}
}
app.post("/fish", getSpeciesData);
app.listen(port, () => {
console.log(`Listening on ${port}`);
});

TypeError: Cannot read property 'then' of undefined , TypeError: _cb is not a function

my code in github, but I didn't upload the latest version:
https://github.com/godzillalogan/markdownblog
I use node.js and express.js framework. Database use mongoDB.
I am using the package Imgur and dotenv, try to upload image to imgur.
But I encounter some bug:
bug:
App is running on http://localhost:3000
mongodb connected!
TypeError: Cannot read property 'then' of undefined
at Promise (D:\Github\markdownblog\helpers\file-helpers.js:26:7)
at new Promise (<anonymous>)
at imgurFileHandler (D:\Github\markdownblog\helpers\file-helpers.js:23:10)
at router.put (D:\Github\markdownblog\routes\modules\admin.js:115:26)
at process._tickCallback (internal/process/next_tick.js:68:7)
D:\Github\markdownblog\node_modules\imgur-node-api\lib\imgur.js:34
_cb(null, body);
^
TypeError: _cb is not a function
at Request._callback (D:\Github\markdownblog\node_modules\imgur-node-api\lib\imgur.js:34:9)
at Request.self.callback (D:\Github\markdownblog\node_modules\request\index.js:142:22)
at Request.emit (events.js:182:13)
at Request.<anonymous> (D:\Github\markdownblog\node_modules\request\index.js:856:14)
at Request.emit (events.js:187:15)
at IncomingMessage.<anonymous> (D:\Github\markdownblog\node_modules\request\index.js:808:12)
at IncomingMessage.emit (events.js:187:15)
at endReadableNT (_stream_readable.js:1094:12)
at process._tickCallback (internal/process/next_tick.js:63:19)
[nodemon] app crashed - waiting for file changes before starting...
Here is my code:
app.js:
const path = require('path') // 引入 path 套件
const express = require('express')
const session = require('express-session')
const bodyParser = require('body-parser') //新版express以內建body-parser
const { engine } = require('express-handlebars');
const flash = require('connect-flash')
if (process.env.NODE_ENV !== 'production') { //要放在const routes = require('./routes')前面
require('dotenv').config()
}
const routes = require('./routes')
const app = express()
const PORT = process.env.PORT || 3000
const methodOverride = require('method-override') // 載入 method-override
//others code............
helpers/file-helpers.js:
const fs = require('fs') // 引入 fs 模組, fs 模組是 Node.js 提供專門來處理檔案的原生模組
//載入 imgur 套件
const imgur = require('imgur-node-api')
const IMGUR_CLIENT_ID = process.env.IMGUR_CLIENT_ID
console.log('IMGUR_CLIENT_ID:',IMGUR_CLIENT_ID)
imgur.setClientID(IMGUR_CLIENT_ID)
const localFileHandler = file => { // file 是 multer 處理完的檔案
return new Promise((resolve, reject) => {
if (!file) return resolve(null)
const fileName = `upload/${file.originalname}`
return fs.promises.readFile(file.path)
.then(data => fs.promises.writeFile(fileName, data))
.then(() => resolve(`/${fileName}`))
.catch(err => reject(err))
})
}
const imgurFileHandler = file => {
return new Promise((resolve, reject) => {
if (!file) return resolve(null)
return imgur.upload(file.path)
.then(img => {
// resolve(img?.link || null) // 檢查 img 是否存在
resolve(img ? img.link : null)
})
.catch(err => reject(err))
})
}
module.exports = {
localFileHandler,
imgurFileHandler //img
}
routes/modules/admin:
const express = require('express')
const router = express.Router()
const Article = require('../../models/article');
const Category = require('../../models/category');
const User = require('../../models/user');
const Contact = require('../../models/contact');
const upload = require('../../middleware/multer') // 載入 multer
const { imgurFileHandler } = require('../../helpers/file-helpers') // 將 file-helper 載進來
////others code....
//edit user
router.put('/users/:id', upload.single('avatar'), async (req, res)=>{
try{
console.log('有到edit user嗎')
const _id = req.params.id
const { name,avatar,introduction } = req.body
const { file } = req // 把檔案取出來
const user = await User.findOne({ _id})
const filePath = await imgurFileHandler(file) // 把檔案傳到 file-helper 處理
user.name = name
// user.cover = filePath || user.cover
user.avatar = filePath || user.avatar
user.introduction = introduction
await user.save()
res.redirect('/about')
}catch(e){
console.log(e)
res.redirect(`/admin/users`)
}
// const {title,description,markdown} = req.body //和new一樣才能將markdown轉成html
// Article.create({...req.body})
// res.redirect('/')
////others code....
})
What I have try:
I think it is about promise problem, and localFileHandler in helpers/file-helpers.js is work successful , but why imgurFileHandler in helpers/file-helpers.js is not work .
Thank you for your help.
It's probably because imgur.upload() dosent support promises and you should pass a callback as a second argument to the function like this :
imgur.upload(file.path, (err, response) => {
if(err) {
return null
}
return response.data.link
})
I move it from helpers/file-helpers.js to routes/modules/admin.js. And the way
is success.
But I think there would have another better way.
routes/modules/admin.js
I add Imgur to the route in create article,edit article and edit user.
routes/modules/admin.js
//Create
router.post('/articles', upload.single('image'), async (req,res)=>{
// console.log(req.body)
// const article = new Article({
// title: req.body.title,
// description: req.body.description,
// markdown: req.body.markdown
// });
try{
const {title,category,description,markdown} = req.body
const{file} = req
console.log('file:',file)
if (file){
imgur.setClientID(IMGUR_CLIENT_ID)
imgur.upload(file.path,(err, img) =>{
Article.create({...req.body, image: file ? img.data.link: null})
})
}else{
Article.create({...req.body})
}
res.redirect('/admin/articles')
} catch(e){
console.log(e)
res.render('admin/articles',{ article })
}
})
////Update
//到edit頁
router.get('/articles/edit/:id', async (req, res) => {
// const _id = req.params.id
// return Article.findOne({ _id})
// .lean()
// .then((article) => res.render('edit', { article}))
// .catch(error => console.log(error))
try{
const _id = req.params.id
const article = await Article.findOne({ _id}).lean()
const categories = await Category.find().lean().sort({createdAt:'desc'})
res.render('edit', { article,categories})
}catch{
console.log(e)
res.redirect(`/articles/edit/:id`)
}
})
//edit article
router.put('/articles/:id', upload.single('image'), async (req, res)=>{
try{
const _id = req.params.id
const { title,description,markdown,category } = req.body
const { file } = req // 把檔案取出來
const article = await Article.findOne({ _id})
if (file){
// const filePath = await imgurFileHandler(file) // 把檔案傳到 file-helper 處理
imgur.setClientID(IMGUR_CLIENT_ID)
imgur.upload(file.path,async (err, img) =>{
// Article.update({...req.body, image: file ? img.data.link: article.image})
article.title = title
article.description = description
article.markdown = markdown
article.category = category
article.image = img.data.link
await article.save()
})
}else{
article.title = title
article.description = description
article.markdown = markdown
article.category = category
await article.save()
}
res.redirect('/admin/articles')
}catch(e){
console.log(e)
res.redirect(`/admin/articles`)
}
// const {title,description,markdown} = req.body //和new一樣才能將markdown轉成html
// Article.create({...req.body})
// res.redirect('/')
})

Use collection get from req.params - node.js

I'm using node.js and mongodb I need to know how to request the reading of a certain collection via API
(day_07-07-2021 is the collection to search)
in the Node.js route I wanted to query the collection day07072021, I wanted to know how I change the collection (on the fly) to query the route using the "req.param" received via URL.
so after setting the collection I'll do find();
Each day will have a collection.
http://localhost:3000/registry/windows2021/1101/day07072021
My actual code is (updated after: Selva Mary), but still not working.
logs.js
const express = require('express')
const router = express.Router()
const logs = require('../models/registry')
router.get('/:device/:rule/:bydate', async (req, res) => {
try {
let byDate = req.params.bydate +"info"
const logues = await db.collection(byDate).find({
'agent.name': req.params.device,
'rule.id': req.params.rule
}).sort({ 'id': -1 }).limit(15);
res.json(logues)
}
catch (err) {
res.status(500).json({ message: err.message })
}
})
server.js
require('dotenv').config()
const express = require('express')
const app = express()
const mongoose = require('mongoose')
const log = mongoose.set('debug', true)
mongoose.connect('mongodb://db:27017/datainfo', { useNewUrlParser: true,useUnifiedTopology: true })
const db = mongoose.connection
const registryRouter = require('./routes/registry')
app.use('/registry', registryRouter)
I hope its clear.
I get the message:
{"message":"db is not defined"}
Try this
router.get('/:device/:rule/:bydate', async (req, res) => {
try {
let byDate = req.params.bydate +"" // this makes the bydate as string. Collection name need to be in string
const logues = await logs.collection(byDate).find({
'agent.name': req.params.device,
'rule.id': req.params.rule
}).sort({ 'id': -1 }).limit(15);
res.json(logues)
}
catch (err) {
res.status(500).json({ message: err.message })
}
})

How to use image4io on node js

Im having problem following the documentation on image4io.
I just tried stuff. So the problem is that the image4io only returns Promise {}
here is my code
module.exports = function(app,db){
const Image4ioAPI = require('#image4io/image4ionodejssdk');
app.post('/addImage',(req,res)=>{
var apiKey = 'api key';
var apiSecret = 'api secret';
var api = new Image4ioAPI.Image4ioClient(apiKey, apiSecret);
let response=api.GetSubscription();
console.log(response)
})
}
It returns a promise you must use then or catch to access the response after the promise is fulfilled.
Ideal use case:
api.GetSubscription()
.then(response => {
// Response returns a JSON object, which can be accessed here
}).catch(error => {
throw error;
})
You can await a promise to show its result.
module.exports = function(app,db){
const Image4ioAPI = require('#image4io/image4ionodejssdk');
app.post('/addImage', async (req,res)=>{
var apiKey = 'api key';
var apiSecret = 'api secret';
var api = new Image4ioAPI.Image4ioClient(apiKey, apiSecret);
let response= await api.GetSubscription();
console.log(response)
})
}

async and await function Node.js

I have followed this tutorial to upload files into IPFS using Node.js, but I had a problem which doesn't appear in the tutorial!
It is related to with Async and await function, I can't make this statement
const fileHash = fileAdded[0].hash;
I tried with await
const fileAdded = await ipfs.add({path: Name, content: file});
but unfortunately, I got an error which is (hash undefined).
I tried with a callback function, but I'm not sure about my way because (fileAdded) variable didn't give me any answer and also it was undefined,
this is a full code:
const ipfsClient = require('ipfs-http-client');
const express = require('express');
const bodyParser = require('body-parser');
const fileUpload = require('express-fileupload');
const fs= require('fs');
const ipfs = new ipfsClient({host: 'localhost', port: '5001', protocol: 'http'});
const app= express();
var hash = require('hash');
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended:true}));
app.use(fileUpload());
app.get('/',(req,res)=>{
res.render('home');
});
app.post('/upload',(req,res)=>{
const f= req.files.file;
const Name = req.files.file.name;
const filePath ="files/"+ Name;
f.mv(filePath,async(err)=>{
if(err){
console.log("error failed to download a file");
return res.status(500).send(err);
}
const fileh = await addFile(Name,filePath);
fs.unlink(filePath, (err)=>{
if(err) console.log("error");
});
res.render('upload',{Name,fileh});
});
});
const addFile= async(Name,filePath)=> {
const file=fs.readFileSync(filePath);
const fileAdded = await ipfs.add({path: Name, content: file});
const fileHash = fileAdded[0].hash;
return fileHash;
};
app.listen(3000,()=>{
console.log("server is listen");
});
this is the error appears:
i write a callback function like that :
const addFile= async(Name,filePath)=> {
const file=fs.readFileSync(filePath);
const fileAdded = await ipfs.add({path: Name, content: file},(err,res)=>{
if(err)
console.log(err);
const fileHash = fileAdded[0].hash;
return fileHash;});};
but the value of fileAdded and fileHash was undefined.
after i use this code from #Always Learning :
const addFile= async(Name,filePath)=> {
const file=fs.readFileSync(filePath);
const hashes = [];
const filesAdded = ipfs.add({path: Name, content: file});
for await (const result of filesAdded) {
hashes.push(result.hash);
console.log(result.hash);
console.log(result);
}
return hashes; // if you know it's just one for example
};
It gave me an information of a file, but hash does not work as it gave me undefined, I want extract just a hash like this "QmRndAYkvH3D2qhmYfaAZvWT6MDi4NiJPbzJor3EL87rrb"
Since ipfs.add() returns an async-iterable object, you need to use for async to go through it like this:
const addFile= async(Name,filePath)=> {
const file=fs.readFileSync(filePath);
const hashes = [];
const filesAdded = ipfs.add({path: Name, content: file});
for await (const result of filesAdded) {
if (result.hash) {
hashes.push(result.hash);
} else if (result.cid) {
hashes.push(result.cid.multihash); // guessing here - might be another part of the cid object
} else {
console.log("No hash found in",result);
}
}
return hashes[0]; // if you know it's just one for example
};
You have to change this:
const fileHash = fileAdded[0].hash;
into this:
const fileHash = fileAdded.hash;
(so remove [0]).
This worked for me: it has to do with the libraries.

Resources