not able to get json response from nestjs route handler - nestjs

Why I am not getting the desired output as i given in res variable for returning from this route
#Get('/signout')
signOut(#Session() session: any) {
session.userId = null;
let res = JSON.parse(
JSON.stringify({
status: 'success',
}),
);
console.log( "--> ", res);
if (!session.userId) {
return res;
}
}
i am getting empty json object as response
{}
i tried printing out my res var it outputs fine.

To help debug your code have you tried just returning the response without any logic ?
#Get('/signout')
signOut(#Session() session: any) {
const res = {
status: 'success',
}
console.log( "--> ", JSON.stringify(res));
return res;
}
and then try
#Get('/signout')
signOut(#Session() session: any) {
session.userId = null;
const res = {
status: 'success',
};
console.log( "--> ", JSON.stringify(res));
if (!session.userId) {
return res;
} else {
throw new HttpException('Error', 500);
}
}

json response can be generated with two ways in NestJs, either use response object of express Response, or just add a header on the top of route handler method
Solution with applying header;
#Get('/')
#Header('Content-type', 'application/json')
handleGet(){
return JSON.stringify({ status : "success"})
}
Solution with using response imported from Express.
#Get('/')
#Header('Content-type', 'application/json')
handleGet(#Response() res : Response){
return res.json({ status : "success"});
}
These are the two possible ways that i found to return JSON response from a route handler method. further if all your responses need to be JSON, you may create an interceptor to alter your response before it is sent

Related

axios retry request but data-object isn't sent again

I have a react native app and a nodejs backend. I'm using refresh and access tokens for authentication. My RN code looks like this (simplified):
const onRequest = (config) => {
console.log('data before request', config.data);
config.headers = {
'Authorization': `Bearer ${accessToken.current}`,
'phosphor-device-id': `${deviceId}`,
'Accept': 'application/json',
};
return config;
};
const onRequestError = (error) => {
Promise.reject(error);
};
const onResponse = (response) => {
return response;
};
const onResponseError = async (error) => {
if (error.response.status === 401 && !oConfig._retry) {
oConfig._retry = true;
return refreshAccessToken().then((token) => {
accessToken.current = token;
apiCall.defaults.headers['Authorization'] = `Bearer ${token}`;
oConfig.headers['Authorization'] = `Bearer ${token}`;
return apiCall.request(oConfig);
})
.catch((error) => {
accessToken.current = null;
setAuth(false);
Promise.reject(error);
});
} else {
return Promise.reject(error);
}
}
apiCall.interceptors.request.use(onRequest, onRequestError);
apiCall.interceptors.response.use(onResponse, onResponseError);
In my nodejs code, I have middleware to check for incoming requests. It looks like this:
app.use((req, res, next) => {
console.log(`${req.method}: ${req.url}`);
if (Object.keys(req.query).length > 0) {
console.log('query params', req.query);
}
if (Object.keys(req.body).length > 0) {
console.log('body params', req.body);
}
next();
});
When the user submits an item with an expired access token, the response is "catched" by the axios response interceptor, and a new access token is generated and send back to the user. This works. Also, with return apiCall.request(oConfig);, the original request is retried. This does not work.
The first time , I get some logs about the request in my server console about the received req.body (thanks to the middleware). In my react native console, I see this body-object also (thanks to console.log('date before request', config.data); So when the request is retried, the full original body/data-object is send again to the server. But the second time, the req.body-object on the server (or what the server receives) is empty. I don't get any output in my node.js-middleware about the req.body-object, and my controller fails because it needs this content.
This only happens with POST requests (and req.body). When a "refresh-access-token" happens with a GET-request, the req.query-object is still complete in the second try.
What can possibly be wrong with this?
Edit: ofc I'm using express.json()
Try using error.config instead of oConfig
const onResponseError = async (error) => {
if (error.response.status === 401 && ! error.config._retry) {
error.config._retry = true;
return refreshAccessToken().then((token) => {
accessToken.current = token;
apiCall.defaults.headers['Authorization'] = `Bearer ${token}`;
error.config.headers['Authorization'] = `Bearer ${token}`;
return apiCall.request(error.config);
})
.catch((error) => {
accessToken.current = null;
setAuth(false);
Promise.reject(error);
});
} else {
return Promise.reject(error);
}
}

Catch Error response not returning as HttpErrorResponse Object

I am trying to catch the exception in the angular service method with the catchError.
Here, in the handleError method, I am trying to cast the error response of HttpErrorResponse but the response is always returning string and in this case it is returning the string Bad Request instead of the HttpErrorResponse object.
The actual error object returning from the node.js service method is of Type Result.
create(data) {
return this.httpClient.post<Result>(this.url, JSON.stringify(data), this.httpOptions)
.pipe(catchError(e => this.handleError(e)))
}
handleError(error: HttpErrorResponse) {
let errorMessage = '';
if (error.error instanceof ErrorEvent) {
// client-side error
errorMessage = `Error: ${error.error.message}`;
} else {
// server-side error
//errorMessage = `Error Code: ${error.failMessage}\nMessage: ${error.failMessage}`;
}
return throwError(error);
}
Result Object
export interface Result
{
error: any;
failMessage: string;
okMessage: string;
}
And the node.js service
function create (req, res, next)
{
service.create(req.body)
.then(result => {
var statusCode = 200; //default to ok
if (result)
{
result.okMessage = "Category Created";
}
else
{
statusCode = 400;
if (result.exception === "duplicate")
{
result.failMessage = `Category ${req.body.category} is already taken`;
}
}
res.status(statusCode).json(result)
})
.catch(err => next(err))
}
Angular http client module will return response body only, in case if you want all http response like headers status and body you have to use observe option, please check angular docs
this.httpOptions = { .....
observe: 'response'
}
Example from angular docs.
getConfigResponse(): Observable<HttpResponse<Config>> {
return this.http.get<Config>(
this.configUrl, { observe: 'response' });
}

Send API GET request with path variables in request-promise-native

I want to do make the same api call as made in this postman photo below :
postman
I have already tried the following code but it only returns some html not the desired response
async function vendor_info() {
const options = {
uri: 'http://**.**.**.**/vendor/:username/pj1527',
json: true,
method: 'GET'
};
let vendor_info = undefined;
await requestPromise(options)
.then((body) => {
// err_token = 0;
vendor_info = body[0];
console.log(body);
// console.log(body[0]);
})
.catch(err => {
vendor_info = undefined;
// err_token = 1;
// console.log(err);
});
return vendor_info;
}
EDIT
It's working now, actually the url should be 'http://.../vendor//pj1527' in the request.
If you are using async await then there is no need to use then and catch blocks, Try like this:
async function vendor_info() {
try {
const options = {
uri: 'http://**.**.**.**/vendor/:username/pj1527',
json: true,
method: 'GET'
};
const vendor_info = await requestPromise(options);
console.log('vendor_info: => ', vendor_info);
return vendor_info;
} catch (err) {
console.log('Error: => ', err);
return err;
}
}
Hope this helps :)

expressjs - response body not set

In the following NodeJS API, a PostgreSQL database is inserted with multiple rows and then a response body needs to be sent. Since there are multiple scenarios where there could be an error, I need to set-up response body with a message code that helps identify a possible cause. Therefore, I am using a resp object that will hold a code key for a message code. This object will be sent in a HTTP response where the status is either 200 (success) or 500 (error).
However, I keep getting an empty response body. Is the variable scope ok?
router.post('/', function (req, res, next) {
rdbmsPool.connect((err, client, release) => {
if (err) {
var resp = {
'Request-Id' : req.get('X-Request-Id'),
'code' : 'code'
}
res.status(500)
res.send(resp)
} else {
var resp = {}
for (k in someArray) {
client.query(queryString, colValues, (err, result) => {
if (err) {
resp = {
'Request-Id' : req.get('X-Request-Id'),
'code' : 'code'
}
res.status(500)
} else {
resp = {
'Request-Id' : req.get('X-Request-Id'),
'code' : 'code'
}
res.status(200)
}
})
}
for (k in someOtherArray) {
client.query(queryString, colValues, (err, result) => {
if (err) {
resp = {
'Request-Id' : req.get('X-Request-Id'),
'code' : 'code'
}
res.status(500)
} else {
resp = {
'Request-Id' : req.get('X-Request-Id'),
'code' : 'code'
}
res.status(200)
}
})
}
release()
res.send(resp)
}
})
});
Try something like this
let array1 = [];
for(k in someArray){
array1.push(client.query(queryString, colValues));
}
let array2 = [];
for (k in someOtherArray) {
array2.push(client.query(queryString, colValues));
}
try{
const results1 = await Promise.all(array1);
const results2 = await Promise.all(array2);
// if it comes here queries are successful
}
catch(error){
//send 500 here. any query have failed
console.log(error);
}
What happens is your response is sent before queries are completed. Your query execution is asynchronous and res.send(resp) does not wait until queries are executed.
The variable resp is set inside callbacks therefore it is empty.
You can try using async-await for synchronized execution with promise wrapper for parrelel execution of queries that are run inside loop. Note async function.
This is how it can be done with node mysql2/promise. Asynchronous means that the callback function you provide in query() will be called after query is executed. and the code after query() will run not waiting until query function is completed.
router.get('/getDayTypes',async function (req, res, next) {
const API_NAME='getDayTypes get, ';
try{
const conn = await pool.getConnection();
// Do something with the connection
var promise1 = conn.execute(`
SELECT
ID_DAY_TYPES,
DAY_NAME
FROM
hrm_calendar_day_types
WHERE
IS_ACTIVE = '1'`);
const values = await Promise.all([promise1]);
conn.release();
return res.status(200).send({success:true, data:values[0][0]});
}
catch(err){
logger.error(API_NAME + 'error :' + err);
return res.status(500).send({success:false, message:'Query Error'});
}
});

