英文:
How to push data after response has been intercepted using nest.js interceptors?
问题
我很抱歉,但是你提供的内容已经是代码,因此我将不提供翻译。如果你有其他问题或需要关于这段代码的解释或帮助,请随时提出。
英文:
I am sorry if my request sounds easy but I am very new to nestJs.
The goal of my code I have a problem with is:
- I enter a physical address through a swagger api.
 - I geolocate this address.
 - I want to save both the address and the geolocation result.
 
For this,
I have 2 observables that get data through a nestjs interceptor (before saving to database) and would like to push this data into my database. I am using mongoose=>mongoDB.
The points.interceptor.ts code is:
export class PointsInterceptor implements NestInterceptor {
  async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
    var monaddress = context.switchToHttp().getRequest().body
    const geocodeResult = from(geocoder.geocode(monaddress));
    const geoCoder = await lastValueFrom(geocodeResult);
    return next.handle().pipe(
 //     tap(value => console.log(value)),
      map(value => {
        // Returning an object from both next.handle() and geoPremiseToObservable
        return {
          ...value,
          geoCoder: geoCoder
        }
      })
      )
  }
}
What I can see through VSCode debugger is that data is here when excecuting next.handle():

The points.schema.ts is:
export const PointSchema = new mongoose.Schema({
  address: String,
  geocoded: Object
});
The create-point.dto.ts is:
export class CreatePointDto {
    readonly address: string;
    readonly geocoded: Object;
The point.service.ts is
@Injectable()
export class PointsService {
  constructor(
    @Inject('POINT_MODEL')
    private PointModel: Model<Point>,
  ) {}
  async create(createPointDto: CreatePointDto): Promise<Point> {
    const createdPoint = new this.PointModel(createPointDto);
    return createdPoint.save();
  }
  async findAll(): Promise<Point[]> {
    return this.PointModel.find().exec();
  }
}
    }
The point.controller.ts is :
export class PointsController {
  constructor(private readonly pointsService: PointsService) {}
  @Post()
  @UseInterceptors(PointsInterceptor)
  create(@Body() createPointDto: CreatePointDto) {
     return this.pointsService.create(createPointDto);
  }
  @Get()
  findAll() {
    return this.pointsService.findAll();
  }
}
Thank you in advance for every help.
答案1
得分: 1
这应该是一个相对简单的任务,但你必须理解拦截器的工作原理。
在拦截器内部,无论你在 return 之前做什么都将在请求进入服务/控制器之前完成,而无论你在 return 之后做什么都将在服务/控制器的生命周期结束后完成。
让我们稍微修改你的拦截器以完成你的工作:
const request = context.switchToHttp().getRequest();
if(request.body) {
  // 我不知道你在控制器中希望如何传递地址的信息,我假设你将其作为字符串传递
  const monaddress = request.body;
  const geocodeResult = from(geocoder.geocode(monaddress));
  const geocoded = await lastValueFrom(geocodeResult);
  // 与你的 create-point.dto 匹配
  request.body = {
    address: monaddress,
    geocoded: geocoded
  }
}
这将修改你的请求体,使其包含解码数据的 geocoded 字段,并可在服务中使用。
英文:
This should be relatively simple task, but you have to understand how interceptor works.
Inside interceptor, whatever you do before return will be done before it goes to the service/controller and whatever you do after return will be done after the lifespan of the service/controller.
Lets change your interceptor a bit to do your work
const request = context.switchToHttp().getRequest();
if(request.body) {
  // I dont have  information how you are expecting the address in the controller, Im assuming you are passing as string
  const monaddress = request.body;
  const geocodeResult = from(geocoder.geocode(monaddress));
  const geocoded = await lastValueFrom(geocodeResult);
  // matching with your create-point.dto
  request.body = {
    address: monaddress
    geocoded: geocoded
  }
}
so this will modify your request body to have the geocoded field with the decoded data and will be available in the service itself
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论