I have been following the tutorial of the heroes in angular, and then I wanted to apply it to my small test project to consolidate it. When I was using it with the built in http server and some mock items, it worked, but now I am not able to retrieve the items I want from another a Django REST API.
I can test that this is my API and works:
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"
},
]
}
Then I have my Item item.ts
export interface Item {
label: string;
name: string;
notes: string;
}
I have a component displaying those items 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);
}
And here I have the service where I am trying to do the changes
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}`);
}
}
It may be a little bit messy, as I removed irrelevant stuff, but the only point where I have been working since I switched to the real API is this method:
getItems(): Observable<Item[]> {
return this.http.get<Item[]>(this.itemsUrl).pipe(
map(res => res ),
tap(_ => this.log('fetched items')),
catchError(this.handleError<Item[]>('getItems', []))
);
}
I have been already more than one day in my free time trying to fix this but I am not able to find how can I access the key results from the JSON in order to map it to the Item. Most of the similar questions I find make use of a function .json() which I think I have understood is not used anymore in HttpClient. Then I have also tried in many forms something like res.results without success, I get an exception that that property does not exist.
The query is working, as If I change the tap line to:
tap(_ => console.log(_)),
I get the Object in an error.
Can someone give me some hint on what I am doing wrong?. I don't know where else to search I can't make it work from the tutorial, and the documentation from https://angular.io/api/common/http/HttpClient I think does also not cover this, and I think it should be quiet simple, but I have no idea how can I further debug.
http.getis not what you're expecting the API to return, which is why it's telling you there's no results property.type Envelope<T> = { count: number, next: string | null, previous: string | null, results: T[] }and use that, but the compiler can only help you if it has accurate information.