Help us understand the problem. What is going on with this article?

PythonのFlaskで学ぶWebアプリケーション制作講座 第2部1章 〜JSONのやりとり〜

WebAPIとは

今回からWebAPI編となる。今までは人がブラウザで閲覧し、操作するという前提でWebアプリケーションを作ってきた。しかし、現代においてはブラウザ以外のアプリケーションからの利用、例えばスマホアプリなど、も一般的となってきている。また、公式のアプリ以外にも一般に機能を公開し、プログラムから利用してもらうようなことが考えられる。こういった場合に一定のルールに則ってWebアプリケーションとプログラムの間にはいる、つまりWebアプリケーションとプログラムのインターフェイスとなるものがWebAPIである。また、通常のWebアプリケーションにおいてもクライアントサイドのアプリケーションからWebAPIを利用してWebアプリケーションを作るということが可能である。この場合はサーバ側の機能とクライアント側の機能が分離しよりプログラムの見通しがよくなる。

JSONとは

今まではリクエストに対してhtmlを返却するという処理を行なってきた。htmlは一般にブラウザで表示させ人が操作することを意図され設計されている。そのため、WebAPIでもhtmlを使うことは可能だが、プログラムで使う上では面倒で非効率であることがおおい。そのため、多くの1WebAPIではJSON(JavaScript Object Notation)というフォーマットがよく利用されている。JSONの正確なフォーマットについてはRFC 8259で定義されている。基本的にはPythonでいうところの数値と文字列、bool値(true, false)、nullを入れられるリストとディクショナリという理解で良い。書き方もほぼ同一である。以下にjsonの一例を示す。

{
"id": 3,
"name": "hoge",
"ref": [1, 2, 4],
}

この例ではidをkeyとして数値3、name対して文字列hoge、"ref"に配列[1, 2, 3]を割り当てている。

JSONを返却する

Flaskから上記の内容のjsonを返却するには下記のようにする。

from flask import Flask, jsonify

app = Flask(__name__)

# 日本語を使えるように
app.config['JSON_AS_ASCII'] = False

books = [{'name': 'EffectivePython', 'price': 3315}, {'name': 'Expert Python Programming', 'price': 3960}]


@app.route('/')
def get_json():
    data = {
        "id": 3,
        "name": "hoge",
        "ref": [1, 2, 4],
    }
    return jsonify(data)


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

まずは

app.config['JSON_AS_ASCII'] = False

でJSONで日本語を使えるようにしている(今回は関係ないが入れておいたほうがよい)。
次に返却するオブジェクトを構築する。

    data = {
        "id": 3,
        "name": "hoge",
        "ref": [1, 2, 4],
    }

これはPythonのディクショナリとリストを使っている。

そしてこのdataをjsonに変換して返却する。

return jsonify(data)

このためにjsonify関数を利用する。

以上をまとめると通常のPythonのディクショナリとリストを使ってJSONを表現し、それをjsonify関数を用いて実際にJSONに変換すればよい。

PyCharmからのWebAPIのデバッグ法

今まではブラウザからWebページを確認してデバッグしていた。しかし、WebAPIをデバッグする際にはPyCharm等からデバッグできたほうが便利である。特にPOSTに関しては今まではフォームを使っていたが、WebAPIの場合は直にPOSTするためブラウザからの操作は困難である。PyCharm(のProfessional版)にはPyCharm上でHTTPリクエストを作成し送信する機能(HTTPクライアント)が備わっている。その機能について紹介する。PyCharm以外のIDEでもおそらくできると思われる。また、cURLというツールを使うという手もある。PyCharm以外を使う人は各自調べてほしい。

PyCharmのHTTPクライアントはその場かぎりのHTTPリクエストを送信する方法とファイルにHTTPリクエストをファイルに保存しそれを送信する方法の2つの方法が提供されている。今回は使い回しがきくHTTPリクエストをファイルに保存する方法を紹介する。

まずはファイルメニューからNewを選択いs、HTTP Requestをクリックする(下図)。
スクリーンショット 2020-02-12 18.12.58.png

そうするとファイル名の記入を求められるので適当な名前を記入する(かきれいではget_test)。
スクリーンショット 2020-02-12 18.13.36.png

