【发布时间】:2021-05-29 13:16:48
【问题描述】:
一直在关注angular大侠的教程,后来想把它应用到我的小测试项目中巩固一下。当我将它与内置的 http 服务器和一些模拟项目一起使用时,它可以工作,但现在我无法从另一个 Django REST API 检索我想要的项目。
我可以测试这是我的 API 并且有效:
curl -H 'Accept: application/json; indent=4' http://127.0.0.1:5000/inventory/items_viewset/ -L
{
"count": 13,
"next": "http://127.0.0.1:5000/inventory/items_viewset/?page=2",
"previous": null,
"results": [
{
"label": "00004",
"name": "Test2",
"notes": "222",
"owner": "admin",
"photo": null
},
{
"label": "0000007",
"name": "Test1",
"notes": null,
"photo": "http://127.0.0.1:5000/media/item_images/2021/02/19/IMG_20210207_134147.jpg"
},
]
}
然后我有我的物品item.ts
export interface Item {
label: string;
name: string;
notes: string;
}
我有一个显示这些项目的组件items.component.ts:
items: Item[];
constructor(private itemService: ItemService, private messageService: MessageService) { }
// constructor() { }
ngOnInit(): void {
this.getItems();
}
getItems(): void {
this.itemService.getItems()
.subscribe(items => this.items = items);
}
在这里我有我正在尝试进行更改的服务
import { Injectable } from '@angular/core';
import { Item } from './item';
import { ITEMS } from './mock-items';
import { Observable, of } from 'rxjs';
import { MessageService } from './message.service';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, tap, map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class ItemService {
constructor( private http: HttpClient, private messageService: MessageService) { }
private itemsUrl = 'http://127.0.0.1:5000/inventory/items_viewset'; // URL to web api
httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json', })
};
getItems(): Observable<Item[]> {
return this.http.get<Item[]>(this.itemsUrl).pipe(
map(res => res ),
tap(_ => this.log('fetched items')),
catchError(this.handleError<Item[]>('getItems', []))
);
}
/**
* Handle Http operation that failed.
* Let the app continue.
* @param operation - name of the operation that failed
* @param result - optional value to return as the observable result
*/
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead
// TODO: better job of transforming error for user consumption
this.log(`${operation} failed: ${error.message}`);
console.error(`${operation} failed: ${error.message}`);
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
/** Log a HeroService message with the MessageService */
private log(message: string) {
this.messageService.add(`ItemService: ${message}`);
}
}
这可能有点乱,因为我删除了不相关的东西,但自从我切换到真正的 API 以来,我一直在工作的唯一一点就是这个方法:
getItems(): Observable<Item[]> {
return this.http.get<Item[]>(this.itemsUrl).pipe(
map(res => res ),
tap(_ => this.log('fetched items')),
catchError(this.handleError<Item[]>('getItems', []))
);
}
我已经有超过一天的空闲时间尝试解决此问题,但我无法找到如何从 JSON 访问密钥 results 以将其映射到项目。我发现的大多数类似问题都使用了.json() 的函数,我认为我已经理解该函数在HttpClient 中不再使用。然后我还尝试了多种形式,例如res.results,但没有成功,我得到一个异常,该属性不存在。
查询正在运行,就像我将点击线更改为:
tap(_ => console.log(_)),
我得到一个错误的对象。
有人可以给我一些提示我做错了什么吗?我不知道在哪里可以搜索我无法从教程中使它工作,我认为https://angular.io/api/common/http/HttpClient 的文档也没有涵盖这一点,我认为它应该很简单,但我不知道如何我可以进一步调试吗?
【问题讨论】:
-
你骗了 HttpClient。您提供给
http.get的泛型类型不是您期望 API 返回的类型,这就是它告诉您没有 results 属性的原因。 -
你可以定义一个额外的类型,例如
type Envelope<T> = { count: number, next: string | null, previous: string | null, results: T[] }并使用它,但编译器只有在有准确信息的情况下才能帮助您。 -
谢谢@jonrsharpe。您能否举例说明如何将此概念应用于我的 getItems 函数?
标签: json angular typescript angular-httpclient