Azure Functions, http request gets second last value back

I'm creating an Node.js API with TypeScript which I want to host in Azure Functions. It sends requests to another public API. I got it to work but it has a bug which I can't resolve.
I'm sending an http post request to my API with Postman. In the body of the request there is a JSON object with one property "id".
But I don't get the last value back as a response. I get the second last value as a response. Assume the first request with id "1" gets "good" as a response. The second request with the id "2" gets a "good" as a response, too. But it should get "bad" as a response. The third request with the id "3" gets as a "bad" as response but it should get "good". The fourth request with the id "4" gets "good" as a response but it should get "bad".
The problem just exsits in my API. When I send requests directly to the another API via Postman, I don't get this problem.
index.js
module.exports = function (context, req) {
if (req.body.checkID) {
api.validationStatus(req.body.checkID)
.then(function (resp) {
if (resp.validated) { // Number is correct
context.log('Result: good');
res = { body: "Result: good" }
}
else if (resp.name === "StatusCodeError") { // Number is not correct
context.log('Result: bad ' + resp.name);
res = { body: "Result: bad " + resp.name }
}
else if (resp.name === "RequestError") { // API is not reachable
context.log('Result, bad ' + resp.name);
res = { body: "Result, bad " + resp.name }
}
else { // Something else went wrong
context.log("Result, bad.");
res = { body: "Result: bad." }
}
});
}
else {
res = {
status: 400,
body: "Please pass an id"
};
}
context.done(null, res);};
api.js
myApi.prototype.validationStatus = function (id) {
// Request options
var options = {
method: 'get',
url: this.config.validationStatusLocationUrl.replace("{id}", id),
headers: { "Authorization": this.config.apiKey }
};
// Request with a promise
return reqpromise(options)
.then(function (res) {
return JSON.parse(res);
})
.catch(function (err) {
return err;
});
};
I got it. The solution is simple and I assume I know why it had this behavior.
The context.done(); needs to be executed in the .then-Section of the promise (in the if and the else section). The problem was that I was sending a response even when the current api request (api.validationStatus()) was not finished yet (async, round robin style) and so I got just the old value of the previous requests.
index.js
module.exports = function (context, req) {
if (req.body.checkID) {
api.validationStatus(req.body.checkID)
.then(function (resp) {
if (resp.validated) { // Number is correct
context.log('Result, good.');
context.res = { body: "Result, good." }
}
else if (resp.name === "StatusCodeError") { // Number is not correct
context.log('Result, bad: ' + resp.name);
context.res = { body: "Result, bad." + resp.name }
context.done();
}
else if (resp.name === "RequestError") { // API is not reachable
context.log('Result, bad: ' + resp.name);
context.res = { body: "Result, bad." + resp.name }
context.done();
}
else { // Something else went wrong
context.log("Result, bad.");
context.res = { body: "Result, bad." }
context.done();
}
context.done();
});
}
else {
context.res = {
status: 400,
body: "Please pass an id"
};
context.done();
}
};

Resources