-忘備録- Flaskで簡単なAPIの作り方

#参考記事
https://qiita.com/fiftystorm36/items/b2fd47cf32c7694adc2e
https://qiita.com/zaburo/items/5091041a5afb2a7dffc8
https://peei.hatenablog.com/entry/2019/03/31/192514
https://swallow-incubate.com/archives/blog/20190819


#事前準備
##仮想環境作成
コマンド

```bash
$ python3 -m venv [仮想環境の名前]
```

実行例

```bash
$ pwd
/Users/Hoge/venv_practice_dir
$ python3 -m venv venv_practice
```

##作成した環境に切り替え
コマンド

```bash
$ source [作成した環境]/bin/activate
#または
$ . [作成した環境]/bin/activate
```

実行例

```bash
$ source venv_practice/bin/activate
```


実行後↓のように「ターミナルの表示が変わる(zash)

```bash
# before
Hoge@fuga venv_practice_dir %
# コマンド実行後
(venv_practice) Hoge@fuga venv_practice_dir % 
```

##仮想環境終了
※後続作業は開発環境で実施

コマンド

```bash
()$ deactivate
```

# APIのベース作成
## Flaskインストール

```bash
()$ pip install Flask
```

##サンプル

```Python:hello.py
from flask import Flask, request
#おまじない
app = Flask(__name__)

@app.route('/')
def hello():
    name = "Hello World"
    return name

@app.route('/hoge', methods=['GET', 'POST'])
def hoge():
    try:
        if request.method == 'GET':
            return "GET"
        elif request.method == 'POST':
            return "POST"
        else:
            return "400"
    except Exception as e:
        return str(e)

## おまじない
if __name__ == "__main__":
    app.run(debug=True)

```

##実行
こんな感じになる

```bash
()$ python hello.py
 * Serving Flask app "hello" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 333-177-100
```


##curlでアクセス

```
$ curl http://127.0.0.1:5000/    
Hello World
$ curl http://127.0.0.1:5000/hoge
GET
$ curl -X POST -d hoge=fuga http://127.0.0.1:5000/hoge
POST                           
```     

##値をjson形式で返す

####サンプル

```Python:hello.pyの変更箇所
from flask import Flask, request, make_response, jsonify

@app.route('/json')
def json():
    return jsonify({
        'user_list': [
            {
                'id': 1,
                'name': 'Tarou'
            }
        ]
    })

```

テスト

```bash
$ curl http://127.0.0.1:5000/json
{
  "user_list": [
    {
      "id": 1, 
      "name": "Tarou"
    }
  ]
}
```                                                 

##DBを使う

追加でSQLAlchemyインストール

```bash
$ pip install SQLAlchemy
```

####サンプル

```hello.py
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
#おまじない
app = Flask(__name__)
#データベースの接続先を記述
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'

db = SQLAlchemy(app)

#DBの内容
class User(db.Model):
    __tablename__ = 'hoge'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Text)

#hello.pyが読み込まれた時点でデータベースも初期化できるようにフックする
with app.app_context():
    db.create_all()


#methods指定なしでGET
@app.route('/json')
def user_list():
    users = User.query.all()
    return jsonify({
        'user_list': [
            {
                'id': i.id,
                'name': i.name
            }
            for i in users
        ]
    })

#ルートが同盟でもmethods違いで定義できる
@app.route('/json', methods=['POST'])
def create_user():
    user = User()
    #リクエストパラメータがjson形式になってることが前提
    user.name = request.json['name']
    db.session.add(user)
    db.session.commit()
    return jsonify({
        'id': user.id,
        'name': user.name
    }), 201

## おまじない
if __name__ == "__main__":
    app.run(debug=True)
```

####POSTテスト
※POSTする際はContent-Typeにapplication/jsonを指定しないとエラーになり、dataをjson形式で渡さないと読み込んでくれない。

```bash
$ curl -X POST --header "Content-Type:application/json" -d '{"name":"hoge"}' http://127.0.0.1:5000/json 
{
  "id": 1, 
  "name": "hoge"
}
```
####GETテスト

POSTで登録したデータが見れる

```bash
$ curl http://127.0.0.1:5000/json                      
{
  "user_list": [
    {
      "id": 1, 
      "name": "hoge"
    }
  ]
}
```