今回はGETリクエストを送信するので右上の「Add Request」から「GET Request」を選択する(下図)。
スクリーンショット 2020-02-12 18.14.03.png

これでGETリクエストのテンプレートが挿入される。挿入されたテンプレートを今回にあわせて下記のように書き換える。

GET http://localhost:5000/
Accept: application/json

###

これの意味はまず

GET http://localhost:5000/

でGETリクエストを「http://localhost:5000/」に送ることを示している。

Accept: application/json

は送るコンテンツタイプが「application/json」であることを示している(定型文なのであまり気にしなくても良い)。

###

はPyCharmのHTTPClient独特の記法で複数のHTTPリクエストを書く場合のリクエストの区切りを示している。他にも色々と書くことができるが最低限は以上だ。他の機能については基本的にはHTTPヘッダの文法に則っている。各自調べてほしい。

次はこのリクエストを実際に送信してみよう。まずは先程のサンプルプログラムを実行する。その後、HTTPClientに戻り、エディタのGETの左にある緑色の▶(下図)をクリックすることでリクエストを送信できる。
スクリーンショット 2020-02-12 18.15.12.png

そうすると下に実行結果が表示される。

POSTリクエストでJSONを受け取る

ここまではGETリクエストに対してJSONを送り返すという処理をしてきた。次はPOSTリクエストとそれに含まれるjsonを受け取るという処理を紹介する。

本体のプログラム(app.py)は下記のようにする。

from flask import Flask, request, jsonify

app = Flask(__name__)

# 日本語を使えるように
app.config['JSON_AS_ASCII'] = False

books = [{'name': 'EffectivePython', 'price': 3315}, {'name': 'Expert Python Programming', 'price': 3960}]


@app.route('/books', methods=['POST'])
def post_json():
    # JSONを受け取る
    json = request.get_json()

    # JSONをパースする
    name = json['name']
    price = json['price']
    book = {'name': name, 'price': price}
    book_id = len(books)
    books.append(book)

    # 返却用ディクショナリを構築
    book['id'] = book_id
    return jsonify(book)  # JSONをレスポンス


@app.route('/books/<book_id>', methods=['GET'])
def get_json_from_dictionary(book_id):
    return jsonify(books[int(book_id)])


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

また、リクエストのサンプルは下記である。

POST http://localhost:5000/books
Content-Type: application/json

{
  "name": "hoge",
  "price": 1000
}

###

GET http://localhost:5000/books/2
Content-Type: application/json

###

POSTリクエストを受け取った後、下記のようにget_jsonをつかうことでJSONをPythonのオブジェクトに変換することができる。

request.get_json()

get_jsonで変換したオブジェクトはPythonのディクショナリやリストのように扱える(下記部分)。

    # JSONをパースする
    name = json['name']
    price = json['price']

また、今まで解説してこなかったが同名であるもの、HTTPのメソッド(ここでのGETとPOST)が異なるURLを定義できる。WebAPI(とくにREST APIと呼ばれるもの)ではこのようなことをよく行う。これはGETの場合は取得する、POSTの場合は送信することを明示する意味がある。

問題

第1部5章の問題では商品の在庫管理システムを考えた。これの機能をWebAPIとして実装したい。商品の追加・削除・取得のためのWebAPIを実装せよ。DBを利用すること。今回は誘導のためほぼ第1部5章の問題と共通の部分が存在する。回答を流用しても良い。

  • (商品ID,商品名,価格)をcolumとしてもつテーブルを作成せよ
  • 商品の取得APIを実装せよ(/api/1.0/items/id)。取得なのでGETメソッドを利用すること。またidは可変である。商品ID,商品名,価格を含むJSONを返却すること。
  • 商品の追加APIを実装せよ(/api/1.0/items)。追加なのでPOSTメソッドを利用すること。商品名,価格を含むJSONを送信したら、商品ID、商品名,価格を含むJSONを返却すること。

発展

  • 商品の修正APIを作成せよ(/api/1.0/items/id)。更新であるのでPUTメソッドを利用すること。
  • 商品の削除ページを作成せよ(/api/1.0/items/id)。削除であるのでDELETEメソッドを利用すること。

  1. "多くの"であるだけですべてではない。過去にはhtmlに近いXMLというフォーマットが利用されていた。最近はより高速に通信が可能なgRPCというプロトコルも出てきている。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした