Is possible to send HTTP code in service? - nestjs

I would like to know if it was possible to return a status from a service?
Indeed in my service I have my code which allows to register but I would like to return an error if for example an account is already existing with the mail.
I tried with throw new HttpException() but it does not change anything
Here is my current code:
Controller:
#Post('/signup')
async signup(#Body() body): Promise<void> {
return await this.accountService.signup(body);
}
Service:
async signup(body: IAccount): Promise<void> {
const hashedPass: string = await bcrypt.hash(body.password, await bcrypt.genSalt(10));
const account: IAccount = {
'uuid': uuidv4(),
'username': body.username,
'password': hashedPass
};
const newAccount = new this.accountModel(account)
newAccount.save()
.then(function (response) {
console.log(response);
})
.catch(function (error) {
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
})
}
Thank advance

You don't ever return anything from the method. You should at least return the newAccount.save() so that the await can actually wait for the response from the catch if there is an error

Related

Why does this http request get stuck on pending with async/await?

So i'm getting some data from an external API for my web-app without any issues. However, these requests takes a bit too long so i'd like to cache this data once retrieved with the help of REDIS. I've managed to successfully do these steps separately but i need to be able to call the external API if there is no existing data in the redis-client.
I tried the /players GET request in Postman and it gets stuck on 'Sending request..'
app.get('/players', async (req, res) => {
const players = await getOrSetCache('players', async () => {
return shl.players();
})
res.json(players);
})
Function to return a Promise. If there is no data, a callback is used to make the request to the external api and store that data in the redis-client
function getOrSetCache(key, callback) {
return new Promise((resolve, reject) => {
redisClient.get(key, async(error, data) => {
if (error) return reject(error)
if (data != null) return resolve(JSON.parse(data))
const freshData = await callback()
redisClient.setex(key, 3600, JSON.stringify(freshData))
resolve(freshData)
})
})
}
Callback code:
players() {
return this.connection.get('/teams').then(teams => {
const teamCodes = teams.map(team => team.team_code);
Promise.all(teamCodes.map(teamCode => this.playersOnTeam(teamCode)))
.then(teamData => {
const teamInfo = [].concat(...teamData);
const playerInfo = [].concat(...teamInfo.map(team => team.players.map(player => ({
player_id: player.player_id,
first_name: player.first_name,
last_name: player.last_name,
default_jersey: player.default_jersey,
position: player.position,
}))));
return playerInfo;
}
);
});
}
Grateful for any tip of what the issue might be or if someone can spot errors in this implementation!

Cloud Function finished with status: 'timeout' while adding data to Firestore

Here's the code,
exports.onEmailRecieved = functions.database
.ref("/emails/recieved/{id}/")
.onCreate(async (snapshot, context) => {
const email = snapshot.val();
const id = context.params.id;
const trimmedEmailBody = String(email.body).replace("\n", "").trim();
if (trimmedEmailBody === cmd) {
const queueRef = fs.collection("requests").doc("all").collection("queue");
await fs
.runTransaction(async (t) => {
const doc = await t.get(queueRef);
const size = doc.size;
console.log(`Size: ${size}`);
console.log("Adding to queue.");
await queueRef
.add({
email: email.email,
subject: email.subject,
body: email.body,
})
.then(() => {
console.log("Successfully added to queue.");
})
.catch((err) => {
console.log(err);
})
.finally(() => {
console.log("It's finally over.");
});
return console.log("Worked?");
})
.then(() => {
return console.log("Complete");
})
.catch((err) => {
return console.log(err);
});
return console.log("Worked I guess.");
} else {
return console.log("Not equal.");
}
});
Don't mind the bunch of useless console.logs. Added em to debug the error.
That first console.log gets called and then nothing, no then, catch or finally functions get triggered and I get a function finished with status: 'timeout' message in the logs.
What I'm doing wrong?
The add() method returns a promise which then when you await a promise, the function is paused in a non-blocking way until the promise settles. It will wait for the transaction to be finished before resolving the creation of the document which results in timeout of the cloud function which by default is 1min. By removing the await on the add method you're instead executing the function. See code below:
messageRef
.add({
email: "email",
subject: "subj",
body: "body",
})
.then(() => {
console.log("Successfully added to queue.");
})
.catch((err) => {
console.log(err);
})
.finally(() => {
console.log("It's finally over.");
});
This will now return something like this:
Size: 1
Adding to queue.
test
Successfully added to queue.
It's finally over.
For more relevant information, you may check this documentations:
Sync, async, and promises
CollectionReference
How to use promises

