HTTP
이 페이지에서 다음과 같이 개선할 것입니다.
- 서버에서 Hero 데이터를 가져옵니다.
- 사용자가 Hero 이름을 추가, 편집 및 삭제할 수 있습니다.
- 변경 사항을 서버에 저장합니다.
원격 서버의 웹 API에 해당 HTTP 호출을 하도록 앱을 수정합니다.
이 페이지를 끝내면 앱은이 라이브 예제/예제 다운로드처럼 보일 것입니다.
어디까지 했었나?
이전 페이지에서는 대시 보드와 고정된 Hero들 목록을 Navigate하면서 선택한 Hero를 편집하는 방법을 배웠습니다. 그것이 이 페이지의 출발점입니다.
앱 실행과 트랜스파일을 유지하기
터미널 창에서 다음 명령을 입력합니다.
|
|
이 명령은 TypeScript 컴파일러를 “watch mode”에서 실행하여 코드가 변경되면 자동으로 다시 컴파일 하도록합니다. 또한 이 명령은 앱이 브라우저에서 동시에 실행되고 코드가 변경되면 브라우저를 새로 고칩니다.
다시 컴파일하거나 새로 고치지 않고 브라우저를 일시 정지하지 않아 Tour of Heroes 앱을 계속 만들 수 있습니다.
HTTP Service 지원하기
HttpModule
은 Angular core 모듈이 아닙니다. HttpModule
은 웹 접근에 대한 Angular의 선택적인 접근 방식입니다. 이것은 @angular/http
라고 하는 별도의 애드온 모듈로 존재하며 Angular npm 패키지의 일부로 별도의 스크립트 파일로 제공됩니다.
SystemJS
가 필요할 때 라이브러리를 로드하기 위해 systemjs.config
에서 설정 했으므로 @angular/http
를 import
할 준비가되었습니다.
HTTP Service 등록
응용 프로그램은 Angular http
서비스에 따라 달라지며, 그 자체는 다른 Service의 지원에 의존합니다. @angular/http
라이브러리의 HttpModule
은 완전한 HTTP 서비스 집합을 제공합니다.
앱의 어느 곳에서나 http
서비스에 접근할 수 있게하려면 AppModule
의 import
목록에 HttpModule
을 추가합니다.
src/app/app.module.ts (v1)
루트 NgModule AppModule
에서 imports
배열의 일부로 HttpModule
을 제공합니다.
Web API 시뮬래이트
우리는 루트AppModule
의 providers에 app-wide 서비스를 등록할 것을 권장합니다.
Heroes 데이터에 대한 요청을 처리할 수있는 웹 서버가 있을 때까지 HTTP 클라이언트는 Mock Service인 in-memory 웹 API에서 데이터를 가져오고 저장합니다.
src/app/app.module.ts
을 Mock 서비스 사용하는 이 버전으로 업데이트합니다.
src/app/app.module.ts (v2)
|
|
실제 API 서버를 요구하는 대신,이 예제는 InMemoryWebApiModule을 import
에 추가함으로써 원격 서버와의 통신을 시뮬레이트하고, Http
클라이언트의 XHR 백엔드 서비스를 메모리 내에서 효과적으로 대체합니다.
|
|
forRoot()
설정 메서드는 in-memory
데이터베이스를 준비하는 InMemoryDataService
클래스를 사용합니다. 다음과 같은 내용으로 app에 in-memory-data.service.ts
파일을 추가합니다.
src/app/in-memory-data.service.ts
이 파일은 mock-heroes.ts
를 대체합니다. 이제는 mock-heroes.ts
파일을 삭제해도 안전합니다. Hero “Zero”를 추가하여 데이터 서비스가 id == 0
인 Hero를 처리할 수 있음을 확인했습니다.
in-memory
웹 API는 개발 초기와 이 Tour of Heroes와 같이 시연에서 유용합니다. 이 백엔드 대체에 대한 세부 사항은 걱정하지 마십시오. 실제 웹 API 서버를 가지고있을 때 건너 뛸 수 있습니다.in-memory
웹 API에 대한 자세한 내용은 HTTP Client 페이지의 Appendix: Tour of Heroes in-memory web api 섹션을 참조하십시오.
Hero들과 HTTP
현재 HeroService
구현에서는 Mock Heroes가 Resolved Promise를 반환합니다.
src/app/hero.service.ts (old getHeroes)
이것은 궁극적으로 비동기 작업이어야하는 HTTP 클라이언트로 Heroes를 가져 오는 것을 예상하여 구현되었습니다.
이제 HTTP를 사용하도록 getHeroes()
를 변환합니다.
src/app/hero.service.ts (updated getHeroes and new class members)
다음과 같이 import
문을 업데이트하십시오.
src/app/hero.service.ts (updated imports)
|
|
브라우저를 새로 고칩니다. Hero 데이터가 Mock 서버에서 성공적으로 로드 되어야합니다.
HTTP Promise
Angular http.get
은 RxJS Observable
을 반환합니다. Observable은 비동기 데이터 흐름을 관리하는 강력한 방법입니다. 이 페이지의 뒷부분에있는 Observable에 대해서 읽어 보십시오
지금은 toPromise
연산자를 사용하여 Observable을 Promise로 변환합니다.
|
|
Angular Observable
에는 toPromise
연산자가 기본적으로 제공되지 않습니다.
Observable
을 확장하는 toPromise
와 같은 유용한 연산자가 많이 있습니다. 이러한 기능을 사용하려면 연산자를 추가해야합니다. 이것은 RxJS
라이브러리에서 다음과 같이 import
할 수 있습니다.
|
|
이 튜토리얼의 뒷부분에서 더 많은 연산자를 추가하고 그렇게해야하는 이유를 배웁니다.
then
callback 안에서 데이터 추출
Promise then()
콜백에서 HTTP 응답의 json
메소드를 호출하여 응답내의 데이터를 추출합니다.
|
|
응답 JSON에는 호출자가 원하는 Heroes 배열을 보유하는 단일 data
속성이 있습니다. 그래서 그 배열을 해결된 Promise 값으로 반환합니다.
서버가 반환하는 데이터의 모양에 유의하십시오. 이 특정 in-memory 웹 API 예제는 데이터 프로퍼티가 있는 객체를 반환합니다. API가 다른 것을 반환할 수 있습니다. 웹 API와 일치하도록 코드를 조정하십시오.
호출자는 (Mock) 서버에서 Hero들을 가져온 것을 알지 못합니다. 그것은 이전처럼 Hero의 Promise를 받습니다.
에러 핸들링
getHeroes()
의 끝에서 서버 실패를 catch
하고 error handler에 전달합니다.
|
|
이것은 중요한 단계입니다. HTTP 오류는 사용자가 제어할 수없는 이유로 자주 발생하므로 대비 해야합니다.
|
|
이 데모 서비스는 오류를 console에 기록합니다. 실서비스에서는 코드의 오류를 처리할 것입니다. 데모에서는 이 방법이 유용합니다.
이 코드에는 Rejected된 Promise의 오류가 포함되어 있어 호출자가 사용자에게 적절한 오류 메시지를 표시할 수 있습니다.
id
로 Hero 얻어오기
HeroDetailComponent
가 Hero를 가져 오도록 HeroService
에게 요청하면, HeroService
는 모든 Hero등을 가져와서 id
가 일치하는 하나의 Hero를 필터링 합니다. 시뮬레이션에서는 문제가 없지만 실제 서버에 모든 Hero들을 물어 보는 것은 낭비입니다. 대부분의 웹 API는 api/hero/:id
(api/hero/11
와 같은) 형태로 get-by-id 요청을 지원합니다.
HeroService.getHero()
메서드를 업데이트하여 get-by-id 요청을 만든다.
src/app/hero.service.ts
|
|
이 요청은 getHeroes()
와 거의 같습니다. URL의 Hero id
는 서버가 업데이트 해야할 Hero를 식별합니다.
또한 응답의 data
는 배열이 아닌 단일 Hero 객체입니다.
getHeroes API 변경 없음
getHeroes()
와 getHero()
에 내부적으로 중요한 변경을 가했지만 public 시그니처는 변경되지 않았습니다. 두 방법 모두에서 Promise를 반환합니다. 이를 호출하는 Component를 업데이트할 필요가 없습니다.
이제 Hero을 만들고 지울 수있는 기능을 추가할 차례입니다.
Hero 상세 정보 업데이트 하기
Hero 상세보기에서 Hero의 이름을 편집 해보십시오. 입력할 때 Hero 이름이 뷰 제목에 업데이트됩니다. 그러나 뒤로 단추를 클릭하면 변경 내용이 손실됩니다.
이전에는 업데이트가 손실되지 않았습니다. 무엇이 바뀌 었을까요? 앱이 Mock Heroes 목록을 사용하면 업데이트가 단일 앱 전체 공유 목록의 Hero 개체에 직접 적용됩니다. 이제 서버에서 데이터를 가져 오는 중이므로 변경 사항을 유지하려면 서버에 다시 써야합니다.
Hero 상세 정보 저장하는 기능 추가
Hero 상세 템플릿의 끝에서 save()
라는 새로운 Component 메서드를 호출하는 click
이벤트 바인딩과 함께 save 버튼을 추가합니다.
src/app/hero-detail.component.html (save)
Hero Service update ()
메서드를 사용하여 Hero 이름의 변경을 지속시키는 save()
메서드를 추가한 다음, 이전 뷰로 Navigate합니다.
src/app/hero-detail.component.ts (save)
Hero Service에 update() 메서드 추가
update()
메서드의 전체적인 구조는 getHeroes()
와 비슷하지만 HTTP put()
를 사용하여 서버에 변경을 지속합니다.
src/app/hero.service.ts (update)
서버가 업데이트 해야하는 Hero를 식별하기 위해 Hero id
가 URL에 인코딩됩니다. put()
본문은 JSON.stringify
를 호출하여 얻은 Hero의 JSON 문자열 인코딩입니다. body의 content type(application/json
)은 요청 헤더에서 식별됩니다.
브라우저를 새로 고치고 Hero 이름을 변경하고 변경 사항을 저장한 다음 브라우저 뒤로 버튼을 클릭하십시오. 변경 사항이 지속되어야합니다.
Hero들 추가하는 기능 추가
Hero를 추가하려면 Hero의 이름이 필요합니다. 추가 버튼과 쌍을 이루는 input
엘리먼트를 사용할 수 있습니다.
Hero Component HTML에 제목 다음줄에 아래 내용을 추가합니다.
src/app/heroes.component.html (add)
클릭 이벤트에 응답하여 Component의 클릭 핸들러를 호출한 다음 입력 필드를 지우고 다른 이름을 사용할 준비를 합니다.
src/app/heroes.component.ts (add)
주어진 이름이 비어 있지 않으면, 핸들러는 Hero Service에 지명된 Hero의 생성을 위임한 다음, 새로운 Hero를 배열에 추가합니다.
HeroService
클래스에 create()
메서드를 구현합니다.
src/app/hero.service.ts (create)
브라우저를 새로 고침하고 Hero를 만듭니다.
Hero 삭제기능 추가
Hero 뷰의 각 Hero는 삭제 버튼이 있어야합니다.
Hero Component HTML의 반복적인 <li>
엘리먼트 다음에 아래의 버튼 엘리먼트를 추가합니다.
|
|
<li>
엘리먼트는 이제 다음과 같아야합니다.
src/app/heroes.component.html (li-element)
Component의 delete()
메서드를 호출하는 것 외에도, 삭제 버튼의 클릭 핸들러 코드는 클릭 이벤트의 전파를 중지합니다. <li>
클릭 핸들러는 사용자가 삭제할 영웅을 선택하기 때문에 트리거되기를 원하지 않습니다.
delete()
핸들러의 로직은 조금 복잡합니다.
src/app/heroes.component.ts (delete)
물론 Hero Service에 Hero 삭제를 위임하지만 Component는 여전히 디스플레이 업데이트에 대한 책임이 있습니다. 삭제된 Hero를 배열에서 제거하고 필요한 경우 선택된 Hero를 재설정합니다.
Hero 항목의 맨 오른쪽에 삭제 버튼을 배치하기 위해 다음 CSS를 추가합니다.
src/app/heroes.component.css (additions)
Hero Service에 delete() 메서드
Hero Service delete()
메서드를 추가합니다. 이 메서드는 HTTP delete ()
메서드를 사용하여 서버에서 Hero를 제거합니다.
src/app/hero.service.ts (delete)
브라우저를 새로 고치고 새로운 삭제 기능을 사용해보십시오.
Observables
각각의 Http
Service 메소드는 HTTP Response 객체의 Observable
을 반환합니다.
HeroService
는 Observable
을 Promise
로 변환하고 호출자에게 Promise를 리턴합니다. 이 절에서는 Observable
을 언제, 어떻게, 왜 직접 리턴해야 하는지를 설명합니다.
Background
Observable은 배열과 비슷한 연산자로 처리할 수있는 이벤트 스트림입니다.
Angular core는 Observable를 기본적으로 지원합니다. 개발자는 RxJS library의 연산자 및 확장 프로그램을 사용하여 지원을 확대할 수 있습니다. 곧 보게 될 것입니다.
HeroService
는 toPromise
연산자를 http.get()
의 Observable
결과에 연결 시켰습니다. 그 연산자는 Observable
을 Promise
로 변환했고 그 Promise
를 호출자에게 다시 전달했습니다.
Promise으로 전환하는 것은 종종 좋은 선택입니다. 일반적으로 http.get()
을 호출하여 단일 데이터 덩어리를 가져옵니다. 데이터를 받으면 작업이 완료됩니다. 호출 Component는 Promise의 형태로 단일 결과를 쉽게 사용할 수 있습니다.
그러나 요청이 항상 한 번만 수행되는 것은 아닙니다. 서버가 첫 번째 요청에 응답하기 전에 하나의 요청을 시작하여 취소하고 다른 요청할 수 있습니다.
request-cancel-new-request 순서는 Promise로 구현하기가 어렵지만 Observable에서는 쉽게 구현할 수 있습니다.
이름으로 검색하는 기능 추가
Tour of Hero들에 영웅 검색 기능을 추가할 예정입니다. 사용자가 검색 상자에 이름을 입력하면 해당 이름으로 필터링된 Hero에 대한 반복적인 HTTP 요청을합니다.
우선 서버의 웹 API에 검색 쿼리를 보내는 HeroSearchService
를 생성합니다.
src/app/hero-search.service.ts
HeroSearchService
에 있는 http.get()
호출은 URL에 질의 문자열이 있는데 HeroService
에 있는 것과 유사합니다.
더욱 중요한 것은 toPromise ()
를 호출하지 않는다는 것입니다. 대신 http.get()
에서 Observable을 다른 RxJS 연산자인 map ()
에 연결 한 후 응답 데이터에서 Hero를 추출합니다. RxJS 연산자 체인은 응답 처리를 쉽고 읽기 쉽게 만듭니다. discussion below about operators를 참조하십시오.
HeroSearchComponent
새로운 HeroSearchService
를 호출하는 HeroSearchComponent
를 만듭니다.
Component 템플릿은 단순한 텍스트 상자 및 일치하는 검색 결과 목록입니다.
src/app/hero-search.component.html
또한 새로운 Component에 Style을 추가하십시오.
src/app/hero-search.component.css
사용자가 검색 상자에 입력하면 keyup 이벤트 바인딩은 Component의 search()
메서드를 새 검색 상자 값으로 호출합니다.
예상대로 *ngFor
는 Component의 heroes
프로퍼티에서 Hero들을 반복합니다.
그러나 곧 보게 되겠지만 heroes
프로퍼티는 이제 Hero 배열이 아니라 Hero 배열의 Observable 프로퍼티입니다. *ngFor
는 async
Pipe(AsyncPipe
)를 통해 라우트할 때까지 Observable로 아무 것도 할 수 없습니다. async
Pipe Observable
을 Subscribe하고 Heroes들의 배열을 *ngFor
로 Produces 합니다.
HeroSearchComponent
클래스 및 메타 데이터를 만듭니다.
src/app/hero-search.component.ts
|
|
검색어
searchTerms
에 중점을 둡니다.
|
|
Subject
는 Observable 이벤트 스트림의 생성자입니다. searchTerms
는 이름 검색을 위한 필터 기준인 문자열 Observable을 생성합니다.
search()
를 호출할 때마다 next()
를 호출하여 이 subject의 Observable 스트림에 새로운 문자열을 넣습니다.
heroes property (ngOnInit) 초기화하기
Subject
는 또한 Observable
입니다. 검색 용어의 스트림을 Hero 배열의 스트림으로 변환하고 그 결과를 heroes
프로퍼티에 지정할 수 있습니다.
|
|
HeroSearchService
에 직접 모든 사용자 키 스트로크를 전달하면 과도한 양의 HTTP 요청이 생성되어 서버 리소스를 부담시키거나 셀룰러 네트워크 데이터가 많아질 것입니다.
대신 Observable
연산자를 연결하여 Observable
문자열에 대한 요청 흐름을 줄일 수 있습니다. HeroSearchService
에 대한 호출 횟수를 줄이고 적절한 시간에 결과를 얻습니다. 방법은 다음과 같습니다.
debounceTime(300)
은 새로운 문자열 이벤트의 흐름이 300 밀리초 동안 일시 중지 될 때까지 기다린 후 최신 문자열을 전달합니다. 300ms보다 자주 요청을하지 않습니다.distinctUntilChanged
는 필터 텍스트가 변경된 경우에만 요청을 보냅니다.switchMap()
은debounce
및distinctUntilChanged
를 통해 검색하는 각 검색어에 대해 검색 서비스를 호출합니다. 이전 검색 관측 값을 취소하고 파기하며 Observable 최신 검색 서비스만 반환합니다.
switchMap 연산자 (이전에는
flatMapLatest
라고 함)를 사용하여 모든 규정 키 이벤트가http()
메서드 호출을 트리거할 수 있습니다. 요청간에 300ms의 일시 중지가 있더라도 여러 개의 HTTP 요청을 보낼 수 있으며 전송된 순서대로 반환하지 않을 수 있습니다.
switchMap()
은 가장 최근의http
메서드 호출에서 Observable만 리턴하면서 원래 요청 순서를 보존합니다. 이전 호출의 결과는 취소되고 폐기됩니다.검색 텍스트가 비어 있으면
http()
메서드 호출도 일단락되고 빈 배열을 포함하는 Observable이 반환됩니다.서비스가 해당 기능을 지원할 때까지
HeroSearchService
Observable을 취소한다고 해서 보류중인 HTTP 요청이 실제로 중단되지는 않습니다. 지금은 원치 않는 결과는 무시됩니다.
catch
는 실패한 Observable 항목을 차단합니다. 간단한 예제는 콘솔에 오류를 인쇄합니다. 실제 응용 프로그램이 더 잘할 것입니다. 그런 다음 검색 결과를 지우려면 빈 배열을 포함하는 Observable 객체를 반환합니다.
RxJS 연산자 Import
대부분의 RxJS 연산자는 Angular 기반 Observable
구현에 포함되지 않습니다. 기본 구현에는 Angular 자체에서 필요한 것만 포함됩니다.
더 많은 RxJS 기능이 필요하면 정의된 라이브러리를 가져 와서 Observable
을 확장하십시오. 이 Component에 필요한 모든 RxJS import
는 다음과 같습니다.
src/app/hero-search.component.ts (rxjs imports)
가져 오기 rxjs/add/...
구문이 익숙하지 않을 수 있습니다. 중괄호 사이에 일반적인 심볼 목록이 없습니다. {...}
.
연산자 심볼 자체는 필요하지 않습니다. 각각의 경우에, 라이브러리를 임포트하는 단순한 행위는 라이브러리의 스크립트 파일을 로드하고 실행 시켜서, 연산자를 Observable 클래스에 추가합니다.
Search Component를 Dashboard에 추가하기
Hero 검색 HTML 엘리먼트를 DashboardComponent
템플리트의 맨 아래에 추가합니다.
src/app/dashboard.component.html
|
|
마지막으로 hero-search.component.ts
에서 HeroSearchComponent
를 import
하고 declarations
배열에 추가합니다.
src/app/app.module.ts (search)
앱을 다시 실행합니다. 대시 보드에서 검색 상자에 텍스트를 입력합니다. 기존의 Hero 이름과 일치하는 문자를 입력하면 다음과 같은 메시지가 표시됩니다.
앱 구조와 코드
이 예제 페이지의 라이브 예제/예제 다운로드에서 샘플 소스 코드를 확인하십시오. 그리고 다음과 같은 구조인지 확인하십시오.
|
|
Home Stretch
당신의 여행이 끝나고 많은 것을 성취했습니다.
- 앱에서 HTTP를 사용하기 위해 필요한 의존성을 추가했습니다.
HeroService
를 리팩토링하여 웹 API에서 Hero를 로드했습니다.post()
,put()
및delete()
메소드를 지원하도록HeroService
를 확장했습니다.- Hero를 추가, 편집 및 삭제할 수 있도록 Component를 업데이트했습니다.
- in-memory 웹 API를 구성했습니다.
- Observable 사용법을 배웠습니다.
이 페이지에서 추가하거나 변경 한 파일은 다음과 같습니다.
Next step
이것으로 “Tour of Heroes”튜토리얼을 마칩니다. 이제 Angular 개발에 대해 자세히 배울 준비가되었습니다. Architecture 가이드부터 시작하세요.
이 내용은 나중에 참고하기 위해 제가 공부하며 정리한 내용입니다.
의역, 오역, 직역이 있을 수 있음을 알려드립니다.
This post is a translation of this original article [https://angular.io/tutorial/toh-pt6]