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.
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
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:
Créez une classe app-error.ts comme ci-dessous:
export class AppError {
constructor(public originalError?: any) { }
}
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;
}
}
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
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));
}
}
}
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.
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 {
// ...
}
}
);
}
}
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();
});
});
}
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"}
]
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
}
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
}