how to wait for a result in rxjs for a lambda function

I am trying to write an async lambda function which is calling a function for sign up a user in cognito.
my problem is that in my lambda function, it is not waiting for the result and finish the execution. would you mind check what is my issue? I am new to rxjs. please help me.
mylambda function
exports.handler = async (event, context) => {
//poolData and params will fetch from event
let source = await signup(poolData, params);
console.log(source);
});
my signup function
function signup(poolData, body) {
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
const { username, password, attributes } = body;
const attributesList = [];
if (Array.isArray(attributes)) {
attributesList.push(
...attributes.map(item => new AmazonCognitoIdentity.CognitoUserAttribute(item))
);
}
let source = Observable.create(observer => {
let output = (err, res) => {
if (err)
{
observer.error(err);
}
else
{
const cognitoUser = res.user;
const data = {
username: cognitoUser.getUsername(),
};
observer.next(data);
}
observer.complete();
}
userPool.signUp(username, password, attributesList, null, output);
});
let respond;
let subscriber = {
next(value) {
console.log('Subscriber - next: ', value);
respond = {
'statusCode': 200,
'body': JSON.stringify({
"username": value.username,
})
}
}, error(err) {
console.log('Subscriber - err: ', err);
respond = err;
},
complete() {
console.log('Subscriber - complete');
return response;
}
};
source.subscribe(subscriber);
}
module.exports = signup;
This behavior is totally normal.
So first thing first, an observable is not a promise which means you are not able to await a response with the await keyword, also I don't see anything to be returned from the signup function, which will probably lead to undefined to be logged anyways.
So how to fix that, one way to fix this issue is to use toPromise() which will turn your observable into a promise which then can be awaited wherever needed.
The other way (which is the rxjs way) will be to return from the signup function the observable and inside your handler function to subscribe for the response.
let subscriber = {
next(value) {
console.log('Subscriber - next: ', value);
respond = {
'statusCode': 200,
'body': JSON.stringify({
"username": value.username,
})
}
}, error(err) {
console.log('Subscriber - err: ', err);
respond = err;
},
complete() {
console.log('Subscriber - complete');
return response;
}
};
exports.handler = (event, context) => {
//poolData and params will fetch from event
signup(poolData, params).subscribe(subscriber);
})

How i can return the token after the user register complete?

I'm making a api to register users and i like to return in the json response the user and the jwt token.
Actually this is my function:
initializeCreate( {request} ){
const data = request.only(["username", "password", "permission", "status"])
return new Promise(function(resolve, reject) {
user.create(data, function(err, resp, body) {
if (err) {
reject(err);
} else {
resolve(JSON.parse(body))
}
})
})
}
createUser({ auth }){
var initializePromise = initializeCreate();
initializePromise.then(function(result) {
const token = await auth.attempt(result.username, result.password)
return token
}, function(err) {
console.log(err);
})}
I suppose that i have to wait the event User.create() finish to make the auth.attempt, so i create this promise, but this is the better way to do this? There's a way that i make this in only 1 function?
Actually i'm receiving this error:
Unexpected token const token = await auth.attempt(result.username,
result.password)
You can use .generate(user) - documentation
const user = await User.find(1)
const token = await auth.generate(user)
or .attempt(uid, password) - documentation
const token = await auth.attempt(uid, password)
I suppose that i have to wait the event User.create() finish to make
the auth.attempt, so i create this promise, but this is the better way
to do this?
Yes. You need to use await. like :
await user.create(...)
(And now you can put everything in a function)
You can use try/catch :
async login({ auth, response, request }) {
const data = request.only(['email', 'password'])
try {
await auth.check()
return response.status(200).send({ message: 'You are already logged!' })
} catch (error) {
try {
return await auth.attempt(data.email, data.password)
} catch (error) {
return response.status(401).send({ message: error.message })
}
}
}
Sample code for a personal project

why my async await is not working properly

