flaskのrest apiと, axiosでAPIのやり取りをする方法について.

content

一般的なリクエスト・レスポンスのやり取り

まずは, 単純なパラメータ・レスポンスの受け渡しだけ.

1. axiosからリクエストを送信する

まずは, axiosを使って, httpリクエストを送信します.

とりあえずcdn版でやります(node.jsでやる場合は, yarnやnpm等で導入してくらさい)

<script src="https://cdnjs.cloudflare.com/ajax/libs/qs/6.8.0/qs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="js/main.js"></script>

この3文をbodyタグの末尾に追加し, main.jsに処理を書いていきます.

パラメータのサンプルとして, 以下のものを用意します.

const id = "12345";
const params = {
    mail: "mail@mail.com",
    passwd: "passwd"
};

これを, 各メソッドでリクエストを送るには以下のようにします.

axios.get('/api', {params: params})
axios.post('/api', params)
axios.put('/api' + id, params)
axios.delete('/api' + id, {data: params})

2. flaskでrest apiを作る

パラメータを受け取り, 表示し, 空のjsonをレスポンスとして返すだけのapiを書きます.

from flask import Flask
from flask_restful import Resource, Api, reqparse

app = Flask(__name__)
api = Api(app)


def print_dict(dic):
  for key in args.keys():
    print(f"{key}: {args[key]}")


class MyAPI(Resource):
  def __init__(self):
    self.parser = reqparse.RequestParser()
    self.parser.add_argument('mail')
    self.parser.add_argument('passwd')
    super(MyAPI, self).__init__()
    
  def get(self):
    args = dict(self.parser.parse_args())
    print_dict(args)
    return {}
    
  def post(self):
    args = dict(self.parser.parse_args())
    print_dict(args)
    return {}
    
  def put(self):
    args = dict(self.parser.parse_args())
    print_dict(args)
    return {}
    
  def delete(self):
    args = dict(self.parser.parse_args())
    print_dict(args)
    return {}
    
    
api.add_resource(MyAPI, '/api')

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

returnでディクショナリを返せば, jsonに変換されてそのままレスポンスを返すことができます.

3. axiosでレスポンスを受け取る

レスポンスはget, post, put, deleteメソッドの戻り値として帰ってきます.

axios
  .get('/api', {params: params})
  .then(response => {
    console.log("status: " + response.status);
    console.log(response.data);
  })
  .catch(error => {
      console.log(error);
  });

これで, response.dataにflaskで返した(ディクショナリから変換した)jsonがそのまま入ります.

あとはDOMを書き換えるなり好きに処理をかけばOKです.

例として, getでやりましたが他のメソッドでも同様です.

パラメータとして配列やオブジェクトを渡す

axios -①-> flask -②-> axios と情報の受け渡しが行われますが,

②の受け渡しでリストは配列に, ディクショナリはオブジェクトに変換されるので自然にかけば大丈夫なんですが

①の受け渡しでは, オブジェクトや配列を上手く渡すことができないので渡したい場合はquery stringを使う必要があります.

Qsモジュールは最初にaxiosと一緒にscriptタグで取ってきてるのでそのまま利用できます.

const id = "12345";
const params = {
    mail: "mail@mail.com",
    passwd: "passwd",
    list: Qs.stringify([
      "hoge",
      "hoge2"
    ]),
    obj: Qs.stringify({
      key0: "content0",
      key1: "content1"
    })
};

axios.get('/api', {params: params})

python側では,

urllib.parse.parse_qsl関数, parse_qs関数等を用いてリスト, ディクショナリに変換できます.

まずは変換用関数を定義しておきます.

from urllib import parse


def qs2list(qs: str) -> list:
    parsed = parse.parse_qsl(qs)
    return [x[1] for x in parsed]
    
    
def qs2dict(qs: str) -> dict:
    parsed = parse.parse_qs(qs)
    _ = {}
    for key in parsed.keys():
        _[key] = parsed[key][0]
    return _

処理内容はめんどいので割愛しますが,

この関数を通すことでquery stringがリストとディクショナリに変換されます.

class MyAPI(Resource):
    def __init__(self):
        self.parser = reqparse.RequestParser()
        self.parser.add_argument('mail')
        self.parser.add_argument('passwd')
        self.parser.add_argument('list')
        self.parser.add_argument('obj')
        super(MyAPI, self).__init__()

    def get(self):
        args = dict(self.parser.parse_args())
        arg_l = qs2list(args['list'])
        arg_o = qs2dict(args['obj'])
        print(arg_l)  # ['hoge', 'hoge2']
        print(arg_o)  # {'key0': 'content0', 'key1': 'content1'}
        return {}

これでパラメータに配列等を渡すこともできるようになりました.

ただし, 試せば分かりますが入れ子まで対応するのは無理なので, 複雑な形式で渡すことはできません.