Ce tutoriel montre comment intégrer HTTP et une API dans votre application.
Jusqu'à présent, votre application lisait les données depuis un tableau statique dans un service Angular. L'étape suivante consiste à utiliser un serveur JSON avec lequel votre application communiquera via HTTP. La requête HTTP simulera l'expérience de travailler avec des données provenant d'un serveur.
Important : Nous vous recommandons d'utiliser votre environnement local pour cette étape du tutoriel.
Ce que vous allez apprendre
Votre application utilisera les données d'un serveur JSON
-
Configurer le serveur JSON
JSON Server est un outil open source utilisé pour créer des API REST simulées. Vous l'utiliserez pour servir les données de logements actuellement stockées dans le service de logements.
Installez
json-serverdepuis npm à l'aide de la commande suivante.npm install -g json-serverDans le répertoire racine de votre projet, créez un fichier nommé
db.json. C'est là que vous stockerez les données pourjson-server.Ouvrez
db.jsonet copiez-y le code suivant{ "locations": [ { "id": 0, "name": "Acme Fresh Start Housing", "city": "Chicago", "state": "IL", "photo": "https://angular.dev/assets/images/tutorials/common/bernard-hermant-CLKGGwIBTaY-unsplash.jpg", "availableUnits": 4, "wifi": true, "laundry": true }, { "id": 1, "name": "A113 Transitional Housing", "city": "Santa Monica", "state": "CA", "photo": "https://angular.dev/assets/images/tutorials/common/brandon-griggs-wR11KBaB86U-unsplash.jpg", "availableUnits": 0, "wifi": false, "laundry": true }, { "id": 2, "name": "Warm Beds Housing Support", "city": "Juneau", "state": "AK", "photo": "https://angular.dev/assets/images/tutorials/common/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg", "availableUnits": 1, "wifi": false, "laundry": false }, { "id": 3, "name": "Homesteady Housing", "city": "Chicago", "state": "IL", "photo": "https://angular.dev/assets/images/tutorials/common/ian-macdonald-W8z6aiwfi1E-unsplash.jpg", "availableUnits": 1, "wifi": true, "laundry": false }, { "id": 4, "name": "Happy Homes Group", "city": "Gary", "state": "IN", "photo": "https://angular.dev/assets/images/tutorials/common/krzysztof-hepner-978RAXoXnH4-unsplash.jpg", "availableUnits": 1, "wifi": true, "laundry": false }, { "id": 5, "name": "Hopeful Apartment Group", "city": "Oakland", "state": "CA", "photo": "https://angular.dev/assets/images/tutorials/common/r-architecture-JvQ0Q5IkeMM-unsplash.jpg", "availableUnits": 2, "wifi": true, "laundry": true }, { "id": 6, "name": "Seriously Safe Towns", "city": "Oakland", "state": "CA", "photo": "https://angular.dev/assets/images/tutorials/common/phil-hearing-IYfp2Ixe9nM-unsplash.jpg", "availableUnits": 5, "wifi": true, "laundry": true }, { "id": 7, "name": "Hopeful Housing Solutions", "city": "Oakland", "state": "CA", "photo": "https://angular.dev/assets/images/tutorials/common/r-architecture-GGupkreKwxA-unsplash.jpg", "availableUnits": 2, "wifi": true, "laundry": true }, { "id": 8, "name": "Seriously Safe Towns", "city": "Oakland", "state": "CA", "photo": "https://angular.dev/assets/images/tutorials/common/saru-robert-9rP3mxf8qWI-unsplash.jpg", "availableUnits": 10, "wifi": false, "laundry": false }, { "id": 9, "name": "Capital Safe Towns", "city": "Portland", "state": "OR", "photo": "https://angular.dev/assets/images/tutorials/common/webaliser-_TPTXZd9mOo-unsplash.jpg", "availableUnits": 6, "wifi": true, "laundry": true } ] }Enregistrez ce fichier.
Il est temps de tester votre configuration. Depuis la ligne de commande, à la racine de votre projet, exécutez les commandes suivantes.
json-server --watch db.jsonDans votre navigateur web, accédez à
http://localhost:3000/locationset vérifiez que la réponse contient les données stockées dansdb.json.
Si vous rencontrez des difficultés avec votre configuration, vous trouverez plus de détails dans la documentation officielle.
-
Modifier le service pour utiliser un serveur web au lieu d'un tableau local
La source de données est configurée ; l'étape suivante consiste à modifier votre application web pour s'y connecter et utiliser les données.
Dans
src/app/housing.service.ts, apportez les modifications suivantes :Modifiez le code pour supprimer la propriété
housingLocationListet le tableau contenant les données, ainsi que la propriétébaseUrl.Ajoutez une propriété de type chaîne nommée
urlet affectez-lui la valeur'http://localhost:3000/locations'Ajouter la propriété url dans housing.service.ts
import {Service} from '@angular/core'; import {HousingLocationInfo} from './housinglocation'; @Service() export class HousingService { url = 'http://localhost:3000/locations'; async getAllHousingLocations(): Promise<HousingLocationInfo[]> { const data = await fetch(this.url); return (await data.json()) ?? []; } async getHousingLocationById(id: number): Promise<HousingLocationInfo | undefined> { const data = await fetch(`${this.url}/${id}`); const locationJson = await data.json(); return locationJson ?? {}; } submitApplication(firstName: string, lastName: string, email: string) { // tslint:disable-next-line console.log(firstName, lastName, email); } }Ce code provoquera des erreurs dans le reste du fichier, car celui-ci dépend de la propriété
housingLocationList. Nous allons ensuite modifier les méthodes du service.Modifiez la fonction
getAllHousingLocationspour qu'elle appelle le serveur web que vous avez configuré.Modifier la méthode getAllHousingLocations dans housing.service.ts
import {Service} from '@angular/core'; import {HousingLocationInfo} from './housinglocation'; @Service() export class HousingService { url = 'http://localhost:3000/locations'; async getAllHousingLocations(): Promise<HousingLocationInfo[]> { const data = await fetch(this.url); return (await data.json()) ?? []; } async getHousingLocationById(id: number): Promise<HousingLocationInfo | undefined> { const data = await fetch(`${this.url}/${id}`); const locationJson = await data.json(); return locationJson ?? {}; } submitApplication(firstName: string, lastName: string, email: string) { // tslint:disable-next-line console.log(firstName, lastName, email); } }Le code utilise maintenant du code asynchrone pour effectuer une requête GET via HTTP.
Utile : Dans cet exemple, le code utilise
fetch. Pour des cas d'usage plus avancés, envisagez d'utiliser leHttpClientfourni par Angular.Modifiez la fonction
getHousingLocationByIdpour qu'elle appelle le serveur web que vous avez configuré.Utile : Remarquez que l'URL de
fetchajoute maintenant l'idcomme segment de chemin (${this.url}/${id}) pour demander le logement dont la propriétéida la valeur correspondante.Modifier la méthode getHousingLocationById dans housing.service.ts
import {Service} from '@angular/core'; import {HousingLocationInfo} from './housinglocation'; @Service() export class HousingService { url = 'http://localhost:3000/locations'; async getAllHousingLocations(): Promise<HousingLocationInfo[]> { const data = await fetch(this.url); return (await data.json()) ?? []; } async getHousingLocationById(id: number): Promise<HousingLocationInfo | undefined> { const data = await fetch(`${this.url}/${id}`); const locationJson = await data.json(); return locationJson ?? {}; } submitApplication(firstName: string, lastName: string, email: string) { // tslint:disable-next-line console.log(firstName, lastName, email); } }Une fois toutes les modifications terminées, votre service modifié doit correspondre au code suivant.
Version finale de housing.service.ts
import {Service} from '@angular/core'; import {HousingLocationInfo} from './housinglocation'; @Service() export class HousingService { url = 'http://localhost:3000/locations'; async getAllHousingLocations(): Promise<HousingLocationInfo[]> { const data = await fetch(this.url); return (await data.json()) ?? []; } async getHousingLocationById(id: number): Promise<HousingLocationInfo | undefined> { const data = await fetch(`${this.url}/${id}`); const locationJson = await data.json(); return locationJson ?? {}; } submitApplication(firstName: string, lastName: string, email: string) { // tslint:disable-next-line console.log(firstName, lastName, email); } }
-
Modifier les composants pour utiliser des appels asynchrones au service de logements
Le serveur lit maintenant les données à partir de la requête HTTP, mais les composants qui dépendent du service comportent désormais des erreurs, car ils ont été programmés pour utiliser la version synchrone du service.
Dans
src/app/home/home.ts, modifiez leconstructorpour utiliser la nouvelle version asynchrone de la méthodegetAllHousingLocations. Comme nous n'avons pas utilisé de signals pour notre état, vous devez notifier Angular qu'un changement nécessitant une synchronisation s'est produit. Appelezthis.changeDetectorRef.markForCheck()pour cela.Modifier le constructor dans home.ts
import {ChangeDetectorRef, Component, inject} from '@angular/core'; import {HousingLocation} from '../housing-location/housing-location'; import {HousingLocationInfo} from '../housinglocation'; import {HousingService} from '../housing.service'; @Component({ selector: 'app-home', imports: [HousingLocation], template: ` <section> <form> <input type="text" placeholder="Filter by city" #filter /> <button class="primary" type="button" (click)="filterResults(filter.value)">Search</button> </form> </section> <section class="results"> @for (housingLocation of filteredLocationList; track $index) { <app-housing-location [housingLocation]="housingLocation" /> } </section> `, styleUrls: ['./home.css'], }) export class Home { private readonly changeDetectorRef = inject(ChangeDetectorRef); housingLocationList: HousingLocationInfo[] = []; housingService: HousingService = inject(HousingService); filteredLocationList: HousingLocationInfo[] = []; constructor() { this.housingService .getAllHousingLocations() .then((housingLocationList: HousingLocationInfo[]) => { this.housingLocationList = housingLocationList; this.filteredLocationList = housingLocationList; this.changeDetectorRef.markForCheck(); }); } filterResults(text: string) { if (!text) { this.filteredLocationList = this.housingLocationList; return; } this.filteredLocationList = this.housingLocationList.filter((housingLocation) => housingLocation?.city.toLowerCase().includes(text.toLowerCase()), ); } }Dans
src/app/details/details.ts, modifiez leconstructorpour utiliser la nouvelle version asynchrone de la méthodegetHousingLocationById. Comme précédemment, vous devez aussi appelerthis.changeDetectorRef.markForCheck()pour notifier Angular des changements.Modifier le constructor dans details.ts
import {ChangeDetectorRef, Component, inject} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocationInfo} from '../housinglocation'; import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms'; @Component({ selector: 'app-details', imports: [ReactiveFormsModule], template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> <section class="listing-apply"> <h2 class="section-heading">Apply now to live here</h2> <form [formGroup]="applyForm" (submit)="submitApplication()"> <label for="first-name">First Name</label> <input id="first-name" type="text" formControlName="firstName" /> <label for="last-name">Last Name</label> <input id="last-name" type="text" formControlName="lastName" /> <label for="email">Email</label> <input id="email" type="email" formControlName="email" /> <button type="submit" class="primary">Apply now</button> </form> </section> </article> `, styleUrls: ['./details.css'], }) export class Details { private readonly changeDetectorRef = inject(ChangeDetectorRef); route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocationInfo | undefined; applyForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), email: new FormControl(''), }); constructor() { const housingLocationId = parseInt(this.route.snapshot.params['id'], 10); this.housingService.getHousingLocationById(housingLocationId).then((housingLocation) => { this.housingLocation = housingLocation; this.changeDetectorRef.markForCheck(); }); } submitApplication() { this.housingService.submitApplication( this.applyForm.value.firstName ?? '', this.applyForm.value.lastName ?? '', this.applyForm.value.email ?? '', ); } }Enregistrez votre code.
Ouvrez l'application dans le navigateur et vérifiez qu'elle s'exécute sans erreur.
Note : Cette leçon s'appuie sur l'API fetch du navigateur. Pour la prise en charge des intercepteurs, consultez la documentation du client HTTP
Résumé : Dans cette leçon, vous avez modifié votre application pour utiliser un serveur web local (json-server) et des méthodes de service asynchrones pour récupérer des données.
Félicitations ! Vous avez terminé ce tutoriel avec succès et vous êtes prêt à poursuivre votre parcours en construisant des applications Angular encore plus complexes.
Si vous souhaitez en apprendre davantage, envisagez de suivre d'autres tutoriels et guides Angular destinés aux développeurs.