I am working on a personal project and I do not have much experience with nodeJS, the idea is to bring a JSON that has remotely taken some data and generate some statistics, I am doing some tests before starting fully in the project and I am having problems with the callback.
the server.js works correctly,
my module is the following:
const extjson = require('remote-json');
//---------------------API CONFIG--------------------------
//apikey
const apikey ="xxxxxxxxxxxxxxxxxxxxx";
function get_sum_id(sumname){
const urlsumbySumName = "https://la2.api.riotgames.com/lol/summoner/v3/summoners/by-name/" + sumname + "?api_key=" + apikey;
var id;
extjson(urlsumbySumName).get((err, res, body)=> {
id = body.id;
});
return id;
}
module.exports = {get_sum_id
};
and the routes.js is the following:
const riot = require('./rapi.js');
const express = require('express');
//---------------------------------------------------------
const router = express.Router();
//Jtask -- task remote json
//const Task = require('../models/Task'); // taskdb
router.get('/',async (req, res) => {
res.render('index');
});
router.post('/profile', (req,res)=>{
const sum = req.body.summoners;
console.log(riot.get_sum_id(sum));
res.render('profile',{sum});
});
module.exports = router;
I want to show that id by console and it returns undefined, the idea is to pass that value to the render below to have it available in an EJS document.
Your module make an asynchronous call to another server with remote-json. It means that the callback will be called only after the request to this other server. So, this line return id; is read before this line id = body.id;.
One way to fix that is to provide the callback from the place where you call your module function.
Based on your code you could do something like that :
// module.js
const extjson = require('remote-json');
const apikey ="xxxxxxxxxxxxxxxxxxxxx";
function get_sum_id (sumname, callback) {
const urlsumbySumName = "https://la2.api.riotgames.com/lol/summoner/v3/summoners/by-name/" + sumname + "?api_key=" + apikey;
extjson(urlsumbySumName).get(callback);
}
module.exports = { get_sum_id };
// app.js
const riot = require('./rapi.js');
const router = express.Router();
router.post('/profile', function(req, res, next) {
riot.get_sum_id(req.body.summoners, function (err, resp, body) {
console.log(body);
res.json(body); // Response here
});
});
module.exports = router;
Now, requests to your server will be in pending until your callback close it with res.json(body);.
Thank you very much I am working, now I understand much better how the asynchronous functions work. I leave here the complete solution to my problem in case someone needs it in the future:
//rapi.js
const extjson = require ('remote-json');
//---------------------API CONFIG--------------------------
//apikey
const apikey ="RGAPI-77f658f1-ff2b-40e7-a74c-47f7510c8dac";
//trayendo los datos desde riot
function get_sum_id(sumname, callback){
const urlsumbySumName = "https://la2.api.riotgames.com/lol/summoner/v3/summoners/by-name/" + sumname + "?api_key=" + apikey;
extjson(urlsumbySumName).get(callback)
}
module.exports = { get_sum_id };
//routesapp.js
const riot = require('./rapi.js');
const express = require('express');
//---------------------------------------------------------
const router = express.Router();
router.get('/',async (req, res) => {
res.render('index');
});
router.post('/profile', (req, res, next)=>{
const sum = req.body.summoners;
riot.get_sum_id(sum,function (err, resp, body){
console.log(body.id);
//responces....
res.render('profile',{sum, id: body.id})
});
});
module.exports = router;
TNX very much!
Related
I'm making a text hosting service and I want it to say "TextMessage Not found! You can create one in the name by clicking here" but I don't know how to do that.
I tried making a custom 404 error, and detecting if the file exists via the node fs module, that did not work out.
this is my code:
// Importing require packages/modules
const express = require("express");
const bodyParser = require("body-parser");
const fs = require("fs");
// Defining needed variables
const app = express();
const PORT = 3000;
// Express midleware to enable body-parser
app.use(bodyParser.urlencoded({ extended: false }));
// Express static handler
app.use(express.static("public"));
// POST API To create message/file
app.post("/api/message/submit", (req, res) => {
const file = req.body.messageText;
const fileID = req.body.messageID;
fs.writeFile(__dirname + "/messageFiles/" + fileID + ".txt",
file, (err) => {
if (err) res.send("ERROR! <br>" + err);
else res.send("Saved");
});
});
// GET API To read message/file
app.get("/message/:id", (req, res) => {
const msg = req.params.id;
if (fs.existsSync(__dirname + "/messageFile/" + msg + ".txt")) {
res.sendFile(__dirname + "/messageFiles/" + msg + ".txt");
} else {
res.send("Message does not exist");
}
});
// Running the server
app.listen(PORT, () => {
console.log("Running on port: " + PORT);
});
`
You may try async writing to a file by wrapping it with trycatch block. It seems you have a problem with path to the file.
I suggest you to have a helper functions to write to a file and read from a file:
const create = async (data, fileName) => {
try {
const text = await fs.writeFile(`./files/${fileName}.txt`, data);
console.log('File write successful!');
} catch (error) {
throw new Error('File write operation failed');
}
};
const read = async (fileName) => {
try {
const fileContent = await fs.readFile(`./files/${fileName}.txt`, {encoding: 'utf-8'});
return fileContent;
} catch (error) {
throw new Error('File read operation failed');
}
};
app.post("/api/message/submit", async (req, res) => {
const fileContent = req.body.messageText;
const fileID = req.body.messageID;
const message = await create(fileContent, fileID);
message ? res.send('Successful') : res.send('Failed');
});
app.get("/message/:id", async (req, res) => {
const msgID = req.params.id;
const message = await read(msgID);
res.send(message);
});
I hope it helps!
P.S.: Don't use too many comments. Your code should be self-documenting (readable)!
P.S.S: Added async keyword before (req, res).
So I'm doing a simple NodeJS app with MongoDB/Express/Mongoose. In my mongoose schema I have a field (pictureURL) with a default value, the problem is that if pictureURL is an empty string the default value does not get applied. To solve this I though about using a custom middleware when doing the POST request either when creating or updating the model.
But the issue I'm having is that from within the middleware req.body is undefined. It is fine when in the router.post method but not in the middleware. Here is the code I have.
middleware (pictureU.js)
const app = require('../app');
const bookPictureUrl = (res, req, next) => {
console.log({ body: req.body });
if (!req.body.pictureUrl)
req.body.pictureUrl = 'images/default';
next();
};
module.exports = { bookPictureUrl };
book.routes.js
const app = require('../app');
const router = require('express').Router();
const Book = require('../models/Book.model');
const { bookPictureUrl } = require('../middleware/pictureUrl');
router.post('/update/:id', bookPictureUrl, async (req, res, next) => {
try {
req.body.authors = req.body.authors.split(',');
const data = await Book.findByIdAndUpdate(req.params.id, req.body);
res.redirect('/books');
} catch (err) {
next(err);
}
});
Any help trying to fix this so that I can use req.body within the middleware would be greatly appreciate.
Thanks
You mixed up your argument order. req should come before res.
const bookPictureUrl = (req, res, next) => {
console.log({ body: req.body });
if (!req.body.pictureUrl)
req.body.pictureUrl = 'images/default';
next();
};
Before I call expressApp.use(express.static(path.join(__dirname, '/../frontend/dist'))); I need to modify the html-code. What I basically need to do is inserting meta tags in two middleware functions. I figured out how to do this. But with my solution I call a middleware-functions inside another one.
app.js
let frontend = await fs
.readFileSync(path.join(__dirname, '/../frontend/dist/index.html'))
.toString('utf8');
expressApp.use((req, res, next) => {
//...
frontend = frontend.replace(
'<meta device="ABC" />',
'<head><meta device="' + deviceId + '"/>'
);
next();
});
expressApp.use((req, res, next) => {
const language = req.get('language') || 'en_GB';
logger.info('language:' + language);
this._languageModule.setLanguage(language);
frontend = this._languageModule.insertSIDs(frontend);
logger.info(frontend);
expressApp.use(express.static(path.join(__dirname, '/../frontend/dist'))); // nested middleware function
next();
});
/** set up all the express routes **/
expressApp.get('/', (req, res) => {
res.send(frontend);
});
Edit
If I don't call expressApp.use(express.static(path.join(__dirname, '/../frontend/dist'))); nested - like this:
expressApp.use((req, res, next) => {
const language = req.get('language') || 'en_GB';
logger.info('language:' + language);
this._languageModule.setLanguage(language);
frontend = this._languageModule.insertSIDs(frontend);
logger.info(frontend);
next();
});
expressApp.use(express.static(path.join(__dirname, '/../frontend/dist')));
the HTML will not be served modified.
You probably should write your own middleware that handles the modification of the files. Here's an example not tested. But it's rough. It's based on the express.static function
const fs = require("fs");
var parseUrl = require('parseurl')
app.use((req, res, next) => {
var originalUrl = parseUrl.original(req)
var path = parseUrl(req).pathname
// make sure redirect occurs at mount
if (path === '/' && originalUrl.pathname.substr(-1) !== '/') {
path = ''
}
// We only answer to GET
if (req.method !== 'GET' && req.method !== 'HEAD') {
return next()
}
let path = path;
fs.exists(path, (exists) => {
if(!exists)
{
// file don't exists skip this middleware
return next();
}
fs.readFile(path, (err, data) => {
if (err)
{
// Can't send the file skip this middle ware
return next();
}
// Do whatever you need with the file here?
// ...
// Setup mime type of the file
res.setHeader("content-type", "text/html");
// send the client the modified html
res.send(data);
});
console.log(exists ? 'it\'s there' : 'no passwd!');
});
});
For the original source please take a look at this github page:
https://github.com/expressjs/serve-static/blob/master/index.js
I use pasport.js + Express.js and got error
TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
with this code
passport/local.js
var LocalStrategy = require("passport-local").Strategy;
var models = require("../../models");
module.exports = new LocalStrategy(
function(username,password,done){
models.User.findOne(
{
where:{username:username}
},function(err,user){
if(err){return done(err);}
if(!user){return done(null,false,{message:"no such user"});}
if(!user.validPassword(password)){return done(null,false,{message:"invalid password"});}
return done(null,user);
}
);
}
);
passport.js
var passport = require("passport");
var models = require("../models");
var local = require("./passport/local");
module.exports = () => {
passport.serializeUser((user,done) => {
done(null,user.id);
});
passport.deserializeUser((id,done) => {
models.User.findOne({
where:{id:id}
}).then(user => {
done(null,user);
}).catch(err => {
done(err,null);
});
});
console.log(typeof(local));
passport.use(local);
}
console.log(typeof(local)); return "object". but passport.use() need function?
How can i solve this?
Usually this error comes from a missing export in one of the files that declares your routes. Please double check these files.
Also I checked and the code above works as it is.
Like the title entails.
I'm trying to make an application that when i put in certain info, it creates a link using mongoose _id. and express's app.get what i don't get is that to be able to join that directory i have to reload the whole server, which for the users and my sake a i don't want to do.
var mongoose = require("mongoose");
var express = require("express");
var app = express();
var http = require("http").Server(app);
var io = require("socket.io")(http);
var router = express.Router();
app.get("/", function (req, res) {
var ip = req.connection.remoteAddress;
res.sendFile(__dirname + "/index.html");
});
mongoose.connect("mongodb://localhost:27017/NEW_DB1");
console.log("Connection to database has been established");
var collectedData = new mongoose.Schema({
ipAddress: String,
name: {
type: String,
unique: false
}
});
var collectionOfData = mongoose.model("dataType", collectedData);
io.on("connection", function (socket) {
socket.on("name", function (e) {
var ip = socket.request.socket.remoteAddress;
var dataBase = mongoose.connection;
var Maindata = new collectionOfData({
ipAddress: ip,
name: e
});
Maindata.save(function (err, Maindata) {
if (err) {
return console.error(err);
} else {
console.dir(Maindata);
}
});
});
});
app.get("/mix", function (req, res) {
collectionOfData.find(function (err, data) {
res.send(data);
});
});
collectionOfData.find(function (err, data) {
data.forEach(function (uniqueURL) {
app.get("/" + uniqueURL._id, function (req, res) {
res.send("<h1>Hello " + uniqueURL.ipAddress + "</h1><p>" + uniqueURL.name + "</p>");
});
});
});
http.listen(10203, function () {
console.log("Server is up");
});
So what i'm trying to do is make it so i don't have to reload the whole server, and i'm able to just join the created directory when it's done being loaded.
figured i should put a quick example:
localhost:10203/55c2b2f39e09aeed245f2996
is a link a user just created the long
55c2b2f39e09aeed245f2996
is the effect of the _id, but when the user try's to connect to that site it won't work until i reload the server and obviously i'd like to avoid that haha.
I have a index.html file, but all that has is a socket.emit that sends "name" to the server
app.get("/", function (req, res) {
var ip = req.connection.remoteAddress;
res.sendFile(__dirname + "/index.html");
});
app.get('/:uniqueURL', function(req, res){
var id = req.params.uniqueURL;
res.send("Your requested id : " + id);
})
Try to use this above.
You are creating fix get path inside collectionData.find. That is the problem. So each time you have to reload the server by restarting.