简体   繁体   中英

Angular 4 proper way to cast http response

I've created a service in Angular 4 and I'm fetching data via REST/JSON (new to Angular) using this code:

Interface

export interface IItem {
    Id: number;
    Title: string;
}

Service

import { IItem } from './item';
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';

@Injectable()
export class ItemTest {

    constructor(private _http: HttpClient) {}

    getItems(): Observable<IItem[]> {
        return this._http.get<IItem[]>('url')
            .do(data => {
                console.log(data);
            })
    }
}

The http cast to IITem works fine if the response is in this format

[
    {
        "Id": 53,
        "Title": "Test Document 4.docx"
    },
    {
        "Id": 55,
        "Title": "Test Document 2.docx"
    }
]

But the actual response from the server looks like this and the cast doesn't work. What's the best way to cast the "results" portion of the response to an array of IItems?

{
    "d": {
        "results": [
            {
                "Id": 53,
                "Title": "Test Document 4.docx"
            },
            {
                "Id": 55,
                "Title": "Test Document 2.docx"
            }
        ]
    }
}

Youll want to use the map operator:

@Injectable()
export class ItemTest {

    constructor(private _http: HttpClient) {}

    getItems(): Observable<IItem[]> {
        return this._http.get('url').map((data) => data['d']['results'])              
            .do(data => {
                console.log(data);
            })
    }
}

The specific type for the get should describe the shape of the actual response JSON you expect to receive. Then the compiler can actually help you by telling you whether you're accessing and returning the right things. In your case:

getItems(): Observable<IItem[]> {
    return this._http.get<{ d: { results: IItem[] } }>('url')
        .map(response => response.d.results)
        .do(data => {
            console.log(data);
        }):
}

Note that none of this is casting the response data, just describing it.


As for your other suggestion:

.get<IItem[]>(...)
.map((data) => data['d']['results']) 

If you're going to assert the type of the response wrongly then make unsafe property accesses with a result the compiler can only assume is any , you might as well not be using types at all. Don't just ignore the compiler when it tells you you're accessing the wrong properties.

You'd probably want to run a few mapping utilities

http.get(url)
.map(response => response.json())
.map(response => response.d.results)
.map(results => results.map(item => return Object.create(IItem, item))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM