Le Guide Angular | Marmicode
  • Le Guide Angular par Marmicode
  • Pourquoi Angular ?
  • ECMAScript 6+
    • Un Peu d'Histoire
    • Propriétés du Langage
    • "Single-Threaded" donc Asynchrone
    • Event Loop
    • Classes
    • Hoisting is Dead: var vs. let vs. const
    • this & "binding"
    • Arrow Functions
    • Template Strings
    • Syntactic Sugar
      • Spread
      • Destructuring
      • Rest
      • Object Literal Property Value Shorthand
    • Named Parameters
    • Compatibilité
  • TypeScript
    • Pourquoi TypeScript ?
    • De l'ECMAScript au TypeScript
    • Visibilité des Propriétés
    • Typing des Propriétés
    • Types
    • Interfaces
    • Inference
    • Duck Typing
    • Duck Typing Patterns
      • Compatibilité de Librairies
      • Entity Constructor
    • Décorateurs
      • Décorateurs de Propriété
      • Décorateurs de Classe
      • Décorateurs de Méthode & Paramètres
    • Quelques Liens
  • Tools
    • Clavier mécanique
    • Git
    • Command Line
    • NodeJS
    • NPM
    • Yarn
      • Pourquoi Yarn ?
      • Définition et Installation des Dépendances
      • Scripts
      • Mise à Jour et Automatisation
    • Chrome
    • IntelliJ / WebStorm / VSCode
      • Raccourcis clavier IntelliJ / WebStorm
    • Floobits
    • Angular CLI
    • StackBlitz
    • Compodoc
  • Angular
    • Bootstrap
    • Composants
      • Root Component
      • Template Interpolation
      • Property Binding
      • Class & Style Binding
      • Event Binding
      • *ngIf
      • *ngFor
      • L'approche MVC
      • Création de Composants
      • Exemple
    • Container vs. Presentational Components
    • Interaction entre Composants
      • Input
      • Output
      • Exemple
    • Change Detection
      • Les Approches Possibles
      • Fonctionnement de la Change Detection
      • Optimisation de la Change Detection
      • Immutabilité
      • Quelques Liens
    • Project Structure & Modules
      • Entry Point
      • Définition d'un Module
      • Root Module
      • Feature Module
      • Shared Module
      • Exemple
    • Dependency Injection
      • Qu'est-ce que la "Dependency Injection" ?
      • Injection d'un Service Angular
      • Services & Providers
      • Portée des Services
      • Tree-Shakable Services
      • Class vs Injection Token
      • Exemple
    • Callback Hell vs. Promise vs. Async / Await
      • Callback Hell
      • Promise
      • Async / Await
    • Observables
      • Reactive Programming
      • Promise vs Observable
      • Subscribe
      • Unsubscribe ⚠️
      • Création d'un Observable
      • Opérateurs
        • Définition d'un Opérateur
        • Lettable Operators vs Legacy Methods
        • map
        • filter
        • mergeMap & switchMap
        • shareReplay
        • buffer
        • debounceTime
        • distinctUntilChanged
        • retry
      • Quelques Liens
      • Talks
    • Http
      • Pourquoi HttpClient ?
      • Utilisation de HttpClient
      • Utilisation dans un Service
      • Gestion de la Subscription ⚠️
    • State Management
      • Quelques Liens
      • Talks
    • GraphQL
    • Formulaires
      • Template-driven Forms 🤢
      • Reactive Forms 👍
        • Avantages des "Reactive Forms"
        • La boite à outils des "Reactive Forms"
        • Validation
        • Observation des Changements
    • Directives
      • Attribute Directive
      • Structural Directive
    • Pipes
    • Routing
      • Mise en Place du Routing
      • Lazy Loading
      • Project Structure
      • Route Guards
    • Testing
      • Unit-Testing
        • 📺Introduction au Test-Driven Development
        • Jasmine
        • Unit-Test Synchrone
        • Test-Driven Development
        • Unit-Test Asynchrone
        • TestBed
        • Unit-Test d'un Service
        • Unit-Test d'un Composant
        • Unit-Test et Spies
        • Unit-Test et HttpClient
      • End-to-End
      • Talks
    • Sécurité
      • Quelques Liens
    • Animation
    • Internationalisation
    • Quelques Liens
  • Cookbook
    • Authentification et Autorisation
    • Remplacement Dynamique de Composants
    • Lazy Loading without Router
    • Project Structure
    • SCAM Modules
    • Setup a Mock ReSTful API
  • Autres Ressources
  • Stay Tuned
    • 🎁-20% sur nos workshops avec le code GUIDEANGULAR
    • 🐦Suivez-moi !
    • 📺Cours Vidéo
    • 📬Newsletter
    • 📝Blog
  • Nos Services
    • Formation Angular
    • Atelier Unit-Testing Angular
    • Atelier Architecture Angular
    • Consultation à Distance & Code Review
  • Nos Guides
    • Guide Agile
    • Guide API ReST
    • Guide NodeJS
