web-dev-qa-db-fra.com

Angular HttpClient modifier la réponse en service

J'effectue une mise à niveau vers Angular vers la version 5, j'utilisais @angular/http auparavant et maintenant, je dois mettre à jour vers @angular/common/http et utiliser HttpClient

Je viens juste de faire des requêtes http dans les services (pas dans les composants) et cela les rend faciles à réutiliser

C'est ce que j'ai déjà (http obsolète)

return this.http.get(url, {headers: this.headers}).map(
      (response: Response) => {
        const data = response.json();
        // Does something on data.data

        // return the modified data:
        return data.data;
      }
    ).catch(
      (error: Response) => {
        return Observable.throw(error);
      }
    );

Maintenant, d'après ce que j'ai appris de la nouvelle HttpClient, c'est comme si je ne pouvais pas modifier la réponse et la donner à la méthode du composant qui la souscrit.

comment modifier la réponse à une requête HTTP et y accéder facilement avant de la renvoyer depuis Observable?

Je veux juste la même capacité de modifier la réponse que je reçois de l'API ... Par exemple, ajouter un élément ou faire d'autres choses avant de le réenregistrer.

5
John Three

Tout dépend de la version de RxJs. Angular 6 fourni avec RxJs 6 - ce qui signifie que l’approche map ()/catch () n’est plus valide.

Au lieu de cela, vous devez utiliser pipe + map ()/catchError () comme indiqué ci-dessous:

Avant Angular 6/RxJs 6 - utilisation classique de Http:

return this.http.get(url, {headers: this.headers}).map(
  (response: Response) => {
    const data : SomeType = response.json() as SomeType;
    // Does something on data.data

    // return the modified data:
    return data.data; // assuming SomeType has a data properties. Following OP post
  }
).catch(
  (error: Response) => {
    return Observable.throw(error);
  }
);

Devrait être changé en ceci:

Après Angular 6/RxJs 6 - Migration HttpClient:

return this.http.get<SomeType>(url, {headers: this.headers})
  .pipe(
     map( response => {  // NOTE: response is of type SomeType
         // Does something on response.data
         // modify the response.data as you see fit.

         // return the modified data:
         return response; // kind of useless
     }),
     catchError( error => {
         return Observable.throw(error);
     })
  ); // end of pipe

Dans le tuyau, map () récupérera l'objet de réponse (déjà analysé à partir de Json) et catchError () détectera la première erreur, si http échoue.

Notez également que vos en-têtes doivent également être un objet HttpHeaders.

Lisez sur pipe, map et catchError dans RxJs 6

16
John

Si vous voulez gérer les erreurs plus efficacement, en écrivant ci-dessous les codes et les classes d’erreurs, veuillez noter les points suivants:

  1. Je fais un dossier des erreurs et à l'intérieur de ce dossier faire une classe pour chacune des erreurs, ces erreurs peuvent être 500 erreurs ou 400 erreurs comme image bloww:

 Error Classes

  1. Créez une classe app-error.ts comme ci-dessous: 

    export class AppError {
        constructor(public originalError?: any) { }
    }
    
  2. Une autre classe d'erreurs s'étend de app-error.ts class:

    // not-found-error.ts class
    import {AppError} from './app-error';
    
    export class NotFoundError extends AppError { }
    
    
    
    // conflict-error.ts class
    import {AppError} from './app-error';
    
    export class ConflictError extends AppError { }
    
    
    
    // internal-server-error.ts class
    import {AppError} from './app-error';
    
    export class InternalServerError extends AppError { }
    
    
    
    // bad-request-error.ts class
    import {AppError} from './app-error';
    
    export class BadRequestError extends AppError {
        constructor(public originalError?: any) {
            super(originalError);
        }
    
        get errors(): string[] {
            if (this.originalError)
                return this.originalError;
    
            return null;
        }
    }
    
  3. Si vous voulez accéder à l'erreur de base ou si vous pouvez modifier l'erreur, je le fais dans la dernière classe bad-request-error.ts

  4. Ensuite, vous pouvez utiliser ces classes service inisde:

    import {Injectable} from '@angular/core';
    import {HttpClient} from '@angular/common/http';
    import {HttpHeaders} from '@angular/common/http';
    
    import {Observable} from 'rxjs/Observable';
    import 'rxjs/add/operator/map';
    import 'rxjs/add/operator/catch';
    import 'rxjs/add/observable/throw';
    
    import {AppError} from '../errors/app-error';
    import {BadRequestError} from '../errors/bad-request-error';
    import {NotFoundError} from '../errors/not-found-error';
    import {InternalServerError} from '../errors/internal-server-error';
    import {ConflictError} from '../errors/conflict-error';
    
    @Injectable()
    export class DataService {
        public headers = new HttpHeaders().set('Content-Type', 'application/json');
    
        constructor(public http: HttpClient, public url: string) { }
    
        get(id: number) {
            return this.http.get(`${this.url}/${id}`, {headers: this.headers})
                   .map((response) => response.json())
                   .catch(DataService.handleError);
        }
    
        create(resource) {
            return this.http.post(this.url, JSON.stringify(resource), {headers: this.headers})
                   .map((response) => response.json())
                   .catch(DataService.handleError);
        }
    
        update(id: number, resource) {
            return this.http.put(`${this.url}/${id}`, JSON.stringify(resource), {headers: this.headers})
                   .map((response) => response.json())
                   .catch(DataService.handleError);
        }
    
        remove(id: number) {
            return this.http.delete(`${this.url}/${id}`, {headers: this.headers})
                   .map((response) => response.json())
                   .catch(DataService.handleError);
        }
    
        public static handleError(error: Response) {
            switch (error.status) {
                case 400:
                    return Observable.throw(new BadRequestError(error));
                case 404:
                    return Observable.throw(new NotFoundError());
                case 409:
                    return Observable.throw(new ConflictError());
                case 500:
                    return Observable.throw(new InternalServerError());
    
                default:
                    return Observable.throw(new AppError(error));
            }
        }
    }
    
  5. Le code ci-dessus est le meilleur code pour la gestion des erreurs et l’utilisation d’un opérateur de carte pour manipuler la réponse avec succès.

  6. Et le rythme le plus récent utilise le service dans le composant, comme ci-dessous:

    import {Component} from '@angular/core';
    import {OnInit} from '@angular/core';
    import {HttpParams} from '@angular/common/http';
    
    import {DataService} from '../../services/data.service';
    
    import {AppError} from '../errors/app-error';
    import {BadRequestError} from '../errors/bad-request-error';
    import {NotFoundError} from '../errors/not-found-error';
    import {InternalServerError} from '../errors/internal-server-error';
    import {ConflictError} from '../errors/conflict-error';
    
    @Component({
        selector: 'app-data',
        templateUrl: './data.component.html',
        styleUrls: ['./data.component.css']
    })
    export class DataComponent implements OnInit {
    
        constructor(private dataService: DataService) {
        }
    
        ngOnInit() {
            this.dataService.get(123).subscribe(
                (response: DataModel) => {
                    // ...
                },
                (error: AppError) => {
                    if (error instanceof NotFoundError) {
                        // ...
                    } else if (error instanceof BadRequestError) {
                        // ...
                    } else if (error instanceof ConflictError) {
                        // ...
                    } else {
                        // ...
                    }
                }
            );
        }
    }
    
