Mapping an Angular HTTP Response properly

2.4k Views Asked by At

I am writing a simple Angular application that calls to an external API for data. One of these API calls returns data in such a way:

{
    "data": {
        "items": [
            {
                // An Appointment object is here
            }, 
            {
               ...
            }
        ]
    }
}

I have an AppointmentService which I use to call the API using the Angular HTTP library:

getBookedAppointments(userID : number) : Observable<Appointment[]> {
    return this.http.get<Appointment[]>('/api/url/goes/here')
            .pipe(retry(2), catchError(this.handleError));
}

And finally, I am trying to get these Appointment objects into an Array:

this.AppointmentService.getBookedAppointments(id).subscribe((appts : Appointment[]) => { 
    // appts contains {"data" : {"data": {"items" : [...]}}}
})

The issue being the fact that the API returns the array nested within data.items. How can I properly map the response so that the array is not nested?

2

There are 2 best solutions below

1
Joshua McCarthy On

You can use the map() operator to return any object de-structuring from an API response. You should also have your HTTP return the correct type. Here's an example solution:

interface ApiResponse {
  data: {
    items: Appointment[];
  }
}

getBookedAppointments(userID : number) : Observable<Appointment[]> {
  return this.http.get<ApiResponse>('/api/url/goes/here')
  .pipe(
    map(({data}) => data.items)
    retry(2),
    catchError(this.handleError)
  );
}

Note: I'm using object de-structuring inside the map() operator. You could do map(response => response.data.items) as well, but de-structuring helps reduce the number of properties you need to traverse.

0
ari On

The easiest way is to create a model(class/interface) that replicates the content structure. For a data structure like this : {"data" : {"data": {"items" : [...]}}} create a class ( or an interface) like follows:

export class Response {
    constructor() { }
    public data: ResponseData = new ResponseData();
}
export class ResponseData {
    public data: Item = new Item();
}
export class Item {
    public items: Appointment[] = [];
}
export class Appointment {
    constructor() { }
}