반응형

http.get

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

private fetchPosts() {
    this.http
      .get('https://PROJECT_NAME.firebaseio.com/posts.json')
      .subscribe(posts => {
        console.log(posts);
      });
  }

HttpClient를 이용하여, 매우 간단하게 가져올 수 있습니다.


자료 가공하기

import { map } from 'rxjs/operators';

id라는 key를 추가하여 post를 get하는 코드입니다.

private fetchPosts() {
    this.http
      .get('https://ng-complete-guide-be717.firebaseio.com/posts.json')
      .pipe(
        map(responseData => {
          const postsArray = [];
          for (const key in responseData) {
            if (responseData.hasOwnProperty(key)) {
              postsArray.push({ ...responseData[key], id: key });
            }
          }
          return postsArray;
        })
      )
      .subscribe(posts => {
        // ...
        console.log(posts);
      });
  }

get()와 subscribe()사이에 pipemap으로 변경하였습니다.

 

pipe는 앞에서 사용해 보았듯이, 

여러가지 operator로 observable 데이터를 가공(연산)할 수 있도록 합니다.

 

여기선 map Operator를 사용하였습니다.

한번더 observable로 레핑(wrapping)하는 역할입니다.

 

id는 랜덤으로 설정되는 글자이기 때문에 string으로 하였습니다.

 

결과는 캡쳐화면처럼 id의 key:value를 response에 추가해 줍니다.


Type사용하기.

export interface Post {
  title: string;
  content: string;
  id?: string; // optional 물음표 보이시죠? 있을수도 있고 없을 수도 있습니다.
}

먼저 Post를 선언합니다.

 

private fetchPosts() {
		...
      .pipe(
        map((responseData: {[key: string]: Post}) => {
          const postsArray = [];
		    ...
          return postsArray;
        })
      )
		...
  }

map의 데이터의 타입을 지정해줍니다. key는 string으로 되어있고, value는 Post로 합니다.

 

이렇게 하여 response데이터의 타입을 알려주게 됩니다.

또한 맵 안에 있는 postsArray도 타입을 지정할 수 있게됩니다.

private fetchPosts() {
		...
      .pipe(
        map((responseData: {[key: string]: Post}) => {
          const postsArray: Post[] = [];
		    ...
          return postsArray;
        })
      )
		...
  }

 

조금 더 편리한 방법은 response body의 타입을 지정해 주는 방식입니다.

private fetchPosts() {
    this.http
      .get<{[key: string]: Post}>('https://PROJECT_NAME.firebaseio.com/posts.json')
      .pipe(
        map(responseData => {
          const postsArray: Post[] = [];
          for (const key in responseData) {
            if (responseData.hasOwnProperty(key)) {
              postsArray.push({ ...responseData[key], id: key });
            }
          }
          return postsArray;
        })
      )
      .subscribe(posts => {
        // ...
        console.log(posts);
      });
  }

get에 <>를 추가하여 제네릭을 추가합니다.

따로 map과 같은 operator를 사용할 때마다 지정하지 않아도 body와 동일한 타입으로 인식합니다.


Post에도 response body 타입 지정해보기.

onCreatePost(postData: { title: string; content: string }) {
    // Send Http request
    this.http
      .post(
        'https://PROJECT_NAME.firebaseio.com/posts.json',
        postData
      )
      .subscribe(responseData => {
        console.log(responseData);
      });
  }

위와 같은 코드가 있을 경우, subscribe의

responseData는 (parameter) responseData: Object로 나타납니다.

 

 

하지만 .post<name: string> 을 추가할 경우,

onCreatePost(postData: { title: string; content: string }) {
    // Send Http request
    this.http
      .post<{name: string}>(
        'https://PROJECT_NAME.firebaseio.com/posts.json',
        postData
      )
      .subscribe(responseData => {
        console.log(responseData);
      });
  }

responseData는 (parameter) responseData: {name: string;}으로 나타납니다.


Error Handling

 

http에서 지원하는 error사용.

.subscribe(
  (posts: Post[])=> {
    this.isFetching = false;
    this.loadedPosts = posts;
  }, (error) => {
    console.log(error);
    this.error = error.message;
});

console.log(error)의 내용 입니다.

여러곳에서 에러를 다루어야할 경우, Subject를 생성합니다.

