Node.jsの基礎（データの送受信）

https://qiita.com/hiro949/items/8f992bdafa8f90828b62

の続きです。

# http通信

```app.js
const http = require('http');
const server = http.createServer((req,res)=>{
    res.write('Hello world from nodejs');
    res.end();
});

server.listen('3000');
```

```
node app
```

でこれを実行し、ブラウザ(chromeやedgeなど)のurl検索欄で

```
localhost:3000
```

と検索すると、ブラウザに次の画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/f353185c-8268-ef86-79eb-c5518460979a.png)

なお、app.jsはずっと実行しっぱなしになっていると思うので、終わったらctrl+cで中断しておきます（以下の操作でも同様）。

# htmlファイルの表示

app.jsと同じディレクトリにstaticというフォルダを用意して、次のhtmlファイルを入れます：

```static/index.html
Test HTML file 
```

実行するJavascriptファイルは次のものです：

```app.js
const http = require('http');
const fs = require('fs');
http.createServer((req,res)=>{
    //output html file
    const readStream = fs.createReadStream('./static/index.html');
    res.writeHead(200,{'Content-type':'text/html'});
    readStream.pipe(res);
}).listen('3000');
```

実行してlocalhost:3000を更新すると、ブラウザに

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/c17377a1-d234-2209-3a08-c443c7012afb.png)

と表示されます。


# フレームワークexpressの利用

コマンドプロンプトで

```
npm init --yes
npm install express
```

と打ち込んで、フレームワークの１つであるexpressパッケージをインストールします。以下、このフレームワークを使います。

Javascriptファイルに

```app.js
const express = require('express');
```

と書けば、このobjectにexpressの中身が入っています。

## get通信(urlから変数を読み込む)

```app.js
const express = require('express');
const app = express();

app.get('/',(req,res)=>{
    res.send('Hello World');
});

app.get('/example',(req,res)=>{
    res.send('hitting example route');
});

// :name & :age in url are read as req.params
//?xxx = yyy&zzz=www in url is pushed into req.query by json style
app.get('/example/:name/:age',(req,res)=>{
    console.log(req.params); //読み込んだパラメーターをターミナルに表示
    console.log(req.query); 　//読み込んだクエリをターミナルに表示
    res.send(req.params.name + " : " + req.params.age);
});

app.listen(3000);

```

実行して、ブラウザで、例えば

```
localhost:3000
```

と検索すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/39d71e2d-f80c-7c51-f54c-7a8a4c8f7cfd.png)


```
localhost:3000/example
```

と検索すると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/b49e2947-cfb0-9533-6ecf-807973116032.png)

とブラウザに表示されます。

また、

```
localhost:3000/pedro/99
```

では、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/46f60c12-6999-15e7-0ee0-ad2e53c8e345.png)

となり、ターミナルには

```
{ name: 'predro', age: '99' }
```

と出力されます。最後に

```
http://localhost:3000/example/predro/99?tutorial=paramstutorial&sort=byage
```

で検索すると、ブラウザではひとつ前のものと同じ出力ですが、ターミナルでは

```
{ name: 'predro', age: '99' }
{ tutorial: 'paramstutorial', sort: 'byage' }
```

が出力されます。１行目はreq.params、２行目はreq.queryの中身です。

つまり:xxxの中身はreq.paramsに、?の後の等式はreq.queryにjson形式で格納されます。

## htmlファイルの呼び出し

最初のhttp通信のセクションでつかったindex.htmlを使います。

```app.js
const express = require('express');
const path = require('path')
const app = express();
app.use('/public',express.static(path.join(__dirname,'static')));

app.get('/',(req,res)=>{
    res.sendFile(path.join(__dirname,'static','index.html'));
});

app.listen(3000);

```

```
localhost:3000
```

で検索すると、http通信のときと同じ画面が出力されます。

## post通信(ユーザーが入力したものを読み込む)

### パッケージの読み込み
コマンドプロンプトで

```
npm install body-parser
```

と打って、body-parserも読み込んでおきます。

### htmlファイル

ユーザーが入力できるようなフォームを表示するようにstatic/index.htmlを書き直します。今回はメアドとパスワードを入力してもらいます。今回の話のメインはnode.jsなので、htmlの書き方については触れません。

```index.html
<form action="/" method="POST">
    <div clas="form-group">
        <label for="email">Email adress:</label>
        <input type="email" class="form-control" name="email">
    </div>
    <div clas="form-group">
        <label for="pwd">Password:</label>
        <input type="password" class="form-control" name="pasword">
    </div>
    <button type="submit" class="btn btn-default"> Submit</button>
</form>
```

### API

```app.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const app = express();

app.use('/public',express.static(path.join(__dirname,'static')));
app.use(bodyParser.urlencoded({extended:false}));

app.get('/',(req,res)=>{
    res.sendFile(path.join(__dirname,'static','index.html'));
});

app.post('/',(req,res)=>{
    console.log(req.body);
    //database work here
    res.send('successfully posted data');
});

app.listen(3000);
```

これを実行してlocalhost:3000を見ると以下のようなフォームが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/c7c378d9-aa38-849b-44f8-2364134cf39b.png)

適当にメアドの欄にはaaa@gmail.com、パスワードの欄にはbbbbbbbbと打ちました。
次にsubmitボタンをクリックすると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/46b65c22-4131-be1c-c19d-0ca35662dbad.png)

と画面が切り替わり、以下のようにちゃんと入力した内容がreq.bodyとして読み込まれてターミナルに出力されています。

