제8회: 뉴스 피드 취득 서버 IF를 웹 앱에서 호출

7825 단어 Angular
목차: 웹 앱 개발 로드맵

제8회: 뉴스 피드 취득 서버 IF를 웹 앱에서 호출



이번에는 이전에 작성한 뉴스 피드 목록 취득 IF를 프런트 엔드에서 호출해 보겠습니다.

REST API 조작을 위한 서비스 작성



빈 서비스 만들기



프런트 엔드에서 REST API를 처리하는 서비스를 만듭니다.
다음 명령을 실행합니다.
$ ng g service services/rest/rest
rest.service.ts 및 테스트 코드 rest.service.spec.ts가 만들어집니다.


모듈에서 만든 서비스 로드


src/app/app.module.ts에서 다음을 수정하여 앱에 service를 로드합니다.
・・・
import { RestService } from './services/rest/rest.service';
・・・
  providers: [
    RestService
  ],
・・・

REST API의 응답 데이터를 수신하기 위한 데이터 클래스 작성



뉴스피드용 데이터 클래스 만들기


src/app/services/rest/data/newsfeeds.ts를 다음과 같이 새로 작성합니다.
뉴스피드의 데이터를 갖게 하기 위한 데이터 클래스입니다.
export class Newsfeed {
  message: string;
  createdAt: Date;

  decode(json: any) {
    if (json) {
      this.message = json.message;
      this.createdAt = json.createdAt ? new Date(json.createdAt) : undefined;
    }
  }
}

export class Newsfeeds {
  private sortedByDefault: Newsfeed[] = [];
  newsfeeds: Newsfeed[];

  decode(json: any) {
    if (json) {
      for (const jsonNewsfeed of json) {
        const newsfeed = new Newsfeed();
        newsfeed.decode(jsonNewsfeed);
        this.sortedByDefault.push(newsfeed);
      }
      this.sortByCreatedAt();
    }
  }

  sortByCreatedAt() {
    this.newsfeeds = this.sortedByDefault.slice();
    this.newsfeeds.sort((a, b) => {
      return b.createdAt.getTime() - a.createdAt.getTime();
    });
  }
}

JSON 객체로부터 데이터를 꺼내, 내부에 보관 유지시키는 decode 메소드나,
일시로 초기 소트를 실시하는 sortByCreatedAt() 메소드를 갖게 하고 있습니다.

응답 데이터 공통 데이터 클래스 만들기


src/app/services/rest/data/response.ts를 다음과 같이 새로 작성합니다.
모든 응답 데이터가 공통으로 가지는 부분을 작성합니다.
export class Response<T> {
  code: number;
  data: T;

  constructor(data: T, code?: number) {
    this.code = code ? code : 200;
    this.data = data;
  }
}

RestService에서 뉴스 피드 목록을 얻기위한 처리 구현



HttpClientModule을 모듈에 등록



RestClient에서는 HttpClient를 사용하고 싶으므로 HttpClientModule을 app.module.ts에 등록합니다.
・・・
import { HttpClientModule } from '@angular/common/http';
・・・
  imports: [
・・・
    HttpClientModule,
  ],
・・・

RestService에서 뉴스 피드 목록 검색 처리 구현


src/app/services/rest/rest.service.ts에서 뉴스 피드 목록 검색 처리를 구현합니다.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Response } from './data/response';
import { Newsfeeds } from './data/newsfeeds';

@Injectable({
  providedIn: 'root'
})
export class RestService {

  constructor(
    private httpClient: HttpClient
  ) { }

  async searchNewsFeeds(): Promise<Response<Newsfeeds>> {
    return new Promise((resolve, reject) => {
      const url = 'http://127.0.0.1:4300/newsfeeds';
      this.httpClient.get(url).toPromise().then(response => {
        const newsfeeds = new Newsfeeds();
        newsfeeds.decode(response);
        resolve(new Response(newsfeeds));
      }).catch(error => {
        console.error(error);
        reject(error);
      });
    });
  }
}

async, Promise, resolve, reject, then, catch는 비동기 처리를 수행하기 위한 것입니다.
아래를 참조하십시오.
  • 비동기 처리 Promise 정보
  • 비동기 처리 async, await 정보

  • REST API는 this.httpClient.get(url) 부분에서 호출됩니다.

    구성 요소에서 만든 RestService 사용



    TypeScript 파일을 수정합니다.


    src/app/components/newsfeeds/newsfeeds.component.ts를 다음과 같이 수정합니다.
    후술하는 html의 수정까지 실시하지 않으면 에러가 됩니다.
    import { Component, OnInit } from '@angular/core';
    import { RestService } from '../../services/rest/rest.service';
    import { Newsfeeds } from '../../services/rest/data/newsfeeds';
    
    @Component({
      selector: 'app-newsfeeds',
      templateUrl: './newsfeeds.component.html',
      styleUrls: ['./newsfeeds.component.scss']
    })
    export class NewsfeedsComponent implements OnInit {
    
      newsfeeds: Newsfeeds;
    
      constructor(
        private restService: RestService
      ) { }
    
      async ngOnInit() {
        try {
          const response = await this.restService.searchNewsFeeds();
          this.newsfeeds = response.data;
        } catch (error) {
          // TODO: display alert dialog.
        }
      }
    }
    

    Service 객체는 앱 내에서 하나만 생성됩니다.
    constructor()의 인수에 Service를 기재하는 것으로, 컴퍼넌트가 생성될 때 인수에 건네집니다.
      constructor(
        private restService: RestService
      ) { }
    

    aync, await는 비동기입니다.
    비동기 처리 async, await 정보을 참조하십시오.

    HTML 파일을 수정합니다.


    src/app/components/newsfeeds/newsfeeds.component.html를 다음과 같이 수정합니다.
    여기까지 구현하면, 화면에 백엔드로부터 취득한 데이터가 표시됩니다.
    <div id="newsfeeds">
      <ng-container *ngIf="newsfeeds && newsfeeds.newsfeeds">
        <article *ngFor="let newsfeed of newsfeeds.newsfeeds" class="newsfeed">
          <p class="message">{{newsfeed.message}}</p>
          <p class="createdAt">{{newsfeed.createdAt | dateToString}}</p>
        </article>
      </ng-container>
    </div>
    

    원래는 newsfeeds에 배열을 갖게 하고 있었지만, newsfeeds.newsfeeds에 배열을 갖게하도록 수정하고 있습니다.
    따라서 REST API에서 데이터를 받기 전에 화면을 만들려고하면 newsfeeds.newsfeeds에 참조 오류가 발생합니다.
    따라서 if 문을 추가하고 데이터가 있을 때만 표시하도록 수정하고 있습니다.
    또한 *ngIf*ngFor와 동일한 태그에 쓸 수 없으므로 <ng-container>를 추가하고 *ngIf를 수행합니다.<ng-container>는 화면에 표시되지 않는 제어용 태그입니다.

    환경 변수 이용



    환경 파일 수정


    src/app/services/rest/rest.service.ts에 서버 주소 http://127.0.0.1:4300를 직접 작성했기 때문에,
    환경 변수로 바꿉니다.src/environments/environment.prod.tssrc/environments/environment.ts에 아래의 부분을 추가합니다.
    export const environment = {
      production: true,
      rest: {
        domain: 'http://127.0.0.1:4300'
      }
    };
    
    environment.prod.ts는 프로덕션 (상용) 빌드이고 environment.ts는 개발 빌드에서 사용되는 환경 변수입니다.
    지금까지 사용해 온 빌드 명령$ ng serve이나 $ ng build는 개발용의 빌드를 실시합니다.--prod 옵션을 사용하면 프로덕션 빌드가됩니다.

    환경 변수 포함


    src/app/services/rest/rest.service.ts에 다음 수정 사항을 추가합니다.
    ・・・
    import { environment } from '../../../environments/environment';
    ・・・
      async searchNewsFeeds(): Promise<Response<Newsfeeds>> {
        return new Promise((resolve, reject) => {
          const url = environment.rest.domain + '/newsfeeds';
    ・・・
    

    마지막으로



    이번에는 프런트 엔드에서 REST API를 불러 보았습니다.
    다음 번에는 뉴스 피드 게시물에 대한 IF를 만들겠습니다.
    이번에 개발한 소스 코드는 GitHub에 들어 있습니다.

    좋은 웹페이지 즐겨찾기