// service.ts
import { Subject} form 'rxjs';

error = new Subject<string>();

.subscribe(
	...
  },
  error => {
  	this.error.next(error.message);
  }
)

다른 곳에서 service.error.subscribe()를 통하여 에러메시지를 핸들링 할 수 있습니다.

 

catchError를 이용하여, analytics server등을 던질 수 있습니다.

import { throwError } form 'rxjs';

  ...
,
catchError(errorRes => {
	return throwError(errorRes);
});

제네릭 에러를 핸들링하는 작업이 필요할 경우 사용하면 됩니다.


Header Setting

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

.get<{ [key: string]: Post }>(
  'https://ng-complete-guide-be717.firebaseio.com/posts.json',
  {
    headers: new HttpHeaders({'Custom-Header': 'Hello'})
  }
)

hangular/common/http 에서 지원하는 HttpHeaders를 이용하면, 원하는 Header를 추가할 수 있습니다.

해더에 추가한 대로, Custom-Header에 Hello라는 key-value pair로 나오죠?


파라미터 추가하기

 

import { HttpPramas } from '@angular.common,http';

params: new HttpParams().set('print', 'pretty')
let searchParams = new HttpParams(); // multi. 파라미터 추가하기.
searchParams = searchParams.append('print', 'pretty');
searchParams = searchParams.append('custom', 'key');

javascript로 데이터 받기(data type 변경하기)

2번째 argu.에 observe를 추가합니다.

this.http
  .post<{ name: string }>(
    'https://ng-complete-guide-c56d3.firebaseio.com/posts.json',
    postData,
    {observe: 'response'}
)

tap operator

tap 연산자는 Observable을 디버깅 할 수 있도록 정확한 값이나, 다른 사이드 이팩트에 유용합니다.

Note: Observable의 측면에서 subscribe와는 다릅니다. 설령 subscribe하지 않은 Observable이 tap에 의해서 return되어도 , Observer에 의한 사이드 이팩트는 절대 발생하지 않습니다. tap은 단순히 존재하는 실행만 엿볼뿐, subscribe처럼 이벤트를 실행하지 않습니다.

 

Response body Type 변경하기

deletePosts() {
  return this.http.delete(
    'https://ng-complete-guide-c56d3.firebaseio.com/posts.json', {
    observe: 'events',
    responseType: 'json'
    }
  );
}

interceptors

모든 

// auth-intercptor.service.ts

import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';

export class AuthInterceptorService implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler) {
      console.log('Resquest in an Its way');
      return next.handle(req);
    }
}
// app.module.ts

providers: [
  {
    provide: HTTP_INTERCEPTORS, // 토큰
    useClass: AuthInterceptorService,
    multi: true
  } 
], 

Header 추가하기

intercept(req: HttpRequest<any>, next: HttpHandler) {
  console.log(req.url);
  const modifiedRequest = req.clone({headers: req.headers.append('Auth', 'xyz')})
  console.log('Resquest in an Its way');
  return next.handle(modifiedRequest);
}

로깅 인터셉터

// logging-interceptor.service.ts

import { HttpInterceptor, HttpRequest, HttpHandler, HttpEventType } from '@angular/common/http';
import { tap } from 'rxjs/operators';

export class LoggingIntercptorService implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler) {
    console.log('Outgoing request');
    console.log(req.url);
    console.log(req.headers);
    return next.handle(req).pipe(
      tap(event => {
        if (event.type === HttpEventType.Response) {
          console.log('Incoming response');
          console.log(event.body);
      }
    }));
  }
}
// app.module.ts

providers: [
    {
      provide: HTTP_INTERCEPTORS, // 토큰
      useClass: AuthInterceptorService,
      multi: true
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: LoggingIntercptorService,
      multi: true
    }
  ], 

여러개의 인터셉터를 사용할 경우에는 순서매우 중요합니다.

providers에서 Logging은 뒤쪽에 위치해야 합니다.

 

 

반응형

'프로그래밍 > Angular' 카테고리의 다른 글

Dynamic Component  (0) 2019.09.13
Authentication & Route Protection  (0) 2019.09.06
Pipe  (0) 2019.08.15
Form - 복습 및 보충 내용  (0) 2019.08.14
FormHandling - Reavice  (0) 2019.07.02

+ Recent posts