```
[Object: null prototype] {
  email: 'aaa@gmail.com',
  pasword: 'bbbbbbbb'
}

```

## 読み込んだ内容の条件判定

### パッケージのインストール

```
npm install joi
```

### API

index.htmlは先ほどのpost通信のものを使い、postで読み込んだデータが設定した条件を満たすか判定します。

```app.js
const express = require('express');
const express = require('express');
const path = require('path');
const Joi = require('joi');
const bodyParser = require('body-parser');
const app = express();

app.use('/public',express.static(path.join(__dirname,'static')));
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());

app.get('/',(req,res)=>{
    res.sendFile(path.join(__dirname,'static','index.html'));
});

app.post('/',(req,res)=>{
    console.log(req.body);
    //set conditions of res.params
    const schema = Joi.object().keys({
        email : Joi.string().trim().email().required(),
        password : Joi.string().min(5).max(10).required()
    });
    //check conditions
    const validation = schema.validate(req.body);
    if(validation.error){
        console.log(validation.error);
        res.send('an error has occurred');
    }
    else res.send('successfully posted data');
});

app.listen(3000);

```

実行したのち、localhost:3000のフォームで、

メアド：aaa@gmail.com
パスワード：bbbbbbbb

を入力してsubmitボタンを押すと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/89f6229a-128c-4e14-36f2-bff539de946b.png)

がブラウザに表示され、ターミナルでも

```
[Object: null prototype] {
  email: 'aaa@gmail.com',
  password: 'bbbbbbbb'
}

```

となっています。

一方、

メアド：aaa@gmail.com
パスワード：c

としてsubmitボタンを押すと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/fefe6389-8bb5-073b-c3d2-7a26b8dbf3ad.png)

がブラウザに表示され、ターミナルでは

```
[Error [ValidationError]: "password" length must be at least 5 characters long] {
  _original: [Object: null prototype] { email: 'aaa@gmail.com', password: 'c' },
  details: [
    {
      message: '"password" length must be at least 5 characters long',
      path: [Array],
      type: 'string.min',
      context: [Object]
    }
  ]
}

```

が出力されます。今回の条件はパスワードが５文字以上、10文字以下というものです。これに引っかかっったため、if文でエラー発生時の分岐の処理がされました。

### 注意点

参考にしたyoutubeの動画ではschema.validateではなく

```wrong.js
Joi.validate(req.body,schema)
```

を使用していましたが、このメンバ関数は最新版(2022.9.現在)のnode.jsでは廃止されていて使えません。

### 配列の条件判定

入力が配列の場合です。面倒なので、サンプルの入力をapp.js内できめてしまいました。だから、node appを実行するだけで結果がターミナルに出力されます。

```app.js
const express = require('express');
const path = require('path');
const Joi = require('joi');

const arrayString = ['banana','bacon','cheese'];

const userInput = { personalInfo: {
        streetAdress: '123456789',
        city: 'abrakatabra',
        state: 'fl'
    },
    preferences : arrayString
};

const personalInfoSchema = Joi.object().keys({
    streetAdress : Joi.string().trim().required(),
    city : Joi.string().trim().required(),
    state : Joi.string().trim().length(2).required()
});

const preferencesSchema = Joi.array().items(Joi.string());

const schema = Joi.object().keys({
    personalInfo : personalInfoSchema,
    preferences : preferencesSchema
});
```

### objectの条件判定

```app2.js
const Joi = require('joi');

const arrayObject = [{example : 'example1'},{example : 'example2'},{example : 'example3'}];

const userInput = { personalInfo: {
        streetAdress: '123456789',
        city: 'abrakatabra',
        state: 'fl'
    },
    preferences : arrayObject
};

const personalInfoSchema = Joi.object().keys({
    streetAdress : Joi.string().trim().required(),
    city : Joi.string().trim().required(),
    state : Joi.string().trim().length(2).required()
});

const preferencesSchema = Joi.array().items(Joi.object().keys({
    example : Joi.string().required()
}));

const schema = Joi.object().keys({
    personalInfo : personalInfoSchema,
    preferences : preferencesSchema
});

const validation = schema.validate(userInput);
if(validation.error){
    console.log(validation.error);
}
else{
    console.log(arrayObject);
}
```

## ルーティング
別のjavascriptコードに飛ぶ方法です。ここでは/peopleに飛びたいと思います。このurlで実行するpeople.jsをroutesというフォルダに入れておきます。

```app.js
//npm init --yes
//npm install express

const express = require('express');
const path = require('path')
const app = express();

app.use('/public',express.static(path.join(__dirname,'static'))); 

const people = require('./routes/people');

app.use('/people',people);

app.listen(3000);
```

```routes/people.js
const express = require('express');
const route = express.Router();

route.get('/',(req,res)=>{
    res.send('/ bein hit');
});

route.get('/example',(req,res)=>{
    res.send('/example bein hit');
});

module.exports = route;
```

app.jsを実行して、ブラウザで

```
localhost:3000/people
```

に飛ぶと、次のように出力され、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/d7a3e5aa-8e2f-fd3e-64c5-3cbc03706d38.png)


```
localhost:3000/people/example
```

に飛ぶと、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2445529/8c0575fe-1b08-bf37-b0b4-3acc29aabd08.png)

が出力されるので、ちゃんとpeople.jsが起動しています。

# 参考記事
- https://nodejs.org/ja/
- https://www.youtube.com/watch?v=RLtyhwFtXQA&list=PLdYSLVEeET--X4dFLv8os6M2V3J2rq97V&index=1&t=3457s&ab_channel=freeCodeCamp.org