Nest: Set response headers using the standard (recommended) way of dealing with the response of a controller action

Created on 12 Jan 2018  路  8Comments  路  Source: nestjs/nest

I'm submitting a...


[ ] Regression 
[ ] Bug report
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

When creating a resource, a restful api should return a 201 status code and a resource identifier (using location header) that points to the freshly created resource. We can set response status code via @HttpCode decorator. But what about location header? Can we set location header without using @Res()?

This is what I do right now:

@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() catDto: CatDto) : Observable<{}>{
    return this.catService.create(catDto)
               .map(() => Observable.empty())
               .catch(error => this.httpExceptionService.mapToHttpExceptionObservable(error));
}

When I start using @Res() the code turns into something like (express way):

@Post()
create(@Res() res, @Body() catDto: CatDto) {
    this.catService.create(catDto)
        .subscribe(cat => {
          res.set('Location', cat.id);
          res.status(HttpStatus.CREATED).send();
        }, error => {
          // create error response
    });
}

Expected behavior

I would like to do something like:

@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() catDto: CatDto) : Observable<{}>{
    return this.catService.create(catDto)
               .map(cat => {
                   // magically set location header here
                  return Observable.empty();
               })
               .catch(error => this.httpExceptionService.mapToHttpExceptionObservable(error));
}

What is the motivation / use case for changing the behavior?

I want to manipulate the response (i.p. the response headers) using standard (recommended) way and not express way.

Environment


Nest version: 4.5.6

For Tooling issues:

  • Node version: 7.9.0
  • Platform: Mac
question 馃檶

Most helpful comment

Hi @ArtworkAD,
Inject request instead of response. request has a res property that is as response in fact 馃檪

All 8 comments

Hi @ArtworkAD,
Inject request instead of response. request has a res property that is as response in fact 馃檪

:1st_place_medal: @kamilmysliwiec awesome, this totally solves my problem. Thank you!

@artjomzab @kamilmysliwiec I have been trying this and it is not working in v5.6.2

import { Injectable, NestInterceptor, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';

@Injectable()
export class MyInterceptor implements NestInterceptor {
  private readonly customHeader = 'my-custom-header';

  intercept(
    context: ExecutionContext,
    call$: Observable<any>,
  ): Observable<any> {
    const request = context.switchToHttp().getRequest();
    request.res.header[this.customHeader] = 'foo';
    return call$;
  }
}

results in

TypeError: Cannot read property 'header' of undefined
    at MyInterceptor.intercept (my.interceptor.ts:30:19)
    at interceptors.reduce (node_modules/@nestjs/core/interceptors/interceptors-consumer.js:22:95)

What's the proper way to add custom response headers from an interceptor?

Hi @ArtworkAD,
Inject request instead of response. request has a res property that is as response in fact 馃檪

So this is recommended way of appending data to response body?

@felangel

@artjomzab @kamilmysliwiec I have been trying this and it is not working in v5.6.2

import { Injectable, NestInterceptor, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';

@Injectable()
export class MyInterceptor implements NestInterceptor {
  private readonly customHeader = 'my-custom-header';

  intercept(
    context: ExecutionContext,
    call$: Observable<any>,
  ): Observable<any> {
    const request = context.switchToHttp().getRequest();
    request.res.header[this.customHeader] = 'foo';
    return call$;
  }
}

results in

TypeError: Cannot read property 'header' of undefined
    at MyInterceptor.intercept (my.interceptor.ts:30:19)
    at interceptors.reduce (node_modules/@nestjs/core/interceptors/interceptors-consumer.js:22:95)

What's the proper way to add custom response headers from an interceptor?

What I'm doing is the same, but inside call$.pipe(map()), like the following.

@Injectable()
export class MyInterceptor implements NestInterceptor {
  private readonly customHeader = 'my-custom-header';

  intercept(
    context: ExecutionContext,
    call$: Observable<any>,
  ): Observable<any> {
    call$.pipe(map(data => {
        const request = context.switchToHttp().getRequest();
        request.res.header[this.customHeader] = 'foo';
        return data;
    }));
  }
}

However, this now fails downstream with Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.

UPDATE: @felangel Your case is solved if you use request.res.set(this.customHeader, 'foo'). However, I'm not sure how to edit response header as observed after execution, before returning. So we can, for instance, replace something in it.

Just use .getResponse() instead of .getRequest().

Just use .getResponse() instead of .getRequest().

@kamilmysliwiec Does this actually work?

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

2233322 picture 2233322  路  3Comments

anyx picture anyx  路  3Comments

yanshuf0 picture yanshuf0  路  3Comments

mishelashala picture mishelashala  路  3Comments

tronginc picture tronginc  路  3Comments