I would like to know how I could send in my reply the return of my functions.
In this example I want to return in my response the error of my validator if I have one
Here is my SqlCompanyRepository.ts:
async create(company: CompanyCommand): Promise<CompanyEntity> {
const createCompany = await dataSource.getRepository(CompanyEntity).save(company)
await validate(company).then(errors => {
if (errors.length > 0) {
return errors;
}
});
return createCompany
}
And here is my index.ts:
app.post("/company", async (req, res) => {
const company = new CompanyCommand()
company.id = crypto.randomUUID()
company.name = req.body.name
company.email = req.body.email
company.password = req.body.password
const checkEmail = await companyRepository.findByEmail(company.email)
if (!!checkEmail) {
res.status(409).send("Email already exists.")
} else {
const companyResult = await companyRepository.create(company)
res.send(companyResult)
}
})
Replace return errors; with throw errors;, this causes the Promise<CompanyEntity> to be rejected with errors.
Then wrap the invocation in a try-catch-block to catch this rejection:
try {
const companyResult = await companyRepository.create(company)
res.send(companyResult)
} catch(errors) {
res.send(errors)
}
Basically, I get an error saying "Cannot set headers after they are sent to the client". i tried redoing everything.
this is the form code:
const loader = document.querySelector('.loader');
// selecionar inputs
const submitBtn = document.querySelector('.submit-btn');
const name = document.querySelector('#name');
const email = document.querySelector('#email');
const password = document.querySelector('#password');
const number = document.querySelector('#number');
const tac = document.querySelector('#terms-and-cond');
const notification = document.querySelector('#notifications');
submitBtn.addEventListener('click', () => {
if(name.value.length < 3){
showAlert('name must be 3 letters long');
} else if (!email.value.length){
showAlert('enter your email');
} else if (password.value.length < 8){
showAlert('password should be 8 letters long');
} else if (!number.value.length){
showAlert('enter your phone number');
} else if (!Number(number.value) || number.value.length < 10){
showAlert('invalid number, please enter valid one');
} else if (!tac.checked){
showAlert('You must agree to our terms and conditions');
} else{
// para dar submit
loader.style.display = 'block';
sendData('signup', {
name: name.value,
email: email.value,
password: password.value,
number: number.value,
tac: tac.checked,
notification: notification.checked,
seller: false
})
}
})
// mandar a função dos dados
const sendData = (path, data) => {
fetch(path, {
method: 'post',
headers: new Headers({'Content-Type': 'application/json'}),
body: JSON.stringify(data)
}).then((res) => res.json())
.then(response => {
processData(response);
})
}
const processData = (data) => {
loader.style.display = null;
if(data.alert){
showAlert(data.alert);
}
}
const showAlert = (msg) => {
let alertBox = document.querySelector('.alert-box');
let alertMsg = document.querySelector('.alert-msg');
alertMsg.innerHTML = msg;
alertBox.classList.add('show');
setTimeout(() => {
alertBox.classList.remove('show');
}, 3000);
}
again, and I still get the same error...
and this is the server code:
// importar os packages
const express = require('express')
const admin = require('firebase-admin');
const bcrypt = require('bcrypt');
const path = require('path');
// setup da firebase - admin
let serviceAccount = require("./haza---pap-firebase-adminsdk-lrx0l-0da425a226.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
let db = admin.firestore();
// declarar um caminho estatico
let staticPath = path.join(__dirname, "public");
// inicializar o express.js
const app = express();
//middlewares
app.use(express.static(staticPath));
app.use(express.json());
// routes
// home route
app.get("/", (req, res) => {
res.sendFile(path.join(staticPath, "index.html"));
})
//route do signup
app.get('/signup', (req, res) =>{
res.sendFile(path.join(staticPath, "signup.html"));
})
app.post('/signup', (req, res) => {
let {name, email, password, number, tac, notification } = req.body;
// validações do form
if (name.length < 3){
return res.json({'alert': 'name must be 3 letters long'});
} else if (!email.length){
return res.json({'alert': 'enter your email'});
} else if (password.length < 8){
return res.json({'alert' :'password should be 8 letters long'});
} else if (!number.length){
return res.json({'alert' : 'enter your phone number'});
} else if (!Number(number) || number.length < 10){
return res.json({'alert' :'invalid number, please enter valid one'});
} else if (!tac){
return res.json({'alert' : 'You must agree to our terms and conditions'});
} else {
// guardar utilizadores na base de dados
db.collection('users').doc(email).get()
.then(user => {
if(user.exists){
return res.json({'alert': 'email already exists'});
} else{
// encriptar a password antes de guarda-la.
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(password, salt, (err, hash) => {
req.body.password = hash;
db.collection('users').doc(email).set(req.body)
.then(data => {
res.json({
name: req.body.name,
email: req.body.email,
seller: req.body.seller,
})
})
})
})
}
})
}
res.json('data recieved');
})
//route do 404
app.get('/404', (req, res) => {
res.sendFile(path.join(staticPath, "404.html"));
})
app.use((req, res) => {
res.redirect('/404');
})
app.listen(3000, () => {
console.log('listening on port 3000.......');
})
You are setting some data in response obj after send is being processed by node js.
Try using: res.end() after your all res.send.. events
Ref: https://www.geeksforgeeks.org/express-js-res-end-function/#:~:text=end()%20Function,-Last%20Updated%20%3A%2005&text=The%20res.,Node%20core%2C%20specifically%20the%20response.
You are sending response twice in /signup route.
Remove res.json('data recieved'); and it should work fine
That Error happens when you res. and then res. again to the client. Responding to the client several times is erroneous in node.
Check your route req,res cycles. Remember middleware .use() execute sequentially, and routes execute usually in between so...good luck
i've been struggling a lot with fastify-passport library, mainly because it seems that nobody uses it and there aren't any good examples or issues related to it
anyhow, i have some routes defined like this:
const adminRoutes = [
{
handler: (req,res) => {console.log(req.user) },
url: "/logout",
method: "GET"
}
]
this route is then registered by fastify like this (do note that there are more routes, however, this is just a code snippet)
adminRoutes.forEach((route, index) => {
fastify.route(route)
})
i am using passport local strategy to autenticate, it's configured like this
fastifyPassport.use('login', new passportLocal(async function (username, password, done) {
try {
let data = await dbQuery(`SELECT * FROM \`users\` WHERE username="${username}"`)
if (data[0].length > 0) {
data = data[0][0]
if (username === data.username && bCrypt.compareSync(password, data.hashedPassword)) {
return done(null, username)
} else return done(null, false)
}
} catch (error) {
console.log(error)
done(error);
}
}))
this seems to work, in all my tests, the strategy did what it had to do, when the right user and password is passed all the checks seems to pass and gets all the way down to return done(null, username)
this is my serializer and deserializer
fastifyPassport.registerUserSerializer(async (user, request) => {
return user
});
fastifyPassport.registerUserDeserializer(async (username, request) => {
let data = await dbQuery(`SELECT * FROM users WHERE username="${username}"`);
return data[0][0]
});
i've checked with both a debugger and console logs, they don't seem to ever get called
in fact when i go to /logout my console throws a null
also no session cookie get generated (uncertain of this, sometimes it seems to generate, other times it doesn't)
the complete code is quite long, however, it's probably necessary to see whats the issue
so here is it
this is the server
require('dotenv').config()
const fastify = require('fastify')({ logger: false })
const fastifyPassport = require('fastify-passport')
const fastifySecureSession = require('fastify-secure-session')
const passportLocal = require('passport-local').Strategy
const BannedEverywhere = ["DROP", "CREATE"]
const bCrypt = require('bcryptjs')
const fs = require('fs')
const path = require('path')
const port = process.env.PORT || 3000
const routes = require('./routes')
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: process.env.DB_PASSWD,
database: 'users',
port: 3306
});
console.log("Server Connected!")
function dbQuery(dataExpression) {
if (BannedEverywhere.some(i => dataExpression.includes(i))) {
return "invalid"
}
return pool.query(dataExpression)
}
fastify.register(require('fastify-cors'), {
origin: (origin, cb) => {
cb(null, true);
return
}
})
fastify.register(fastifySecureSession, { key: fs.readFileSync(path.join(__dirname, 'secret-key'))})
fastify.register(fastifyPassport.initialize())
fastify.register(fastifyPassport.secureSession())
fastifyPassport.registerUserSerializer(async (user, request) => {
return user
});
fastifyPassport.registerUserDeserializer(async (username, request) => {
let data = await dbQuery(`SELECT * FROM users WHERE username="${username}"`);
return data[0][0]
});
fastifyPassport.use('login', new passportLocal(async function (username, password, done) {
try {
let data = await dbQuery(`SELECT * FROM \`users\` WHERE username="${username}"`)
if (data[0].length > 0) {
data = data[0][0]
if (username === data.username && bCrypt.compareSync(password, data.hashedPassword)) {
console.log("got here")
return done(null, username)
} else return done(null, false)
}
} catch (error) {
console.log(error)
done(error);
}
}))
const postData = async (req, reply, err, user, info, status) => {
if (err !== null) { console.warn("ah habido un error: " + err) }
else if (user) {
const params = req.body
const newData = {
universidad: params.universidad,
facultad: params.facultad,
nombreExamen: params.nombreExamen,
fechaExamen: params.fechaExamen,
convocatoriaEspecial: params.convocatoriaEspecial,
convocatoriaExtraordinaria: params.convocatoriaExtraordinaria,
curso: params.curso
}
const response = await dbQuery('INSERT INTO `examenes` VALUES("'
+ newData.universidad + '","' + newData.facultad + '","'
+ newData.nombreExamen + '","' + newData.fechaExamen + '",'
+ newData.convocatoriaEspecial + ',' + newData.convocatoriaExtraordinaria + ','
+ newData.curso + ")")
return reply.send({ status: 200, newData, response })
}
}
const deleteData = async (req, reply, err, user, info, status) => {
if (err !== null) { console.warn("ah habido un error: " + err) }
else if (user) {
const { universidad, facultad, nombreExamen, fechaExamen, curso } = req.body
const response = await dbQuery('DELETE FROM `examenes` WHERE universidad="' + universidad + '" and facultad="' + facultad + '" and nombreExamen="' + nombreExamen + '" and date(fechaExamen)="' + fechaExamen + '" and curso=' + curso)
return reply.send({ status: 200, response })
}
}
const logout = async (req, reply, err, user, info, status) => {
if (err !== null) { console.warn("ah habido un error: " + err) }
console.log(req)
console.log("--------------------------------")
console.log(user)
console.log("--------------------------------")
console.log(info)
console.log("--------------------------------")
console.log(status)
}
fastify.get(
"/login",
(req, reply) => {
return reply.sendFile('./login/index.html')
}
)
fastify.post(
"/login",
{preValidation: fastifyPassport.authenticate('login',(req, reply)=>{
reply.send({redirect: "/"})
})},
() => {}
)
const adminRoutes = [
{
handler: () => {},
preValidation: fastifyPassport.authenticate("login", deleteData),
url: '/api/deleteData',
method: 'POST'
},
{
handler: () => {},
preValidation: fastifyPassport.authenticate("login", postData),
url: '/api/postData',
method: 'POST'
},
{
handler: () => {},
preValidation: fastifyPassport.authenticate("login", (req, reply) => { return reply.sendFile('./entry/index.html') }),
url: '/entry',
method: 'GET'
},
{
handler: (req,res) => {console.log(req.user) },
url: "/logout",
method: "GET"
}
]
const start = async () => {
try {
await fastify.listen(port)
} catch (err) {
console.error(err)
process.exit(1)
}
}
fastify.register(require('fastify-static'), {
root: __dirname,
prefix: '/', // optional: default '/'
})
routes.forEach((route, index) => {
fastify.route(route)
})
adminRoutes.forEach((route, index) => {
fastify.route(route)
})
start()
before you comment, i know cors shouldn't be left like that to go in production, don't worry, i know
also logout function was just a test, to try solve this very issue
this is the code that calls the login post request
const HOST = location.origin;
const axiosApp = axios.create({
baseURL: HOST,
});
document
.querySelector("#submit")
.addEventListener("click", async function () {
let response = await axiosApp.post(`${HOST}/login`, {
username: document.querySelector("#username").value,
password: document.querySelector("#password").value,
});
console.log(response);
if(response.status == 200) {
document.location.href = response.data.redirect
}
});
unrelated, bannedEverywhere is just a rudimentary "security" check, i do plan to improve it, for now it's just a better than nothing, and, i do plan to change all the var + string + var chains with template strings
answering my own question:
when you add a callback like that in the preValidation
{preValidation: fastifyPassport.authenticate('login',(req, reply)=>{
reply.send({redirect: "/"})
})}
fastify-passport no longer handles serialization and deserialization on his own, that comes with... a lot more issues, changing the prevalidation to
{preValidation: fastifyPassport.authenticate('login'{successRedirect:"/"})
makes you have to handle 302 codes in the browser, which can be problematic to say the least
i have been facing this error of 401 unauthorized error when i tried to mount my isLoggedinMiddlware.js, and even when i can manage to print the token stored, it stil says its
authorised. Any advice or help would be appreciated! Have a nice day.
this is my isLoggedinMiddleware.js
const jwt = require("jsonwebtoken");
const JWT_SECRET = process.env.JWT_SECRET;
module.exports = (req, res, next) => {
const authHeader = req.headers.authorization;
if (authHeader === null || authHeader === undefined || !authHeader.startsWith("Bearer ")) {
res.status(401).send();
return;
}
const token = authHeader.replace("Bearer ", "");
jwt.verify(token, JWT_SECRET, { algorithms: ["HS256"] }, (error, decodedToken) => {
if (error) {
res.status(401).send();
return;
}
req.decodedToken = decodedToken;
next();
});
};
this is my post api
app.post("/listings/",isLoggedInMiddleware,(req,res)=>{
listings.insert(req.body,(error,result)=>{
if(error){
console.log(error)
console.log(req.body)
console.log(isLoggedInMiddleware)
res.status(500).send('Internal Server Error')
return;
}
console.log(result)
res.status(201).send({"Listing Id":result.insertId})
})
})
This is my front end
const baseUrl = "http://localhost:3000";
const loggedInUserID = parseInt(localStorage.getItem("loggedInUserID"));
const token = localStorage.getItem("token")
console.log(token)
if(token === null || isNaN(loggedInUserID)){
window.location.href = "/login/"
}else{
$('#logoff').click(function(){
event.preventDefault();
localStorage.removeItem('token')
localStorage.removeItem('loggedInUserID')
window.alert('Logging out now')
window.location.href = "/login/"
})
$(document).ready(function () {
$('#submitbtn').click((event) => {
const loggedInUserID = parseInt(localStorage.getItem("loggedInUserID"));
// middleware = {headers:{'Authorization':'Bearer '+token},data:{id: loggedInUserID}}
event.preventDefault();
const itemName = $("#itemName").val();
const itemDescription = $("#itemDescription").val();
const price = $('#price').val();
const image = $('#image').val();
const requestBody = {
itemName: itemName,
itemDescription: itemDescription,
price: price,
fk_poster_id: loggedInUserID,
imageUrl: image
}
console.log(requestBody);
axios.post(`${baseUrl}/listings/`,{headers:{'Authorization':'Bearer '+token},data:{id: loggedInUserID}}, requestBody)
.then((response) => {
window.alert("successfully Created")
})
.catch((error) => {
window.alert("Error")
console.log(requestBody)
})
})
})
}
i can managed to get the token i stored when i log in, however, it stills say 401 unauthorised.
I am currently getting a "ReferenceError: logger is not defined" error when I am running some tests. These errors did not occur while my endpoints were in my app.js. They only started occurring when I moved my endpoints into my router file.
My endpoints all work in postman and can retrieve the data but for some reason all my tests are failing. Is there something I am missing in my router file?
const express = require("express");
const uuid = require("uuid/v4");
const logger = require("../logger");
const { bookmarks } = require("../store");
const BookmarksService = require("../bookmarks-service");
const bookmarkRouter = express.Router();
const bodyParser = express.json();
bookmarkRouter
.route("/bookmarks")
.get((req, res, next) => {
const knexInstance = req.app.get("db");
BookmarksService.getAllBookmarks(knexInstance)
.then(bookmarks => {
res.json(bookmarks);
})
.catch(next);
})
.post(bodyParser, (req, res) => {
//implementation
for (const field of ["title", "url", "rating"]) {
if (!req.body[field]) {
logger.error(`${field} is required`);
return res.status(400).send(`${field} is required`);
}
}
const { title, url, rating, desc } = req.body;
if (!title) {
logger.error("Title is required");
return res.status(400).send("Invalid data");
}
if (!url) {
logger.error("Url is required");
return res.status(400).send("Invalid data");
}
if (!desc) {
logger.error("Desc is required");
return res.status(400).send("Invalid data");
}
const id = uuid();
const bookmark = {
id,
title,
url,
rating,
desc
};
bookmarks.push(bookmark);
logger.info(`Bookmark with bookmark ${id} created`);
res
.status(201)
.location(`http://localhost.8000/bookmark/${id}`)
.json(bookmark);
});
bookmarkRouter
.route("/bookmarks/:id")
.get((req, res, next) => {
//implementation
const { id } = req.params;
const bookmark = bookmarks.find(b => b.id == id);
const knexInstance = req.app.get("db");
BookmarksService.getById(knexInstance, id)
.then(bookmark => {
if (!bookmark) {
logger.error(`Bookmark with id ${id} not found`);
return res.status(404).send({
error: { message: `Bookmark doesn't exist` }
});
}
res.json(bookmark);
})
.catch(next);
})
.delete((req, res) => {
//implementation
const { id } = req.params;
const bookmarkIndex = bookmarks.findIndex(li => li.id == id);
if (bookmarkIndex === -1) {
logger.error(`Bookmark with id ${id} not found.`);
return res.status(400).send("Not found");
}
bookmarks.splice(bookmarkIndex, 1);
logger.info(`Bookmark with id ${id} deleted`);
res.status(204).end();
});
module.exports = bookmarkRouter;