Propulsé par GitBook
Sur cette page
  • 1. Injection du service HttpClient
  • 2. Exécution de la requête
  • HttpClient.get & co.
  • Déclenchement de la requête au subscribe
  • 3. Traitement de la "response"
  • "Hint" du type de la "response"
  • Transformation de la "response"
  • Attention au type de retour
  • Astuce
  1. Angular
  2. Http

Utilisation de HttpClient

PrécédentPourquoi HttpClient ?SuivantUtilisation dans un Service

Dernière mise à jour il y a 5 ans

1. Injection du service HttpClient

HttpClient est un service Angular ; on peut donc le récupérer avec la .

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

@Component({
    selector: 'wt-book-search',
    templateUrl: './book-search.component.html'
})
export class BookSearchComponent {

    constructor(private _httpClient: HttpClient) {
    }

}

On obtient l'erreur suivante No provider for HttpClient! car le service HttpClient n'est pas encore et il faut donc importer le module associé HttpClientModule.

Etant donné que le service HttpClient est stateless, nous pouvons importer le module HttpClientModule directement dans notre BookModule.

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

@NgModule({
    declarations: [
        BookPreviewComponent,
        BookSearchComponent
    ],
    exports: [
        BookPreviewComponent,
        BookSearchComponent
    ],
    imports: [
        HttpClientModule,
        SharedModule
    ]
})
export class BookModule {
}

2. Exécution de la requête

HttpClient.get & co.

Nous pouvons donc récupérer les données par API dans le "lifecycle hook" ngOnInit.

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
    selector: 'wt-book-search',
    templateUrl: './book-search.component.html'
})
export class BookSearchComponent implements OnInit {

    private _bookListUrl = 'https://www.googleapis.com/books/v1/volumes?q=extreme%20programming';

    constructor(private _httpClient: HttpClient) {
    }

    ngOnInit() {
        this._httpClient.get(this._bookListUrl);
    }

}

Déclenchement de la requête au subscribe

En inspectant le comportement du "browser“, on peut remarquer que la requête n'est pas envoyée.

En effet, les méthodes get, delete, patch, post, put, request etc... retournent toujours un Observable.

Cet Observable est "lazy" et il faut donc subscribe pour déclencher le traitement.

Par défaut, les paramètres observe et responseType valent respectivement body et json ; ce qui veut dire que nous allons directement récupérer un objet JavaScript correspondant au contenu JSON "parsé" depuis la "response".

Ces deux paramètres (observe et responseType) peuvent être manipulés pour récupérer l'objet HttpResponse, les événements de progression ou le contenu brut d'une "response".

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
    selector: 'wt-book-search',
    templateUrl: './book-search.component.html'
})
export class BookSearchComponent implements OnInit {

    bookCount: number;
    bookList: Book[];

    private _bookListUrl = 'https://www.googleapis.com/books/v1/volumes?q=extreme%20programming';

    constructor(private _httpClient: HttpClient) {
    }

