От автора: релиз Angular 4.3 представил несколько новых функций. Среди них была HttpClientModule (@angular/common/http заменяет @angular/http). Эта библиотека для создания HTTP запросов меньше, проще и мощнее. Новый сервис Angular HttpClient был также представлен в HttpClientModule. С его помощью можно инициировать HTTP запрос. В этом уроке я покажу вам, как реализовать новый клиент и расскажу про его функции.
Краткий обзор
Что нужно изменить в старой версии (pre-v4) для перехода на новую (4+)
Для импорта в NgModule:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// below v4 ========================================== import { HttpModule } from '@angular/http'; ... @NgModule({ imports: [ HttpModule ] }) ... // v4+ =============================================== import { HttpClientModule } from '@angular/common/http'; ... @NgModule({ imports: [ HttpClientModule ] }) ... |
И для использования в сервисе:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// below v4 ========================================== import { Http } from '@angular/http'; ... constructor(private http: Http) {} ... // v4+ =============================================== import { HttpClient } from '@angular/common/http'; ... constructor(private http: HttpClient) {} ... |
Теперь давайте перейдем к подробному разбору.
Установка Angular 4
Для начала установите Angular CLI через Node и npm, если он еще не установлен.
1 |
npm install -g @angular/cli@latest |
Флаг –g – установить глобально. @latest – установить последнюю версию. После установки запустите следующую команду для создания нового приложения.
1 |
ng new httptutorial |
Будет загружен шаблон проекта, а также установятся все зависимости. Структура папок проекта:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
// end-to-end-tests |- e2e/ |----- app.e2e-spec.ts |----- app.po.ts |----- tsconfig.e2e.json // npm dependencies |- node_modules/ // public facing app. built things go here. this wont show until we run a build |- dist/ // where most of the work will be done |- src/ |----- app/ |----- app.component.css|html|spec.ts|ts |----- app.module.ts |----- assets/ |----- environments/ |----- environment.prod.ts|ts |----- favicon.ico |----- index.html |----- main.ts |----- polyfills.ts |----- styles.css |----- test.ts |----- tsconfig.app.json |----- tsconfig.spec.json |----- typings.d.ts // overall configuration |- .angular-cli.json // the main configuration file |- .editorconfig // editorconfig which is used in some VS Code setups |- .gitignore |- karma.conf.js |- package.json |- protractor.conf.js |- README.md |- tsconfig.json |- tslint.json |
Откройте файл package.json и обновите зависимости Angular до версии 4.3.6. Разделы dependencies и devDependencies должны выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
"dependencies": { "@angular/animations": "^4.3.6", "@angular/common": "^4.3.6", "@angular/compiler": "^4.3.6", "@angular/core": "^4.3.6", "@angular/forms": "^4.3.6", "@angular/http": "^4.3.6", "@angular/platform-browser": "^4.3.6", "@angular/platform-browser-dynamic": "^4.3.6", "@angular/router": "^4.3.6", "core-js": "^2.4.1", "rxjs": "^5.4.2", "zone.js": "^0.8.14" }, "devDependencies": { "@angular/cli": "1.3.2", "@angular/compiler-cli": "^4.3.6", "@angular/language-service": "^4.3.6", "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", "@types/node": "~6.0.60", "codelyzer": "~3.1.1", "jasmine-core": "~2.6.2", "jasmine-spec-reporter": "~4.1.0", "karma": "~1.7.0", "karma-chrome-launcher": "~2.1.1", "karma-cli": "~1.0.1", "karma-coverage-istanbul-reporter": "^1.2.1", "karma-jasmine": "~1.1.0", "karma-jasmine-html-reporter": "^0.2.2", "protractor": "~5.1.2", "ts-node": "~3.2.0", "tslint": "~5.3.2", "typescript": "~2.3.3" } |
В папке проекта запустите
1 |
npm install |
Команда подтянет зависимости в файл package.json. Для проверки запустите веб-сервер:
1 |
ng serve |
Веб-сервер разработчика запустится на //localhost:4200. Откройте этот адерс, перед вам будет следующая страница.
Установка модуля HTTP
Далее импортируйте HttpClientModule в корневой модуль приложения src/app/app.module.ts и добавьте его в свойство imports. Файл должен быть таким:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } |
Для использования HttpClient в компонентах, его необходимо вставить в конструктор класса. Импортируйте HttpClient в src/app/app.component.ts, далее вставьте его в конструктор, вот так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import { Component } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app'; constructor( private http: HttpClient ) { //dependency injection, creating an instance of HttpClient called http } } |
Теперь вы можете выполнять CRUD операции и делать HTTP запросы. Среди HTTP методов доступны post, put, delete, patch, head и jsonp.
HTTP GET
Для демонстрации метода get мы будем запрашивать фейковый REST API. Откройте //jsonplaceholder.typicode.com и прокрутите страницу до Resources. На экране будет следующее:
В Resources кликните на /posts
Это куча json объектов. У каждого по 4 свойства: userId, id, title и body. Если открыть url //jsonplaceholder.typicode.com/posts через приложение Angular, мы получим результат выше. Другие методы HTTP работают примерно так же.
Отредактируйте src/app/app.component.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import { Component, OnInit } from '@angular/core'; // importing the OnInit interface import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { // implementing OnInit title = 'app'; constructor( private http: HttpClient ) { } ngOnInit(): void { // adding the lifecycle hook ngOnInit this.http.get('//jsonplaceholder.typicode.com/posts').subscribe(data => { console.log(data); // using the HttpClient instance, http to call the API then subscribe to the data and display to console }); } } |
Мы вызываем API endpoint в хуке жизненного цикла ngOnInit. Хук выполняется при инициализации компонента. Сначала импортируется интерфейс OnInit. Затем этот интерфейс реализуется в определении класса. Далее мы вызываем метод ngOnInit, внутри которого мы вызываем HttpClient объект http, который мы ранее создали в конструкторе.
Мы вызываем метод get из объекта, который ожидает URL нужного нам API endpoint. Метод get возвращает observable. Чтобы получать уведомления о поступлении ответа, на этот observable необходимо подписаться. Это делается через метод subscribe. В методе subscribe мы задаем обработчик события, получающий данные, которые потом можно распечатать в консоль. Вывод консоли в браузере:
Это json объекты, полученные из //jsonplaceholder.typicode.com/posts.
Чтобы получить доступ к любому свойству из объекта ответа, например к data.userId, необходимо бросить объект ответа в тип, содержащий соответствующие свойства. Для этого необходимо определить интерфейс. Вставьте следующий код в файл src/app/app.component.ts после импортов.
1 2 3 4 5 |
interface DataResponse { userId: string; id: string; title: string; } |
Затем отредактируйте вызов get под интерфейс DataResponse:
1 2 3 4 5 6 |
this.http.get<DataResponse>('//jsonplaceholder.typicode.com/posts/1').subscribe(data => { console.log('UserId: ' + data.userId); console.log('Id: ' + data.id); console.log('Title: ' + data.title); console.log('Body: ' + data.body); }); |
Теперь мы можем получить доступ к userId, title и body отдельно. Вывод в консоль должен быть таким:
Если http запрос не удался, мы можем выводить сообщение об ошибке. Для этого сначала импортируйте HttpErrorResponse из @angular/common/http. Затем создайте обработчик ошибок, добавив колбек к методу subscribe. Далее определите параметр типа HttpErrorResponse для функции обработчика ошибок:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { HttpClient, HttpErrorResponse } from '@angular/common/http'; // ... this.http.get<DataResponse>('//jsonplaceholder.typicode.com/posts/1').subscribe(data => { console.log('UserId: ' + data.userId); console.log('Id: ' + data.id); console.log('Title: ' + data.title); console.log('Body: ' + data.body); }, (err: HttpErrorResponse) => { if (err.error instanceof Error) { console.log('Client-side error occured.'); } else { console.log('Server-side error occured.'); } } ); |
HTTP POST
Как и раньше, для демонстрации HTTP POST будем использовать JSONPlaceholder. Однако обратите внимание, что это фейк сервис. Данные не постоянны, но API отвечает как настоящий. Конечная точка POST запроса — //jsonplaceholder.typicode.com/posts. Если открыть этот url, вы увидите, что нам доступно 4 свойства userId, id, title и body. Чтобы с помощью этой конечной точки создать новую запись, добавьте второй вызов внутрь жизненного цикла ngOnInit:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
this.http.post('//jsonplaceholder.typicode.com/posts', { title: 'foo', body: 'bar', userId: 1 }) .subscribe( res => { console.log(res); }, err => { console.log('Error occured'); } ); |
Метод post возвращает observable, поэтому на него нужно подписаться, как и раньше. Это делается вызовом метода subscribe. В методе subscribe определяется обработчик событий, получающий данные, которые затем можно распечатать в консоли. Далее мы добавляем обработчик ошибок для печати информации при возникновении ошибок. Вывод в консоли браузера должен быть следующим:
HTTP перехватчики
Перехватчики – еще одна новая функция модуля HTTP Client. Перехватчики находятся между приложением и back end API. С их помощью можно манипулировать запросами, идущими от приложения до их принятия и отправки в back end. Верно и обратное – ответ с back end можно изменить до принятия и обработки в приложении. Для демонстрации этого мы изменим заголовки запроса get //jsonplaceholder.typicode.com/posts/1/. Мы будем менять поле заголовка Accept-Language, идущее от API. Создайте новый файл src/app/typicode.interceptor.ts со следующим кодом:
1 2 3 4 5 6 7 8 9 10 11 12 |
import { Injectable } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; import { Observable } from 'rxjs/observable'; @Injectable() export class TypicodeInterceptor implements HttpInterceptor { intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const authReq = req.clone({ headers: req.headers.set('Accept-Language', 'Test') }); return next.handle(authReq); } } |
Сначала мы импортируем injectable из @angular/core. Далее мы импортируем HttpEvent, HttpInterceptor, HttpHandler из @angular/common/http. Пакет Observable импортируется из rxjs/observable.
Далее мы добавляем декоратор @injectable, создаем класс TypicodeInterceptor, реализующий интерфейс HttpInterceptor. Далее добавляем метод interceptor в реализацию класса.
Метод принимает запрос, меняет его перед дальнейшей отправкой для обработки в приложении. Поэтому мы передаем два параметра в этот метод: сам запрос типа HttpRequest
Далее вызывается метод req.clone() для клонирования оригинального HTTP запроса. В методе мы меняем поле заголовка с помощью метода req.headers.set(). Мы изменяем поле Accept-Language на значение Test.
Вновь созданный объект запроса (с заголовком) передается для дальнейшей обработки в метод next.handle.
Провайдер перехватчиков
Чтобы в нашем приложении заработали перехватчики, необходимо отредактировать файл src/app/app.module.ts.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { AppComponent } from './app.component'; import { TypicodeInterceptor } from './typicode.interceptor'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [{ provide: HTTP_INTERCEPTORS, useClass: TypicodeInterceptor, multi: true }], bootstrap: [AppComponent] }) export class AppModule { } |
Мы импортировали HTTP_INTERCEPTORS из @angular/common/http и класс TypicodeInterceptor, созданный ранее в src/app/typicode.interceptor.ts. Далее мы вставляем новый объект в массив, который присваивается к свойству провайдера @NgModule. Объект содержит 3 свойства:
provide: для включения перехватчиков необходимо установить в HTTP_INTERCEPTORS
useClass: необходимо установить в тип класса нашего перехватчика
multi: необходимо установить в multi, чтобы Angular понял, что HTTP_INTERCEPTORS массив значений, а не одно значение
Перехватчики в действии можно посмотреть на вкладке network. Перезагрузите страницу, выберите HTTP запрос на левой панели, и на правой панели отобразятся HTTP заголовки. Нам нужен запрос get по адресу //jsonplaceholder.typicode.com/posts/1.
Заключение
Новый модуль HTTP client облегчает работу с HTTP back end интерфейсом типа REST API. Мы изучили базовую настройку HttpClientModule, продемонстрировали использование методов get и post, а также показали, как использовать новую функцию перехватчиков. Подумайте о случаях использования этой функции. Посмотрите проект на Github. Все вопросы оставляйте в комментариях.
Автор: Caleb Oki
Источник: //scotch.io/
Редакция: Команда webformyself.