Flaskで作るAPIのコードサンプル集

FlaskでAPIを作りました．
そのときに調べた情報がチュートリアルレベルが多かったので，実際に書いたコードを紹介できればと．

随時追記していきます．

# 対象者
FlaskでちょっとしたAPI作りたい

# 環境
- Mac
- Python 3.6.0
- Flask==1.0.2
- Flask-API==1.1

# ソース
ここにおいてます．
https://github.com/monkeydaichan/flask-sample

# Code
### JsonをPostしてJsonが返ってくるPostAPI
postするjsonのデータは`{"name":"monkeydaichan"}`です．
戻り値は`{"data":{"id":1,"name":"monkeydaichan"}}`こうしてます．

```py
# coding:utf-8
import json
from flask import Flask, jsonify, make_response, request, Response

app = Flask(__name__)

@app.route('/post', methods=['POST'])
def post_json():
  json = request.get_json()  # Get POST JSON
  NAME = json['name']
  result = {
    "data": {
      "id": 1,
      "name": NAME
      }
    }
  return jsonify(result) 

if __name__ == "__main__":
  app.run()
```

アクセスしてみる

```bash
$ curl -X POST -H "Content-Type: application/json" -d '{"name":"monkeydaichan"}' http://localhost:5000/post
{"data":{"id":1,"name":"monkeydaichan"}}
```

### URLパラメータを取得してJsonが返ってくるGetAPI
URLから値を取得してJsonを返すAPIです．
/api/<name> にアクセスると`{"data":{"id":1,"name":"monkeydaichan"}}`が返ってきます．

```py
# coding:utf-8
import json
from flask import Flask, jsonify, make_response, request, Response

app = Flask(__name__)

@app.route('/api/<name>', methods=['GET'])
def get_json(name):
  NAME = name
  result = {
    "data": {
      "id": 1,
      "name": NAME
      }
    }
  return jsonify(result) 

if __name__ == "__main__":
  app.run()
```

アクセスしてみる．

```bash
$ curl -X GET -H "Content-Type: application/json" http://localhost:5000/api/monkeydaichan
{"data":{"id":1,"name":"monkeydaichan"}}
```

## エラーハンドリング
### デコレーターを利用したエラーハンドリング
[JsonをPostしてJsonが返ってくるPostAPI](#JsonをPostしてJsonが返ってくるPostAPI)このAPIの`http://localhost/pos`という定義されていないAPIにアクセスします．

```py
# coding:utf-8
import json
from flask import Flask, jsonify, make_response, request, Response
from flask_api import status

app = Flask(__name__)

@app.route('/post', methods=['POST'])
def post_json():
  try:
    json = request.get_json()  # Get POST JSON
    NAME = json['name']
    result = {
      "data": {
        "id": 1,
        "name": NAME
        }
      }
    return jsonify(result) 
  except Exception as e:
    result = error_handler(e)
    return result

@app.errorhandler(400)
@app.errorhandler(404)
@app.errorhandler(500)
def error_handler(error):
    response = jsonify({ 
                          "error": {
                          "type": error.name, 
                          "message": error.description 
                          }
                      })
    return response, error.code

if __name__ == "__main__":
  app.debug=True
  app.run(host='0.0.0.0')
```

アクセスしてみる

```bash
$ curl -X POST -H "Content-Type: application/json" -d '{"name":"monkeydaichan"}' http://localhost:5000/pos
{
  "error": {
    "message": "The requested URL was not found on the server.  If you entered the URL manually please check your spelling and try again.", 
    "type": "Not Found"
  }
}
```

Flaskのログにも404エラーが表示されています．

```bash
127.0.0.1 - - [09/Feb/2019 20:22:01] "POST /pos HTTP/1.1" 404 -
```

## 関数のExceptionを拾って任意のステータスコードを返す
[JsonをPostしてJsonが返ってくるPostAPI](#JsonをPostしてJsonが返ってくるPostAPI)このAPIにnameキーがなかった場合のエラーハンドリングを実装します．
Requestするjsonは`{"hoge":"monkeydaichan"}`として，statusCodeをセットするために`flask_api`をインポートしています．

```py
# coding:utf-8
import json
from flask import Flask, jsonify, make_response, request, Response
from flask_api import status

app = Flask(__name__)

@app.route('/post', methods=['POST'])
def post_json():
  try:
    json = request.get_json()  # Get POST JSON
    NAME = json['name']
    result = {
      "data": {
        "id": 1,
        "name": NAME
        }
      }
    return jsonify(result) 
  except Exception as e:
    result = errorhandling(e)
    return result, status.HTTP_500_INTERNAL_SERVER_ERROR

def errorhandling(error):
  exception_type = error.__class__.__name__
  exception_message = str(error)
  result_error = { 
                    "error": { 
                      "type": exception_type, 
                      "message": exception_message 
                    }
                  }
  return jsonify(result_error)

if __name__ == "__main__":
  app.debug=True
  app.run(host='0.0.0.0')
```

アクセスしてみる.

```bash
$curl -X POST -H "Content-Type: application/json" -d '{"hoge":"monkeydaichan"}' http://localhost:5000/post
{
  "error": {
    "message": "'name'", 
    "type": "KeyError"
  }
}
```

Flaskのログにも500エラーが表示されています．

```bash
127.0.0.1 - - [09/Feb/2019 20:13:20] "POST /post HTTP/1.1" 500 -
```

### POSTへのリクエストをPOSTへリダイレクトする
/postに来たリクエストを/fooにリダイレクトしています．
`redirect(url_for('foo'), code=307)` コード307を追加しないと動きませんでした．．．

```python
import json
from flask import Flask, jsonify, make_response, request, Response, redirect, url_for
from flask_api import status

app = Flask(__name__)

@app.route('/post', methods=['POST'])
def hello():
  return redirect(url_for('foo'), code=307)

@app.route('/foo', methods=['POST'])
def foo():
  json = request.get_json()
  name = json['name']
  result = {
    "name": name
  }
  return jsonify(result)

if __name__ == "__main__":
  app.debug=True
  app.run(host='0.0.0.0')
```

アクセスしてみる.

```bash
$curl -X POST -H "Content-Type: application/json" -d '{"name":"monkeydaichan"}' http://localhost:5000/post
{
  "name": "monkeydaichan"
}
```


# Reference
https://inokara.hateblo.jp/entry/2016/10/01/123923
https://qiita.com/5zm/items/c8384aa7b7aae924135c
https://qiita.com/kohbis/items/f3156f822bac330494fd
https://mabui.org/python-post-api-flask/
https://student-engineer.net/flask-api/
https://medium.com/nyle-engineering-blog/flask%E3%81%A7rest-api%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B-fad8ae1fde5c