I had a controller that didn't send the response back.
#Controller('/foo')
export class FooController {
#Post()
public async getBar(#Body() body: DTO, #Res() res) {
const response = await this.doSomething(body);
return response;
}
}
I had to use the res.send method:
#Controller('/foo')
export class FooController {
#Post()
public async getBar(#Body() body: DTO, #Res() res) {
const response = await this.doSomething(body);
res.send(response);
}
}
The cause was the #Res() res parameter. If you delete it, the response will be sent correctly:
#Controller('/foo')
export class FooController {
#Post()
public async getBar(#Body() body: DTO) {
const response = await this.doSomething(body);
return response;
}
}
You have to use #Res({ passthrough: true }) if you want the response to be send using the Nest way.
If you want to send the response like on Express framework use #Res() and add code res.status(200).send()
https://docs.nestjs.com/controllers
WARNING Nest detects when the handler is using either #Res() or
#Next(), indicating you have chosen the library-specific option. If
both approaches are used at the same time, the Standard approach is
automatically disabled for this single route and will no longer work
as expected. To use both approaches at the same time (for example, by
injecting the response object to only set cookies/headers but still
leave the rest to the framework), you must set the passthrough option
to true in the #Res({ passthrough: true }) decorator.
Related
I'm quite new to NestJS, so if I overlook something obvious, please forgive me.
Now I'm implementing a simple logger which logs request and response.
In NestJS, you can put a middleware only before routing, so my middleware overwrite res.write and res.end so that response chunks will be pushed to an array in the middleware.
export class Logger implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const originalResWrite = res.write;
const originalResEnd = res.end;
const chunks = [];
res.write = (...chunk) => {
chunks.push(Buffer.from(chunk[0]));
originalResWrite.apply(res, chunk);
};
res.end = (...chunk) => {
if (chunk[0]) {
chunks.push(Buffer.from(chunk[0]));
}
const body = Buffer.concat(chunks).toString("utf8");
console.log({
requestBody: req.body,
responseBody: JSON.parse(body) || body || {},
});
originalResEnd.apply(res, chunk);
};
}
}
However, if this middleware is instantiated as a singleton and shared by all requests--like Django middleware--, chunks Array will receive chunks from several streams, and the log will be totally messed up.
So, the problem is, how comsumer.apply instantiate a midddleware.
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(Logger)
.forRoutes('*');
}
}
In NestJS, is a middleware instantiated as a singleton, or instantiated each time request comes?
If you would answer my question, I would appreciate it.
Yes, by default providers are singleton in Nestjs, however, you can define the scope for your middleware using the options in the Injectable decorator.
So you can add this before your middleware class definition
#Injectable({ scope: Scope.REQUEST })
Check out this link in the documentation and this answer on Stackoverflow.
I want to redirect to a website(in NestJs Application) but using the res() from express is not applicable for me
import { Response } from 'express';
#Get('qrmenu/business/:id')
public async ResponseToQRScan(#Param() params: IdValidator, #Res() res: Response,
#Query() qrQuery: QrScanQueryDto): Promise<any> {
console.log(qrQuery)
if (qrQuery.app !== true || !qrQuery.app) {
return res.redirect(`https://masovison.com/about/`)
}
let menu = await this.menuService.getMenuOfABusiness(params.id);
// console.log(menu)
res.send({ menu })
}
PS: The Redirect is a conditional situation so controller should either redirect to a website or send the response as per condition.
is there any other way that I can redirect to a website in NestJS application ?
You would either use the #Redirect() decorator or call res.redirect() directly as stated here. And also:
Returned values will override any arguments passed to the #Redirect() decorator. For example:
#Get('docs')
#Redirect('https://docs.nestjs.com', 302)
getDocs(#Query('version') version) {
if (version && version === '5') {
return { url: 'https://docs.nestjs.com/v5/' };
}
}
I am trying to query some data in my data. But when I send get request to my server, It's not returning anything. But when I console log my data is printed on the console. I handle all promises and other stuff. But the results are the same.
Controller method: -
#Get('order/:state')
async getOrderByStatus(
#Res() response: Response,
#Param('state') state: number,
): Promise<OrderService[]> {
try {
const orderStatus = await this.orderServiceService.getOrderByStatus(
state,
);
if (orderStatus) {
console.log(orderStatus);
return orderStatus;
}
} catch (error) {
console.log(error);
response.status(401).send(error);
}
}
Service method: -
async getOrderByStatus(state: number): Promise<OrderService[]> {
try {
const orderState = await this.orderModel.find({ orderStatus: state });
if (orderState) {
return orderState;
}
throw new HttpException('Order not found', HttpStatus.NOT_FOUND);
} catch (error) {
console.log(error);
throw error;
}
}
Client-side:- (Request data is still sending.Not returning data from my controller)
I really need your help... Thank you..❤️
When you add #Res() to the route handler, you are telling Nest that you want to use the library-specific approach and you'll handle sending the response on your own. If you don't need any underlying engine specific methods, I'd suggest not using #Res() in the route handler, and if you do need some method, but still want Nest to send the response you can end up using #Res({ passthrough: true }), just make sure that you don't end up calling res.send yourself.
For handling the error, you can catch the error and re-throw it as an HttpException, that way Nest's built-in exception filter will send the proper response code and message for you
How can I access pass #Res() into my graphql resolvers?
this doesn't work:
#Mutation(() => String)
login(#Args('loginInput') loginInput: LoginInput, #Res() res: Response) {
return this.authService.login(loginInput, res);
}
#Res() is for HTTP Requests. To access to res object you'd need to first make sure it is added to the context for graphql by using context: ({ req, res }) => ({ req, res }) in the GraphqlModule's options, and then you can use #Context() ctx to get the context and ctx.res to get the response object
When we use Axios we always have to get the data from response. Like this:
const response = await Axios.get('/url')
const data = response.data
There is a way to make Axios return the data already? Like this:
const data = await Axios.get('/url')
We never used anything besides the data from the response.
You can use ES6 Destructing like this:
const { data } = await Axios.get('/url');
So you won't have write another line of code.
add a response interceptors
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response.data; // do like this
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
what i normally do is create a js file called interceptors.js
import axios from 'axios';
export function registerInterceptors() {
axios.interceptors.response.use(
function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response.data;
},
function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
}
);
}
in ./src/index.js
import { registerInterceptors } from './path/to/interceptors';
registerInterceptors();//this will register the interceptors.
For a best practice don't use axios every where, just in case in the future if you want to migrate to a different http provider then you have to change everywhere it uses.
create a wrapper around axios and use that wrapper in your app
for ex:
create a js file called http.js
const execute = ({url, method, params, data}) => {
return axios({
url,
method,//GET or POST
data,
params,
});
}
const get = (url, params) => {
return execute({
url, method: 'GET', params
})
}
const post = (url, data) => {
return execute({
url, method: 'POST', data
})
}
export default {
get,
post,
};
and use it like
import http from './http';
....
http.get('url', {a:1, b:2})
so now you can customize all over the app, even changing the http provider is so simple.