    ngOnInit() {
        this._httpClient.get(this._bookListUrl)
            .subscribe(googleVolumeListResponse => {

                this.bookCount = googleVolumeListResponse.totalItems;

                // @TODO: this.bookList = ...

            });
    }

}

3. Traitement de la "response"

"Hint" du type de la "response"

Lors de la compilation, TypeScript ne connait pas le type des données retournées par l'API. Par défaut, la méthode get retourne un objet de type Observable<Object> . C'est à dire que googleVolumeListResponse est de type Object (ouJavaScript Plain Object). Cela n'est pas bloquant mais on risque de perdre l'aide du compilateur et commettre des erreurs.

Les méthodes de la classe HttpClient sont des méthodes génériques et il est donc possible de contrôler leur type de retour.

Ainsi, avec l'exemple ci-dessous :

export interface GoogleVolumeListResponse {
    totalItems: number;
    items: Array<{
        volumeInfo: {
            title: string;
        }
    }>;
}
this._httpClient.get<GoogleVolumeListResponse>(url)
    .subscribe(googleVolumeListResponse => {
        this.bookCount = googleVolumeListResponse.totalItem;
    });

nous obtenons l'erreur suivante :

error TS2551: Property 'totalItem' does not exist on type 'GoogleVolumeListResponse'. Did you mean 'totalItems'?

ATTENTION ! Le paramètre de type GoogleVolumeListResponse passé à la méthode n'est qu'un "hint".

Si l'API retourne des données sous une forme différente ou si l'interface GoogleVolumeListResponse est erronée ou simplement pas à jour, alors la compilation va réussir mais en revanche nous risquons de nous retrouver avec des types incohérents dans nos variables et propriétés (et potentiellement n'importe où dans l'application tant que les données retournées par l'API ne sont pas vérifiées en "runtime").

A titre d'exemple, si l'API renvoie le JSON suivant : {"totalItems": "oups!"} alors notre propriété bookCount qui est bien de type number, contiendra le string oups!.

Transformation de la "response"

Pour éviter les problèmes décrits précédemment, il est préférable d'éviter de se baser uniquement sur le "hint" de type de la réponse et de le propager dans l'application.

Nous allons donc transformer la "response" en une entité associée à notre "feature".

export interface GoogleVolumeListResponse {
    totalItems: number;
    items: Array<{
        volumeInfo: {
            title: string;
        }
    }>;
}

@Component({
    selector: 'wt-book-search',
    templateUrl: './book-search.component.html',
    styleUrls: ['./book-search.component.scss']
})
export class BookSearchComponent implements OnInit {

    bookCount: number;
    bookList: Book[];
​
    private _bookListUrl = 'https://www.googleapis.com/books/v1/volumes?q=extreme%20programming';

    constructor(private _httpClient: HttpClient) {
    }

    ngOnInit() {
        this._httpClient.get<GoogleVolumeListResponse>(this._bookListUrl)
            .subscribe(googleVolumeListResponse => {

                this.bookCount = googleVolumeListResponse.totalItems;​
                this.bookList = googleVolumeListResponse.items.map(item => new Book({
                    title: item.volumeInfo.title
                }));

            });
    }

}

Attention au type de retour

Malheureusement, la classe HttpClient abuse massivement de l'anti-pattern de "method overloading".

L'anti-pattern est tellement poussé à l'extrême que le type de retour peut changer en fonction de la valeur de certains paramètres (i.e. paramètresobserveet responseType).

Astuce

this._httpClient.get<BookListResponse>('https://books.wishtack.com/api/v2/books')
    .subscribe(response => {
        this.bookList = response.items.map(item => new Book(item));
    });

Si vous disposez d'une spécification OpenAPI (Swagger) de votre API, __pensez à générer ces types avec Swagger Codegen ou directement depuis Swagger Online Editor .

Si vous consommez votre propre API, pensez à profiter du pour construire directement vos entités :

Dependency Injection
Tree-Shakable
Feature Module
https://swagger.io/swagger-codegen/
https://editor.swagger.io/
Duck Typing