かんちゃんの備忘録

プログラミングや言語処理、ゲームなど知的好奇心のための備忘録(個人の感想)です。

hugでAPIやCLIを作る

【Sansan Advent Calendar 2017 1日目の記事です。】

Pythonで、WebAPIやコマンドラインツールを作ったりするときに、ボトルネックになりがちなのが、ルーティングや引数の管理です。 hugは、ここらへんをよしなにやってくれるPythonモジュールです。

hugを使った、WebAPIやコマンドラインツールの作成について備忘録として記します。

もう少しhugについて知ってみる

hugの公式サイトでは、なんともかわいらしいコアラが出迎えてくれます。

一言で言うと、デコレータでメソッドをラップすることで、メソッド単位でシンプルにAPIを構築できるモジュールです。 公式サイトでも挙げられている特徴をまとめると、

  • デコレータでラップ(例:@hug.get())するだけで、APIのエンドポイントとなります
  • 裏側はfalconが動いているため、動作は高速です
  • APIのバージョンが簡単に切れます(例:@hug.get('/', versions=1)
  • APIドキュメントをコードから作成してくれます
  • 引数のバリデーションは、型を指定するだけで可能です(例:def test_method(name: hug.types.text)
  • コマンドラインインターフェイスとしても利用できます

インストールは、いつものpipで pip install hugで完了です。 Python 3.3以降が要件ですので、2系のかたは注意してください。

WebAPIを作ってみる

おきまりのHello World!

# hello_world.py
import hug

@hug.get("/")
def hello_world():
    return "Hello World!"

hugには検証用にlocalhostにhttpサーバーを立ててくれる機能があります。 $ hug -f hello_world.pyと入力して、実際にAPIが動作しているか確認します。

f:id:kanjirz50:20171125105132p:plain

これだけで、APIが作成できていることが確認できました。

パラメータを渡す

GETリクエストのパラメータを受け取ります。 特徴で挙げたように、hugには引数の型を指定してバリデーションをしてくれる機能があります。

先ほどのHello Worldに変更を加えてみます。

# hello_world_2.py
import hug

@hug.get("/")
def hello_world(name: hug.types.text):
    return {"message": "Hello World {0}!".format(name)}

ルートにリクエストすると、nameという名前のテキスト型のパラメータを取得するメソッドとなります。 試しにアクセスしてみると、Hello World name !が返ってきます。

f:id:kanjirz50:20171125110041p:plain

ここで、パラメータが足りないとどうなるでしょうか? パラメータが足りないと、返ってきます。

f:id:kanjirz50:20171125110027p:plain

デコレータでラップして、引数に型を指定するだけで、いとも簡単にAPIが作れる素晴らしいモジュールです。

他にも、独自の型を作れたり、デフォルト引数を与えたりと多機能です。

デプロイするときは

WSGIに対応しているため、Apache+mod_wsgiやnginx+uwsgiで簡単に公開できます。 具体的には、__hug_wsgi__というインターフェースが用意されているため、これを起動します。

Flaskやbottleだと、app = __hug_wsgi__を最終行に追加すれば動きますし、 uwsgiだと、--callable __hug_wsgi__をオプションに加え、gunicornも___hug_wsgi__を呼んであげれば動きます。

コマンドラインツールを作ってみる

サンプルですが、以下のコードとなります。

# coding:utf-8

import hug


@hug.cli()
def hello_world(name: hug.types.text):
    return {"message": "Hello World {0}!".format(name)}


if __name__ == "__main__":
    hello_world.interface.cli()

以下の2つの処理を追記することでコマンドラインツールとなります。 - 対象のメソッドを@hug.cli()というデコレータでラップすること - Pythonスクリプトを直接実行(__name__ == "__main__")した際に、メソッド名.interface.cli()を呼ぶ

あとは、python ファイル名 引数で実行することで、コマンドラインツールとして動作します。 引数が必要な場合に、引数が入力されていないと、エラーとなります。

$ python hello_world_cli.py
usage: hello_world_cli.py [-h] name
hello_world_cli.py: error: the following arguments are required: name
$ python hello_world_cli.py Taro
{'message': 'Hello World Taro!'}

内部ではargparseが使われているようで、意外とargparseを記述するのは大変なのでhugは便利かもしれません。 (いろいろなモジュールに依存するようになりますが)

まとめ

爆速かつ完結にAPICLIを作るPythonモジュールのhugについて書きました。

デコレータでラップするだけで、Web APICLIを作れる便利なモジュールです。

CLI作るときは、argparseもいいですが、hugを積極的に使っていこうと思いました。