第7回：ニュースフィード取得サーバIFを作る

[目次：Webアプリ開発ロードマップ](https://qiita.com/radiance1104/private/7c5b04ce4cf8ec7bd708)
# 第7回：ニュースフィード取得サーバIFを作る

今回はバックエンドにREST APIを実装していきます。
まずニュースフィードのIFを取得するGET /newsfeedsを作成します。

## REST APIのモジュールを利用する

REST APIのクライアント側、サーバ側の実装は在り物のモジュールを利用するのが一般的です。
OSSに色々なモジュールがありますが、今回はexpressを利用します。
下記のコマンドでバックエンドにexpressモジュールをインストールします。

```
$ npm install express
$ npm install @types/express
```

REST APIを処理するためのファイルをapp/rest.tsとして用意します。
下記のように空のクラスを作成してください。

```
export class Rest {
  constructor() {
  }

  start() {
    console.log('start()');
  }

  stop() {
  }
}
```

main.tsからRestクラスのstart()を呼び出します。
main.tsの内容を下記のように書き換えてください。

```
import {Rest} from './rest';

const rest = new Rest();
rest.start();
```

実行すると、下記のログが出力され、Restクラスのstart()メソッドが呼び出されていることが確認できます。

```
$ npm start
> tsc && node build/main.js

start()
```

## ニュースフィードの取得IFを作成する

### Expressを初期化する

下記のようにapp/rest.tsを書き換えます。

```
import * as core from "express-serve-static-core";
import * as http from "http";
import express = require('express');
import bodyParser = require('body-parser');

export class Rest {
  app: core.Express;
  server: http.Server;

  constructor() {
  }

  start() {
    const app = express();
    app.use(bodyParser.urlencoded({extended: true}));
    app.use(bodyParser.json());
    this.server = app.listen(4300, () => {
      console.log('listening to port: 4300');
    });

    app.use((request, response, next) => {
      response.header('Access-Control-Allow-Origin', '*');
      response.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
      response.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
    });
  }

  stop() {
  }
}
```

実行すると下記のログが出力され、REST APIの待ち受けが開始されます。

```
listening to port: 4300
```
一つずつ解説します。

```
    const app = express();
```
ここでexpressを生成しています。

```
    app.use(bodyParser.urlencoded({extended: true}));
    app.use(bodyParser.json());
```
生成したexpressに、利用するボディパーサーを登録しています。
HTTPプロトコルはテキストデータをやりとりしますが、ボディパーサーを利用することで、
テキスト→JSONへ自動変換され、プログラム上ではJSONオブジェクトとして扱うことができるようになります。

```
    this.server = app.listen(4300, () => {
      console.log('listening to port: 4300');
    });
```
ここでサーバの待ち受けを開始しています。4300はポート番号です。
[wiki](https://ja.wikipedia.org/wiki/TCP%E3%82%84UDP%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7%E3%81%AE%E4%B8%80%E8%A6%A7)などで空いているポート番号を調べて利用しましょう。
`() => {}`の部分は、サーバの待ち受けが開始したタイミングで呼び出されます。

### ラムダ式について

先ほどの`() => {}`はラムダ式と呼ばれます。関数をクロージャ登録するときに利用されます。
以前は`function() {}`形式で書いていましたが、簡略化するため上記の記法が利用できるようになりました。
クロージャとは、呼び出し先のモジュールにイベントを通知してもらうための仕組みです。
いつ呼ばれるかはモジュール次第なのでモジュールの仕様を確認しましょう。
目的の処理が完了したタイミングで呼ばれることが多いです。

`app.listen()`のクロージャはサーバの待ち受けが開始したタイミングで呼び出されます。
`rest.ts`はサーバの待ち受けが開始したタイミングで動く処理を実装することができます。

### 環境変数ファイルを作成する
`environment.ts`を下記の内容で作成します。

```
export const environment = {
  restServer: {
    port: 4300
  }
}
```
`app/rest.ts`に修正を加えます。

```
・・・
import bodyParser = require('body-parser');
import {environment} from '../environment';

export class Rest {
・・・
    this.server = app.listen(environment.restServer.port, () => {
      console.log(`listening to port: ${environment.restServer.port}`);
    });
・・・
```
環境変数ファイルを利用することで、作成したプログラムのユーザは環境に合わせて何を書き換えればいいかわかるため、使い勝手がよくなります。

### ニュースフィードの一覧を取得するAPIを登録する

下記のように`app/rest.ts`を修正し、expressに`GET /newsfeeds`を追加します。

```
    });

    app.get('/newsfeeds', (request, response, next) => {
      try {
        const newsfeeds = [
          {
            message: 'あけましておめでとう！',
            createdAt: new Date('2020-01-01T02:23:30'),
          },
          {
            message: 'メリークリスマス！',
            createdAt: new Date('2019-12-25T10:52:02'),
          },
          {
            message: 'ハッピーハロウィーン！',
            createdAt: new Date('2019-10-31T20:13:55'),
          },
        ];
        response.send(newsfeeds);
      } catch (error) {
        response.sendStatus(500);
      }
    });
  }

  stop() {
```
`app.get()`で登録したクロージャは`GET /newsfeeds`を受信した時に呼び出されます。

## 作成したIFをクライアントから呼んでみる
RESTクライアントソフトを使って、作成した`GET /newsfeeds`を呼び出してみます。

### Postmanをインストール
RESTクライアントソフトは今回は[Postman](https://www.postman.com/)を利用します。
公式サイトからインストールしてください。
無料アカウント登録し、サインインすると画像のダイアログが表示されるので、`Download desktop agent`からデスクトップアプリをインストールしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202428/6e96b3cb-a029-34e8-257a-cc62f94291f3.png)

### PostmanでサーバIFを呼んでみる
画像のように`GET http://127.0.0.1:4300/newsfeeds`を作成し送信するとレスポンスが受信できていることが確認できます。
1) 画面上部のタブ(＋)をクリックし、新規のタブを追加します。
2) メソッドにGETを選択します。
3) request URLに`http://127.0.0.1:4200/newsfeeds`を入力します。
4) Sendボタンをクリックします。
![スクリーンショット 2020-09-22 16.23.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202428/a74b6531-bf6a-4200-f902-a79b14217671.png)