i am working on api with express js, in my api call i called 2 functions, first is login() and other function is get_organizations(), but get_organization() called without complete of login() function, i have used async await but it is not working properly, can anyone please help me to resolve this issue ? I have added my whole code here ,
router.get('/', async (req, res) => {
let token = await login();
await get_organizations(token);
});
const get_organizations = async function (api_token) {
try {
console.log('Get List Of Organizations');
console.log('Verifying token');
let verify_token_data = await jwt.verify(api_token, config['token-secret']);
console.log(verify_token_data);
return false;
} catch (error) {
console.log(error);
}
}
const login = async function () {
try {
console.log('Login process started');
const newToken = await jwt.sign({login:'login'},config['token-secret'],{ expiresIn: config['token-expires']});
let username = 'root_admin'
let password = 'Admin123';
let token = String(cryptojs.lib.WordArray.random(20));
console.log("token : "+token);
await connection.query('SELECT * FROM users where username = ? ',[username], async function(err, rows) {
if (err) {
console.log("Looged out failed");
} else {
const user = rows[0];
console.log("psdsdsd");
if(bcrypt.compareSync(password,user.passwordHash)) {
await connection.query('SELECT * FROM organizations where id = ? ',[user.organizationId], async function(err, org_data) {
if (err) {
console.log("Looged out failed");
} else {
console.log("sdsd");
//console.log(org_data);
if(typeof org_data.name!='undefined') {
organization = org_data.name;
} else {
organization = 'VeriCurious';
}
//console.log(organization);
// create a token
const token = await jwt.sign({ id: user.id, username: user.username, organizationId: user.organizationId, organization: organization}, config['token-secret'], {
expiresIn: config['token-expires'] // expires in 30 minutes
});
console.log("Successfull loggedin");
console.log("New generated token : "+token);
return token;
}
});
}
}
});
} catch (error) {
console.log(error);
}
}
When you use await when invoking a function, you're basically waiting for a promise inside that function to resolve. The invoked function is intended to return that promise.
In your code, the login function does invoke connection.query, but there isn't any promise that waits for the query to resolve.
In order to get await to really wait for connection.query, you need to return a Promise which resolves whenever the user finally logs in - i.e. you have the token:
const login = async function () {
try {
console.log('Login process started');
const newToken = await jwt.sign({login:'login'},config['token-secret'],{ expiresIn: config['token-expires']});
let username = 'root_admin'
let password = 'Admin123';
let token = String(cryptojs.lib.WordArray.random(20));
console.log("token : "+token);
return new Promise(function(resolve, reject){
connection.query('SELECT * FROM users where username = ? ',[username], async function(err, rows) { // await won't do anything here,
// you should only use await with functions that return promises.
if (err) {
console.log("Looged out failed");
throw new Error(err);
} else {
const user = rows[0];
console.log("psdsdsd");
if(bcrypt.compareSync(password,user.passwordHash)) {
await connection.query('SELECT * FROM organizations where id = ? ',[user.organizationId], async function(err, org_data) {
if (err) {
console.log("Looged out failed");
throw new Error(err);
} else {
console.log("sdsd");
//console.log(org_data);
if(typeof org_data.name!='undefined') {
organization = org_data.name;
} else {
organization = 'VeriCurious';
}
//console.log(organization);
// create a token
const token = await jwt.sign({ id: user.id, username: user.username, organizationId: user.organizationId, organization: organization}, config['token-secret'], {
expiresIn: config['token-expires'] // expires in 30 minutes
});
console.log("Successfull loggedin");
console.log("New generated token : "+token);
resolve(token); // this signals the Promise to resolve.
// return token;
}
});
}
}
});
});
} catch (error) {
console.log(error);
}
}
Some things to note:
Await is intended to work with promises. Asynchronous functions in javascript, either accept a callback or return a promise. connection.query takes a callback, so await is useless there.
Chances are that the module your using to talk to your database -mongoose?- has a promisified API. Check it out, because if you're willing to use async/await it is better to work directly with Promises rather than wrapping code in a new Promise.
For instance, if connection.query returned a Promise, you could do something like:
const login = async function () {
// skipped a lot of code and logic since this is an example
const rows = await connection.query('SELECT * FROM users where username = ? ',[username]);
const user = rows[0];
const org_data = await connection.query('SELECT * FROM organizations where id = ? ',[user.organizationId]);
const organization = org_data.name;
return await jwt.sign({ id: user.id, username: user.username, organizationId: user.organizationId, organization: organization}, config['token-secret'], {
expiresIn: config['token-expires'] // expires in 30 minutes
});
}
And handling errors is really simple.
When you get an error un a callback inside an async function, and you're returning a new Promise -like in my example- I don't really know if is better to reject or to throw the error. I think both will do the same but I'm not sure.

Resources