nodejsを使ってウエブサーバーを作ろう - majidai

[![Build Status](https://travis-ci.com/dakc/majidai.svg?branch=develop)](https://travis-ci.com/dakc/majidai)[![npm](https://img.shields.io/npm/v/majidai.svg?id=2&ver=2)](https://www.npmjs.com/package/majidai)[![GitHub license](https://img.shields.io/github/license/dakc/majidai.svg?style=popout)](https://github.com/dakc/majidai/blob/master/LICENSE)
# majidaiとは
majidaiとは、nodejs用のWebフレームワークです。 
サードパーティーライブラリが使っていないため非常に軽いです。
<font color="red">データ量 < 50KB</font>


以下の経緯があり「majidai」を開発しました。

- 勝手にインストールされるライブラリを避けたかった
- GET、POST（application/json, form-data,...)など方法が違っても同じやり方でデータへアクセスしたかった
- 設定ファイルによってサーバー機能を制限したかった（DEVモードやPRODモード）
- 簡単に静的ファイルを配信したかった
- レスポンスをシンプルにしたかった

# インストール
[nodejs](https://nodejs.org/en/download/)のインストールはこの記事のスコープ外とします。
##### 1. プロジェクトの初期化
タミナルから作業フォルダーに移動し、プロジェクトの初期化を行います。

```bash
npm init -y
```

##### 2. majidaiインストール
以下のコマンドで「majidai」をインストールします。

```bash
npm install majidai
```

##### 3. サーバーコード
まずは、「server.js」ファイルを作成し、以下のコードを貼り付けます。

```server.js
// majidaiの読み込み
const majidai = require("majidai");

// インスタンス化
const server = new majidai();

// 受付開始
server.start();
```

##### 4. serverの起動
以下のコマンドでウエブサーバーの起動します。

```bash
node server.js
```
そして、ブラウザを起動し、localhost　にアクセスします。以下の画面が表示されればOKです。
<img src="https://raw.githubusercontent.com/dakc/dakc.github.io/master/assets/img/toppage.png" width="200px">

>デフォルトでは80ポートで受け付けしますが、以下のようにポートを指定する事が可能です。

```js
const config = {
    http: {
        port: 8000
    }
};
const server = new majidai(config);
```

1～4の処理をまとめた画像を用意しました。
<img src="https://pbs.twimg.com/media/EcU7LGGXgAcE_Vk?format=png&name=4096x4096" width="">
3行目がリクエスト情報をコンソールに出力するためのコードです。majidaiは2種類のイベントを発します。

- stdout - クライアント情報(JSONオブジェクト)
- stderr - エラー内容

# 応用編

#### 書き方
majidaiの書き方は以下の以下の通りです。

```js
server.METHOD(PATH, CALLBACK)
```
##### METHODとは
以下の３種類があります。
- get : http GETリクエストのみ受け付けます
- post : http POSTリクエストのみ受け付けま
- listen :複数のhttpメソッドを一つのPATHで受け付けます
※詳細については[こちら](https://dakc.github.io/majidai.html)

##### PATHとは
"/" , "/top", "/user/dakc",..みたいにどこでリクエストを受け付けるかの事です。

##### CALLBACKとは
これはコールバック関数の事です。指定のPATHにリクエストを受け付けたら、この関数が実行されます。関数の引数が以下の2つです。
- request : [&lt;http.IncomingMessage>](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
- response : [&lt;http.ServerResponse>](https://nodejs.org/api/http.html#http_class_http_serverresponse)
majidaiが両方のオブジェクトに「mj」オブジェクトを追加します。

###### request.mj
requestに追加したmjオブジェクトがクライアントから送られて来たデータを操作するために以下の2つの関数(メソッド）を有します。

- getParams : GETで送られて来た情報をJSONオブジェクトとして返します。キーを引数として指定することで特定のキーに対する値のみを取得する事が可能です。
- postParams: POSTで送られて来た情報をJSONオブジェクトとして返します。キーを引数として指定することで特定のキーに対する値のみを取得する事が可能です。<font color="red">※x-www-form-urlencoded, application/json, form-data</font>どれでデータが送られて来てもJSONオブジェクトとして返します。

###### response.mj
クライアントにレスポンスを返すために以下のメソッドを有します。

- text : plain/textとしてレスポンス
- json : application/jsonとしてレスポンス
- static : 静的コンテンツのレスポンス 
- redirect : 別のURLへリダイレクト
- error : HTTPエラーとしてレスポンス

※ 詳細については[こちら](https://dakc.github.io/majidai.html?#response_plainText)

# samples
サンプルを見ながらどのようなことできるかやってみましょう！
コード内のコメントも読んでもらいたいです。

##### 1. GET受付
```get-sample.js
const server = new majidai();

server.get("/home", (request,response) => {
    // リクエストがhttp://〇〇/home?price=230)
    var price = request.mj.getParams("price");
    console.log(price);
    // 230
    
    // OR
    // 全データをJsonオブジェクトとして取得
    var getData = request.mj.getParams();
    console.log(getData);
    // { price: '230' }
    
    // 「price」の値を取得
    var price_ = getData.price;
    console.log(price);
    // 230


    return "ここで返すものがクライアントへのレスポンスになります";
});

server.start();
```

##### 2. POST受付
```post-sample.js
const server = new majidai();

server.post("/login", (request,response) => {
    // リクエストがhttp://〇〇/login
    // <form action="/login" method="POST">
    //   <input name="id" type="text" value="abc">
    //   <input name="pass" type="password" value="p@ss">
    // </form>

    // 「id」の値を取得
    var id= request.mj.postParams("id");
    console.log(id);
    // abc
    
    // OR
    // 全データをJsonオブジェクトとして取得
    var postData = request.mj.postParams();
    console.log(postData);
    // { id: 'abc', pass: 'p@ass' }
    
    // 「id」の値を取得
    var id_ = postData.id;
    console.log(id_);
    // abc


    return "ここで返すものがクライアントへのレスポンスになります";
});

server.start();
```

##### 3. 複数HTTPメソッド受付

```multiple-methods.js
const server = new majidai();

server.listen({ method: ["GET", "POST"], path: "/profile" }, (request, response) => {
    // GETでもPOSTでもこのの処理を実行されます。
    // DO SOMETHING

    return "something";
});

server.start();
```

#### Parameterized URL
どのような表現が分かりやすいかよくわからなかったため、上記の表記にしました。ごめんなさい。何か気付くところがありましたら是非コメントに残してやってください。
>この機能がどうしても実現したかった機能です。
「http://〇〇/user?id=abdf&command=edit」より
「http://〇〇/user/abdf/edit」
のほうが好きだったからです。

```parameterized-url.js
// {}の中のものがその名前のキーでデータを取得する事ができます。
server.get("/books/{year}/{price}", function (req, res) {
    // リクエストがhttp://〇〇/books/2020/5000

    // {}の中のものがその名前のキーでデータを取得する事ができます。
    // 「year」の値を取得
    var year = req.mj.getParams("year");
    console.log(year );
    // 2020

    // 「price」の値を取得
    var price= req.mj.getParams("price");
    console.log(price);
    // 5000

    // GETと受けたものをレスポンスとして返す
    return req.mj.getParams();
});
```
<font color="red">※post,listenの時もParameterizedURL機能が使えます。</font>

# 静的コンテンツ配信
デフォルトでは静的コンテンツの配信が無効にしてますが、以下のように「Document Root」指定する事で指定のフォルダーは以下のものを配信する事が可能です。

```js
const config = {
    http: {
        documentRoot: './public'
    }
};
const server = new majidai(config);
````

# Docker
以下の１行のコマンドを実行する事でブラウザーからmajidaiの動作を確認できます。

```bash
docker run -it --rm -p 80:80 dakc/majidai npx /data/server.js
```

# 最後に
nodejsの標準の機能のみで動く軽量なフレームワークを欲しかったため、majidaiを開発しました。MITライセンスでリリースしておりますのでご自由にお使いください。

DOCUMENTATION - https://dakc.github.io/majidai.html