1
Sina Lotfi

Vous pouvez créer votre propre observable qui enveloppe le fichier http.get et renvoyer votre réponse manipulée. Dans cet exemple, il s'agit de l'objet manipulatedAccountsResponse:

getAll(): Observable<AccountsResponse> {
  return Observable.create(observer => {
    this.http.get<AccountsResponse>('/accounts')
             .subscribe((result) => {
               const manipulatedAccountsResponse = result;
               // do something with result.
               manipulatedAccountsResponse.setTotal(100);
               observer.next(manipulatedAccountsResponse);
               // call complete if you want to close this stream (like a promise)
               observer.complete();
            });
  });

}

1
Daniel Mora

Mon service

import {HttpClient} from '@angular/common/http';

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
@Injectable()
export class DataService {
    constructor(private http: HttpClient) {}
    getData()
    {
        return this.http.get('../assets/data.json').map(data=>{
            return this.process(data);
        }).catch(
            (error: Response) => {
              return Observable.throw(error);
            });
    }
    process(data:any)  
    {
        let dataTransform:any[]=[];
        let i:number=0;
        for (let item of data)
        {
            dataTransform.Push({"id":i,"key":item.key});
            i++;
        }
        return dataTransform;
    }
}

// mon composant

export class AppComponent implements OnInit {
  constructor(private dataService:DataService){}
  ngOnInit(){
    this.dataService.getData().subscribe((data:any)=> {
      console.log(data);
    });
  }
}

// l'asset/data.json

[
    {"key":"uno"},
    {"key":"dos"},
    {"key":"tres"},
    {"key":"cuatro"},
    {"key":"cinco"}
]
1
Eliseo

Selon ma considération, vous pouvez appeler fonction de ce service dans votre réponse au succès et traiter vos données en fonction et les renvoyer pour les sauvegarder.

return this.http.get(url, {headers: this.headers}).map(
      (response: Response) => {
        const data = response.json();
        return this.processData(data);
      }
    ).catch(
      (error: Response) => {
        return Observable.throw(error);
      }
    );
    
public processData(data : any){
  //process your data
  return data;//this is processed data
}

0
Kishan

Dans le "nouveau" client HTTP, obtenez encore une réponse json par défaut. Ensuite, vous écrivez seulement

import {HttpClient} from '@angular/common/http'; //<--HttpClient
import 'rxjs/add/operator/map';                  //import the operator "map"
import 'rxjs/add/operator/catch'; //and the operator "catch"

....
constructor(private http: HttpClient) {} //<--sure HttpClient
...
return this.http.get(url).map(  //yet get "data"
      (data:any) => {
        return this.processData(data);
      }
    ).catch(
      (error: Response) => {
        return Observable.throw(error);
      }
    );

public processData(data : any){
  //process your data
  return data;//this is processed data
}
0
Eliseo