LoginSignup
3
2

More than 5 years have passed since last update.

軽い(自己満足の)APIを実装してみる

Last updated at Posted at 2018-03-15

どうやってAPIって提供されているのか?

いつも使う側なので、提供側を経験したく。
インフラエンジニアだと、ミドルウェア設計までで終わっていて、あとはアプリに"はい、どうぞ"なので。

前準備

例のごとく、ネット環境無いのでパッケージから導入。

python-babel-0.9.6-8.el7.noarch.rpm
python-flask-0.10.1-4.el7.noarch.rpm
python-itsdangerous-0.23-2.el7.noarch.rpm
python-jinja2-2.7.2-2.el7.noarch.rpm
python-markupsafe-0.11-10.el7.x86_64.rpm
python-werkzeug-0.9.1-2.el7.noarch.rpm
python2-peewee-2.10.2-1.fc27.x86_64.rpm

実装

■まずはデータを用意

今回はデータベースにpeewee,webフレームワークにflaskを使う。
peeweeで以下のデータとimport用のスクリプトを用意し、一気にデータを作成する。

userlist.tsv
#タブ区切り
#user   firm    isprivileged
Us01    firm1   True
Us02    firm2   True
Us03    firm3   False
Us04    firm4   False
Us05    firm5   True
Us06    firm6   False
Us07    firm7   True
Us08    firm8   False

項目はタブ区切り。

importdata.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from peewee import *

db = SqliteDatabase('base.db')

class BaseModel(Model):
    class Meta:
        database = db

class User(BaseModel):
    user = TextField()
    firm = TextField()
    isprivileged = BooleanField()

#モデルの定義に基いてテーブル作成
User.create_table()
#ファイルをreadモードで開き、1行ずつ読み込む
for line in open("userlist.tsv", "r"):
    (user, firm, isprivileged) = tuple(line[:-1].split("\t"))
    if user == '#user': #1行目が見出しなので、読み込まないように
       pass
    else:
       #レコードを作成
       User.create(user=user,
                   firm=firm,
                   isprivileged=isprivileged)
       #レコードから値を取得して格納
       a = User.get(User.user == user).user
       b = User.get(User.user == user).firm
       c = User.get(User.user == user).isprivileged

       print 'created record : user=' + str(a) + ' firm=' + str(b) + ' privilegelevel=' + str(c)

以下はpeeweeのチュートリアルに載ってた、お約束事的なもの。

db = SqliteDatabase('base.db')
→DBはsqliteを使うよ、DBファイルはbase.dbを使うよ。

class BaseModel(Model):
class Meta:
database = db
→モデル定義し、それが上で言ってたDBと紐付くよ。
※peeweeではモデルなるものを作成して、DBを紐付けて操作をするらしい。

class User(BaseModel):
user = TextField()
firm = TextField()
isprivileged = BooleanField()
→BaseModelをオーバーライドして、Userというモデルを定義して、フィールドを定義。
※これは省略できるか?ただ、何個もモデルを持たせるなら、BaseModel定義はあった方がいい気がする。

上記を実行すると、以下の結果。

sample
# ./import.py
created record : user=Us01 firm=firm1 privilegelevel=True
created record : user=Us02 firm=firm2 privilegelevel=True
created record : user=Us03 firm=firm3 privilegelevel=True
created record : user=Us04 firm=firm4 privilegelevel=True
created record : user=Us05 firm=firm5 privilegelevel=True
created record : user=Us06 firm=firm6 privilegelevel=True
created record : user=Us07 firm=firm7 privilegelevel=True
created record : user=Us08 firm=firm8 privilegelevel=True
#

DBから値を取得するには、pythonのインタプリタに入った後、以下のように実行する。

model
>>>from peewee import *
>>>db = SqliteDatabase('base.db')
>>>class BaseModel(Model):
...  class Meta:
...     database = db
...
>>>
>>>class <Model>(BaseModel):
...    <Field1> = TextField()
...    <Field2> = TextField()
...    <Field3> = BooleanField()
...
>>>
>>><Model>.get(<Model>.<検索するField> == "検索キー").<値を取得したいField>

"<>"内は適宜読み替えてください。

■FlaskでAPI

以下のスクリプト作成。

api.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask, jsonify, abort, make_response, Response, request, url_for
from peewee import *

#利用するDB定義 ここから--------
db = SqliteDatabase("base.db")

class BaseModel(Model):
    class Meta:
        database = db

class User(BaseModel):
    user = TextField()
    firm = TextField()
    isprivileged = TextField()
#ここまで----------------------

#Flask使うぜ!
api = Flask(__name__)

@api.route('/getUser/<string:users>', methods=['GET'])
def get_user(users):
    try:
        user = User.get(User.user == users)
    except User.DoesNotExist:
        abort(404)

    result = {
        "result":0,
        "data":{
            "User":user.user,
            "firm":User.firm,
            "isprivileged":User.isprivileged
            }
        }

    return make_response(jsonify(result))

@api.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

if __name__ == '__main__':
    api.run(host='0.0.0.0', port=80)

上記を部分ごとに説明。

@api.route('/getUser/string:users', methods=['GET'])

・"@"でデコレートする。
・Flaskでは、ユーザがアクセス先と許可するメソッドを@api.route()の中に書く。
 apiは上でインスタンス化した"api = Flask(name)"なので、個々人の設定に沿う。
string:usersはユーザが入力した値を変数usersに格納する、ということ。

def get_user(users):
try:
user = User.get(User.user == users)
except User.DoesNotExist:
abort(404)

・ユーザがアクセスしてきた際の処理内容を定義する。
・ユーザが入力した変数usersを使って、"User.get(User.user == users)"で
 レコードが存在するか確認、なければ"abort(404)"する。
・abortはFlaskの便利屋さんで、"@api.errorhandler(404)"まで飛ばしてくれる。

return make_response(jsonify(result))

・resultに格納した内容をjson化して返却。

@api.errorhandler(404)
def not_found(error):
return make_response(jsonify({'error': 'Not found'}), 404)

・エラーハンドリング。ここでabortした際の処理が発生。

api.run(host='0.0.0.0', port=80)

・実際に動かします。
・"host='0.0.0.0'"は自身のIPアドレスになる。
・ポートを指定。デフォルトは確か80。
・debugしたいなら、api.run()の中に"debug=True"を加える(カンマ区切り)。

■利用してみる

利用できる状態にするには、api.pyを実行します。

session
# ./api.py &
[1] 1738
#  * Running on http://0.0.0.0:80/

Enter押せばプロンプト戻ります。

この状態で、別のブラウザなりlinuxなりからアクセスする。
以下はLinuxの例。

session
# curl -i -k http://XXX.XXX.XXX.XXX:80/getUser/Us01
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 100
Server: Werkzeug/0.9.1 Python/2.7.5
Date: Thu, 15 Mar 2018 03:32:40 GMT

{
  "data": {
    "User": "Us01",
    "firm": "firm1",
    "isprivileged": true
  },
  "result": 0
}
# 
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2