NestJS - send Body to Response - nestjs

#Post('signin')
async signIn(#Body() account) {
return this.appService.signIn(account);
}
******************************
{
"success": true,
"message": "use cache",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJ1c2VyMkB0ZXN0LmNvbSIsImlhdCI6MTYxMDY3NjkyNSwiZXhwIjoxNjEwNzEyOTI1fQ.Tx3a0brtWYD7GQUKYQAq_48biIZCFpqEQsds2-BrINc"
}
-----------------------------------
#Post('signin')
async signIn(#Body() account, #Res() res: Response) {
res.send({
result: this.appService.signIn(account)
})
}
******************************
{
"result": {}
}
I'm trying to send the result as Response.
But result is {} //undefined if i using res.json() or res.send()
Cookie-parser, app.use(cookieParser()) is already done.
How do i send Body using Response?

If your this.appService.login() is an async call, you need to await the response before using res.send(). Something like this should do
#Post('signin')
async signIn(#Body() account, #Res() res: Response) {
const result = await this.appService.signIn(account);
res.send({
result
});
}
Is there any reason you want to inject the #Res() instead of letting Nest handle it?

Related

Express 3 legged OAuth flow for twitter login, isn't storing session across requests

I am implementing the three-legged OAuth twitter-api-v2 flow. My first call from my frontend is to the route containing twitterCallback(). This uri is then generated, and the oauth_token_secret is taken and saved to session - I am using express-session.
public twitterCallback = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const client = this.createTwitterClient();
const { url :uri, oauth_token, oauth_token_secret } = await.client.generateAuthLink(CALLBACK_URL);
req.session = req.session || {} as any;
req.session.oauth_token_secret = oauth_token_secret;
req.session.oauth_token = oauth_token;
res.status(200).json({ uri });
} catch (error) {
next(error);
}
};
However the following call which has the user return, sees the oauth_token in the query, but the oauth_token_secret isn't displaying any value. I can see that the session id is different - I presume because the session cookie for the first request is set on the frontend app, and then on the 2nd request its origin is twitter instead.
public loginWithTwitter = async (req: RequestWithTwitter, res: Response, next: NextFunction): Promise<void> => {
try {
const client = new TwitterApi({
appKey: CONSUMER_KEY,
appSecret: CONSUMER_SECRET,
accessToken: req.query.oauth_token,
accessSecret: req.session.oauth_token_secret,
});
const login = await client.login(req.query.oauth_verifier)
.then(({ client: loggedClient, accessToken, accessSecret }) => {
console.log(loggedClient, accessSecret, accessToken);
})
.catch((e) => console.error(e));
res.status(200).json({ login, message: 'Logged in with twitter with ' });
} catch (error) {
next(error);
}
};
How do I ensure that I can safely keep the session value for oauth_token_secret across different requests, despite the point of request origin being different?
Any tips please - driving me mad because I know I am missing something obvious!
I have explored the idea of trying to set the session id to the frontend on the twitter side.

Axios is returning undefined

My API is returning proper data when I am requesting from Postman. Even API is getting properly called from React, I checked using console.log inside the controller, but I am always getting undefined response. I am not sure what the mistake is.
const submit = async (e: SyntheticEvent) => {
e.preventDefault();
const response = await axios
.get('certificates', {
params: { sponser },
})
.then((res) => {
console.log(response); //undefined
alert(res.status); //200
alert(res); //[object Object]
});
};
Could you please help me on the same.
You need to return res in the then to have access on response:
const response = await axios
.get('certificates', {
params: { sponser },
})
.then((res) => {
console.log(response); //undefined
alert(res.status); //200
alert(res); //[object Object]
// response is not defined here!
return res;
});
console.log(response);
Shorter way:
const response = await axios
.get('certificates', {
params: { sponser }
});
console.log(response);
It seems that OP is relatively new to js - I can recommend this intro to async js: https://javascript.info/async-await

React/Express - Axios get request help needed

