POST.body を Json形式で渡す方法[python-by.bottle]

## form内のinputタグ全てをjsonにして...
POSTは、formデータをサーバへ送信する際に活用するタグで、その中のinputタグに含まれるデータをサーバ側で受け取るのは、特に面倒だったりもする...
例えば、`<input type="text" name="id" id="id">`とか、`<input type="text" name="id" id="name">`とか...紛らわしい上に扱いづらい、そしてサーバ側の言語には予約されていたりするので、さらに変数名を安易に考えられたものについては面倒...
そこで単純に、jsonデータにして受け渡し、サーバ側でも受け取りをjson形式にする事で、加工や挿入、代入などが可能になり、処理もフロント側だけでほぼ完結したりもできる。

### 準備するもの

サーバサイド
---
 - Python3.6<=x
 - Tinydb
 - bottle

フロントエンド
---
 - javascript
 - html
 - Chrome

---

## 実際のコード
---

実際と言いつつも、実行はしていないwけど、多分、動く...
※コメント頂ければ、修正します。

これらは、ただ抜粋しただけだから動かない可能性もあるが、
ポイントを押さえておけば問題ないはず...
まずは、js側から...その次に、サーバ側の処理について...説明したいと思う。

```python3:app.py
import bottle
from bottle import request
from tinydb import TinyDB as tydb


@route("/")
def index():
    index = """
       <!DOCTYPE html>
        <html lang="ja">
          <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Post 2 Json</title>
          </head>
          <body>
               <form action="/db" method="POST" id="form_cnts" name="form_cnts" enctype="multipart/form-data">

            USER: <input type="text" name="user" id="user">
            <br>
            PASSWORD: <input type="text" name="paswd" id="paswd">
            <input type="hidden" name="secret_key" id="secret_key" value="b42c66d06dc047e191aab859429a0105">
            </form>
          <script>
             /*---------------------------------------------------- $ ---------------------------------------------------------------*/
             /** ID と Classを変換する関数
              * $('#id')
              * @param  {String} - let id_name = $('#id')
              * @return {Object} - id-tag
              */
             if (String.prototype.$ == undefined){
               $ = (x) => {
                 const idn = /^#/g
                 if (typeof x == "string") {
                   if(x.match(idn)) return document.getElementById(x.replace(idn, ""))
                 }
                 return x
               }
             }

          let PostDB = (e) => {
             e.preventDefault()
             let JD           = {}

             let FORMCNTS     = $("#form_cnts")
             let INPUT_DATA   = document.getElementsByTagName('input')
             for(let d of Object.values(INPUT_DATA)){JD[d.name]=d.value}
             let JSON_DATA    = '['+JSON.stringify(JD).toString()+']'
             let CUSTOM_HEADER = "CUSTOM-HEADER-NAME"
             let customHeaders = new Headers({'Content-Type': 'application/json','X- 
             Custom-Header': CUSTOM_HEADER })
             let customInit = { method: 'POST',
                             headers: customHeaders,
                             Accept: 'application/json',
                             mode: 'cors',
                             cache: 'default',
                             credentials: 'same-origin',
                             body: JSON.stringify(JSON_DATA)}
            let url = FORMCNTS.action

            let customRequest = new Request(url, customInit)
            fetch(customRequest)
            .then((response) => {
              return response.json()
            })
            .then((resp) => {
              if(resp.status == "OK") {
                for(let d of Object.values(INPUT_DATA)){d.value=""}
                let fade_div          = $("#fade_div")
                fade_div.innerText    = resp.status
                fadeIn(fade_div,1500,function(){
                 fadeOut(fade_div,1500,function(){
                  })
              })
              }
             })
             .catch(function(error) { console.log(error) })
          }
          </script>
          </body>
        </html>
    """
    return index

@post('/db')
def do_db():
    TYDB      = f'{TMP_PATH}/{DATABASE["NAME"]}.json'
    _status   = "NG"
    json_data = {"status": _status}
    if request.json != "":
        with tydb(TYDB) as db:
            json_data  = json.loads(request.json)
            db.insert(json_data[0])
        _status = "OK"
    try:
        reurl = json_data
        request_data = {
            "headers":request.headers['Content-Type'],
            "json": json_data,
            "MEMFILE_MAX":request.MEMFILE_MAX,
            "remote_route":request.remote_route,
            "is_xhr":request.is_xhr,
            "remote_addr":request.remote_addr,
            "url":request.url,
            "method":request.method,
            "status":_status,
            "User_Agent":request.get_header('User-Agent')}

        response.content_type = 'application/json'
        r = HTTPResponse(status=302)
        r.set_header('Location', reurl)

        return dumps(request_data, ensure_ascii=False, indent=2)
    except:
        abort(500)

if __name__ == "__main__":
    bottle.run(host='0.0.0.0', port=8080)
```

と、実行されれば、form内のデータがデータベースに登録されるだろう...
まずは、jsの説明から...
ここが重要で、`TagName=input`を全て、`INPUT_DATA`へ格納する。
その後、`for文`で全て抜き出す。その際、name(key)とvalueで紐付けしながら格納する。
もしかすると、もっといい方法があるだろう...

```js
...
let INPUT_DATA   = document.getElementsByTagName('input')
for(let d of Object.values(INPUT_DATA)){JD[d.name]=d.value}
...
```

その後、一度連想配列にする。
何故か?は、サーバ側の処理を確認するといいだろう。
日本語などがあると通常通り引き渡せない事があったので、救済処置として、このような形にしてみた。

```js
let JSON_DATA    = '['+JSON.stringify(JD).toString()+']'
```

あとは、非同期処理の`fetch`を使ってPOSTすればいい。
その時重要になるのが、`Content-Type`だ。これをjsonにしておかないと、受け渡しの際に、サーバ側で処理が複雑になってしまう。

```js
... customHeaders = new Headers({'Content-Type': 'application/json',...
```

最後となるが、サーバ側の処理をみてみよう。

```js
...json.loads(request.json)
...db.insert(json_data[0])
```
と、上記のようにjson形式で呼び出した上で、データベースへ格納する際には、連想配列にて、`[0]`とし引き渡す事で、str処理などを気にせず、格納できる。
色々試したのだが、連想配列以外での受け渡しだとうまく受け取れない`dict`だったり、`str`だったり...typeが異なり、受け取りの処理が複雑かつ、面倒になりがちだった...

ひとまず、これで落ち着くと思う。

以上。