Search code examples
typescriptaxiosnestjsdeserialization

Deserializing axios response data to a class instance


  1. I am hitting an external API using axios (NestJs app).
  2. I specify the response type (lets say ResponseDto)
  3. When I get the data from axios (response.data), it is a simple plain JS object. As a result I cannot use any functions I defined in the ResponseDto class. So I get error TypeError: response.data.isValid is not a function.

Response Class:

import { InfoDto } from './info.dto';
import { Type } from 'class-transformer';

export class ResponseDto {
  @Type(() => InfoDto)
  private infos: InfoDto[];

  isValid(): boolean {
    return this.infos.length > 0;
  }
}

Info DTO

export class InfoDto {
  private readonly message: string;

  isMessageEmpty(): boolean {
    return !this.message;
  }
}

Api Call

this.httpService.axiosRef
.post<ResponseDto>(apiUrl, request, {
  headers: headers,
})
.then((response) => response.data);

I expect response.data to be of type ResponseDto but it is an Object. What I get

Object {
         "infos": Array(1)[
           Object {
             "message": "message"
           }
         ]
       }

What I want

ResponseDto {
         "infos": Array(1)[
           InfoDto {
             "message": "message"
           }
         ]
       }

Solution

  • You'd need to use something like class-transformer to take the JSON object into a class instance, or manually do that yourself via instantiating a new class and assigning the properties.

    this.httpService.axiosRef
    .post<ResponseDto>(apiUrl, request, {
      headers: headers,
    })
    .then((response) => response.data)
    .then((data) => plainToInstance(ResponseDto, data))
    .then((instance) => {
      if (!instance.isValid) {
        throw new Error('Invalid data from third party API);
      }
      return instance;
    });
    

    These can also be combined to the same then, just wanted to separate them out for the purpose of example.