Trying to make an API get request from front-end (React) to back-end (Express/MongoDB) using Axios. If I use Postman to make the request it works fine (you can enter a user ID in the request body and get back an array of objects containing that user ID, which is what I want), but doing it from a front-end built in React doesn't work, I just get an empty array returned. As far as I can tell my API call from the front-end is exactly the same as the one I'm making in Postman! Can anyone shed any light on this?
This is the code making the get request from the front end:
const getActivities = async (currentUser) => {
const config = {
crossdomain: true,
headers: {
"Content-Type": "application/json"
},
body: {
"user": `${currentUser[0].id}`,
}
}
try {
const res = await axios.get('http://localhost:5000/api/activities', config)
console.log(res)
dispatch({
type: GET_ACTIVITIES,
payload: res.data
})
} catch (error) {
console.log(error)
}
}
And this is the route on the back-end handling this particular request:
router.get('/', async (req, res) => {
try {
const activities = await Activities.find({ user: req.body.user }).sort({ date: -1 })
if (!activities) {
res.json({msg: "Nothing found. Go forth and exercise!" })
}
res.json(activities).send()
} catch (err) {
res.send(err.message)
}
})
Thanks in advance!
You cannot send a request body with GET method see API AXIOS only for request methods 'PUT', 'POST', 'DELETE , and 'PATCH'.
for example if you want to keep a GET method use params
// React
const config = {
crossdomain: true,
headers: {
"Content-Type": "application/json"
},
params: {
user: `${currentUser[0].id}`,
}
}
try {
const res = await axios.get('http://localhost:5000/api/activities',config)
console.log(res.data)
}catch(err){
...
}
// Express
router.get('/', async (req, res) => {
console.log(req.query.user)
}

express-validator extracting validation into separate file

I am trying to validate some input using express validator but i have a different setup than one in the documentation.
Im validating if the body.payload is not null
this.validator.document
public document = async (req: Request, res: Response, next: NextFunction) => {
check("payload").exists({ checkNull: true });
try {
validationResult(req).throw();
next();
} catch (err) {
res.status(422).json({ errors: err.mapped() });
}
}
this.controller.document
public document = async (req: Request, res: Response): Promise<any> => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
}
documentRoute
this.router.post("/:id/document",
this.jwtGuard,
this.validator.document,
this.controller.document);
im aware check is a middleware in itself, so how do i handle this inside my existing validator function that may have some other validation before it.
At the moment this does not work, even tho payload is set to null. It should catch the error and return a 422 response but it is not.
in validator.document:
public document = () => check("payload").exists({ checkNull: true });
in documentRoute:
this.router.post("/:id/document",
this.jwtGuard,
this.validator.document(), // notice the parentheses
this.controller.document);
Update: If you want to handle the errors in validator.document, you need to call check middleware before it when declaring the route:
this.router.post("/:id/document",
this.jwtGuard,
check("payload").exists({ checkNull: true }),
this.validator.document,
this.controller.document);
And in validator.document:
public document = async (req: Request, res: Response, next: NextFunction) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
}
Update 2: If you have multiple check operations and does not want to bloat your route definition, I suggest you use schema validation.

Logging Fastify response body

How can I log the response body in Fastify? The body doesn't seem to be exposed as part of the response object:
const fastify = require('fastify')({
logger: {
serializers: {
res: function (res) {
// No body in req afaik
return { }
}
}
}
})
Try this:
const fastify = require('fastify')({
logger: {
serializers: {
res: function (res) {
return {
statusCode: res.statusCode,
payload: res.payload,
}
},
}
}
})
fastify.addHook('onSend', function (_request, reply, payload, next) {
Object.assign(reply.res, { payload });
next();
})
If some of your payloads are objects and you want to get them in serialize before they are - well, serialized - you can add preSerialization hook as well:
fastify
.addHook('preSerialization', (_request, reply, payload, next) => {
Object.assign(reply.res, { payload });
next();
})
.addHook('onSend', (_request, reply, payload, next) => {
if (!reply.res.payload) Object.assign(reply.res, { payload });
next();
});
here you are a working example. I think that this kind of usage need to be used only for debugging because you are slowing down if you have many req/sec.
I have also added a JSON Schema validation as demo:
const fastify = require('fastify')({ logger: true })
fastify.register(async function (fastify, opts) {
fastify.addHook('onSend', function (request, reply, payload, next) {
console.log(payload);
next()
})
fastify.get('/', {
schema: {
response: {
'2xx': { properties: { this: { type: 'string' } } }
}
}
}, async function () {
return { this: 'is', a: 'json' }
})
})
fastify.listen(3000)
You will get:
curl http://localhost:3000/
{"this":"is"}

Resources