## REST APIについて

最後に簡単にREST APIについて説明します。

```
GET http://xxxx.com/newsfeeds/{id}?a=1&b=2
```

### プロトコル
`http://`の部分をプロトコルと言います。クライアント-サーバ間での通信方式を指定することができます。
プロトコルは通信のデータフォーマットや遣り取りを行うシーケンスの方式などが規定されています。
仕様はRFCに記載されているので詳しくはそちらを参照しましょう。

`http`は暗号化しないHTTPでの通信で、`https`は暗号化するHTTPでの通信です。
一般的には`https`を利用しますが、証明書を作成する必要があるので今回は割愛しました。
REST APIで利用するのは`http`, `https`の二種類ですが、
プロトコルとしては他にファイルを遣り取りする`ftp/ftps`、メールを送信する`smtp`など様々なものがあります。

### ドメイン
`xxxx.com`の部分をドメインと言います。ドメインはコンピュータへたどり着くための場所を示します。
コンピュータはまず最初にDNS(Domain Name System)というサーバへ通信し、`xxxx.com`に対応しているIPアドレスを問い合わせます。次にそのIPアドレスへ通信を行います。
コマンドラインでDNSへの問い合わせを行うこともできます。

```
$ nslookup xxxx.com
```

### パス
`/newsfeeds/{id}`の部分をパスと言います。
パスは、データへのパスを示します。
また、複数形・単数形の名詞で返すデータの種類を示します。

* GET /newsfeeds: newsfeedの一覧を返す
* GET /newsfeeds/{id}: 複数あるnewsfeedのうちの一つの詳細を返す

#### パスパラメータ
`/{id}`の部分をパスパラメータと呼びます。
左のパスに書かれている`/newsfeeds`の中の一つのnewsfeedを指定するためのidを渡すことができます。

### クエリパラメータ
`?a=1&b=2`の部分をクエリパラメータと呼びます。
`?`はパスとの区切り文字、`&`は複数のクエリパラメータの区切り文字として利用します。
`a=1`でaというパラメータに1を設定していることになります。
主に取得するデータが複数ある場合に、フィルタをかける役割で利用します。

### リクエストボディ

POSTメソッドやPUTメソッドではリクエストボディを設定することができます。
POST /newsfeedsとして場合、リクエストボディには投稿する記事のデータを設定することになります。
リクエストボディには一つの種類のデータを入れることができ、REST APIではJSONオブジェクトを送信することが多いです。
ボディに指定しているデータの種類を指定する`Content-Type`やMIME-Typeはまたの機会に記載します。

### メソッド
| メソッド | 説明 |
| --- | --- |
| GET | パスやクエリで指定したデータを取得します。 |
| POST | パスで指定したデータを新規追加します。 |
| PUT | パスで指定したデータを変更します。 |
| DELETE | パスで指定したデータを削除します。 |

## 最後に
今回はREST APIのGETを一つ作成してみました。
次回はフロントエンドからこのAPIを呼び出してみます。
今回開発したソースコードは[GitHub](https://github.com/radiance1104/web-learning-loadmap/tree/create-get-newsfeeds)に入っています。