typescript - Angular - Hantera HTTP-svar med DTO


Jag verkar inte kunna hitta ett komplett exempel på hur man hanterar ett komplext Angular HTTP-svar. Jag använder Angular 16.

Backend-API:t jag försöker kommunicera med tillhandahåller ett DTO (Dataöverföringsobjekt) som detta:

{
  "data": {
    "name": "joe",
    "age": 40
  },
  "success": true,
  "message": "completed successfully"
}

I Angular förväntar jag mig att:

  1. Använd HttpClient för att hämta datan
  2. Ha ett if-uttryck för att kontrollera HTTP-statusen
  3. Om 200 OK - Gör någon form av kartläggning av JSON-data till en modell
  4. Annars returnera ett felmeddelande till frontenden
  5. Returnera ett observerbart

Mina egna försök har misslyckats, men här är vad jag har just nu:

Modeller/http_response.ts:

export interface HttpResponse {
    status: string;
    data: any;
    success: string;
    message: string;
}

Modeller/user.ts:

export interface User {
    name: string;
    age: number;
}

Tjänster/api.service.ts:

import { HttpClient } from '@angular/common/http';
import { HttpResponse } from '../models/http_response';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';


@Injectable({
    providedIn: 'root'
})

export class ApiService {
    constructor( private http: HttpClient ){ }

    getData(): Observable<HttpResponse> {

        // This definently is not correct
        return this.http.get(`${your_api_url}/Data`, {observe:'response'}).pipe(map((res: any) => {
            if(res){
                console.log(`inflow_data.service - 200 OK`);
                result = { status: res.status, data: res.Data.json(), success: res.Success, message: res.Message}
            }
            else {
                console.log(`inflow_data.service - Error! HttpStatus: ${res.status}`);
                result = { status: res.status, data: undefined, success: res.Success, message: res.Message}
            }
        }).subscribe(result => { return result });
    }

}

sidor/sida1/sida1.component:

import { Component, OnInit } from '@angular/core';
import { ApiService } from '../services/api.service'
import { HttpResponse } from '../models/http_response';
import { User } from '../models/user';

@Component({
  selector: 'app-page1',
  templateUrl: './page1.component.html',
  styleUrls: ['./page1.component.scss']
})


export class Page1 implements OnInit {

  // I should be able to grab the data from the Observable and feed it into a table or whatever
  dataSource: User[] = [];

  constructor(private apiService: ApiService) { }

    async ngOnInit() {
      this.onGetData();
    }

    onGetData():void {
        this.apiService.getData().subscribe((response: HttpResponse) => {
          console.log(`Http response was - Status: ${response.status} Success: ${response.success} Data: ${response.data}`);

          if(response.success){
           this.dataSource = response.data;
          }
        });
    }

}

Du kan på sätt och vis se vad jag försöker göra. Det finns förmodligen flera saker som är fel med koden ovan. Som jag sa, jag kunde inte hitta ett komplett exempel.

Tack!

Svar #1

Det finns några fel i din kod:

  1. I getData-metoden bör du inte prenumerera på Observable medan din metod förväntas returnera Observable<HttpResponse>.

  2. Du får felaktigt responsens innehåll. Eftersom du använder {observe:'response'}, för att få innehållet i responsen bör du använda res.body. En annan fråga är att se till att fältnamnet du försökte hämta från responsens innehåll måste vara exakt samma, vilket är gemener enligt det bifogade JSON-exemplet.

Uppdaterad: Med observe: "response" som kommer att resultera i en Observable<HttpResponse> (HttpResponse från @angular/common/http), kan du använda ok-egenskapen för att kontrollera om svaret är framgångsrikt (statuskod med 2XX).

  1. Ditt data-fält från JSON är ett objekt, du kan inte tilldela det till dataSource som är en array. Istället bör du lägga till objektet i arrayen med Array.push().

api.service.ts

getData(): Observable<HttpResponse> {
  return this.http.get(`${your_api_url}/Data`, {observe:'response'}).pipe(
    map((res: any) => {
      let responseBody = res?.body;
      let result: HttpResponse;
      if (res.ok) {
        console.log(`inflow_data.service - 200 OK`);
        result = {
          status: res.status,
          data: responseBody.data,
          success: responseBody.success,
          message: responseBody.message,
        };
      } else {
        console.log(`inflow_data.service - Error! HttpStatus: ${res.status}`);
        result = {
          status: res.status,
          data: undefined,
          success: responseBody?.success,
          message: responseBody?.message,
        };
      }

      return result;
    })
  );
}

page1.komponent

this.apiService.getData().subscribe((response: HttpResponse) => {
  console.log(
    `Http response was - Status: ${response.status} Success: ${response.success} Data: ${response.data}`
  );

  if (response.success) {
    this.dataSource.push(response.data);
  }
});

Demo @ StackBlitz