【Node.js×PostgreSQL】ExpressとPostgreSQLでローカル環境のAPIサーバーを構築する

#自分の環境
・Windows10
・Docker
・Docker-composer
・Node.js 10.15.3

#やりたいこと
DockercomposerでPostgresとExpressを使用して、ローカル環境にAPIサーバーを作る。


#とりあえず、Docker-Composer書く
```yaml:docker-composer.yaml
version: '3.7'

services:
  api:
    image: 'node:12-alpine'
    volumes:
      - './:/api:cached'
    working_dir: '/api'
    environment:
      HOST: '0.0.0.0'
    ports:
      - '3000:3000'
    command: 'sh -c "npm install && npm run start"'

  db:
    image: postgres:12-alpine
    restart: always
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_USER: postgres
      POSTGRES_DB: postgres
      DATABASE_HOST: localhost
    ports: 
      - "5432:5432"
    volumes:
      - ./migration:/docker-entrypoint-initdb.d
```

# npmで必要なものをいろいろ入れる
・Express
・pg

```
npm init
npm install Express pg
```

#とりあえず、ローカルでExpressが上手く動いているか確認する
```
node index.js
```

localhost:3000にアクセスする。Hello World!って表示されたらOK！

#Expressのルーティングをいじってみる
```js:index.js
const express = require('express')
const app = express()

app.get('/', (req, res) => res.send('Hello World!'))

app.get('/user',(req, res) => res.send('Got a PUT request at /user'));
app.get('/hoge',(req, res) => res.send('ほげほげ'));

app.listen(3000, () => console.log('Example app listening on port 3000!'))

```

localhost:3000/userにアクセスしてみて、Got a Put～って書いてあればOK。
他にもルーティングを足したい時はhogeのように足していく。


#ExpressとPostgreSQLを接続させる
```js:index.js
const express = require('express')
const app = express()

const { Pool, Client } = require('pg')
const connectionString = 'postgres://postgres:postgres@db:5432/postgres'
const pool = new Pool({
  connectionString: connectionString,
})
pool.query('SELECT NOW()', (err, res) => {
  console.log(err, res)
  pool.end()
})


app.get('/', (req, res) => res.send('Hello World!'))
app.get('/user',(req, res) => res.send('Got a PUT request at /user'));

app.listen(3000, () => console.log('Example app listening on port 3000!'))
```
ログでSELECT NOW()のクエリの結果が表示されていればOK!

#マイグレーション用のSQLを作成する
今のままだと、DBに何も入っていないので、テーブル作成用のSQLを作成し、Docker-compose up時に自動でSQL文を実行させるようにする。

```sql:/migration/migration.sql
CREATE TABLE	Company	(		
    id	serial,
    name text NOT NULL,
    description	text NOT NULL,
	PRIMARY KEY (id)
);

INSERT INTO	resume(name,description) VALUES(
	'株式会社〇〇'
	'老舗のIT系の会社。人材派遣も行っている',
),		
(		
	'△△株式会社'
	'人材系の会社。自社開発は行っていない',
),		
(		
	'株式会社✖✖'
	'最近設立したばかりの伸び盛りのIT系ベンチャー企業',
);

```

こんな感じで、ファイルを作成し、docker-compose upをすると、Companyテーブルとレコードが追加されます。

実際にレコードが追加されたことを確かめるために、index.jsを修正します。

```js:index.js
const express = require('express')
const app = express()

const { Pool, Client } = require('pg')
const connectionString = 'postgres://postgres:postgres@db:5432/postgres'
const pool = new Pool({
  connectionString: connectionString,
})
pool.query('SELECT NOW()', (err, res) => {
  console.log(err, res)
  pool.end()
})

//idの箇所に数字を入れることで、パラメータを渡すことができる。company/10
//みたいな感じで渡すと、10を受け取ることができる。
//Laravelのルーティングの中に処理を書くイメージだと思われる。（本当はもっといい方法がありそう）
// app.post('/company/:id',(req,res)=> 
//     res.send(req.param('id') + "：POSTデータのお返しです！")
// );


/*
URL設計
/company⇒Companyの全件取得
/company/:id⇒Companyテーブルのidに応じたレコードの取得
*/

app.get('/company',(req, res) => 
{
    const client = new Client({
        connectionString: connectionString,
      })
      client.connect()
      client.query('SELECT * FROM Company', (err, result) => {
        res.send(result.rows);
        client.end()
    })
});


app.get('/company/:id',(req, res) => 
{
    const client = new Client({
        connectionString: connectionString,
      })
      client.connect()

      //idを使ってクエリ
      client.query({
        name: 'fetch-user',
        text: 'SELECT * FROM Company WHERE id = $1',
        values: [req.param('id')]
      }, (err, result) => {
        res.send(result.rows);
        client.end()
    })
});

app.listen(3000, () => console.log('Example app listening on port 3000!'))
```
localhost:3000/companyでテーブルの中身が全件表示されて、
localhost:3000/company/1で「株式会社〇〇」のレコードが表示されていれば成功です。
ちなみに、app.getのところを、app.postにすることもできます。

こんな感じで、Dockerを使用してExpressとPostgreSQLでの
API開発環境の構築が出来ました！！！