読者です 読者をやめる 読者になる 読者になる

c-bata web

@c_bata_ のメモ。python多め

Core APIの概要とDjango REST Frameworkでの使い方

Python Django

Django Advent Calendar 2016 - Qiita 18日目の記事です。

Django REST Frameworkは、DjangoでRESTfulなAPIを提供するときに非常に人気のあるフレームワークです。 既に使ってるよという方も多くいらっしゃるのではないでしょうか。

日経電子版さんも業務でも活用しているようです。

この記事では、REST Framework自体の使い方とかはあまり話しません。 REST Framnworkの作者である @_tomcriestie さんが策定・開発しているCore APIの概要と使い方について、これまでの経緯も含めて簡単に解説します。

Core APIが登場するまで

これまで、Django REST Frameworkと合わせて広く利用されていたライブラリの1つに、Django REST Swaggerというものがあります。 これはDjango REST FrameworkのSerializerやViewSetなどのクラス定義から、Swaggerの定義ファイルをこのライブラリが頑張って生成してくれていて、Swagger UIを提供してくれます。 このライブラリもまた非常によく出来ていて便利です。

Core APIの登場

そんな中、REST Frameworkの開発者であるtomcriestieさんが、Core APIの開発を始めました。 Django REST Frameworkで使われるようになったのもここ半年以内での話なので、初めて聞いたという方も多いのではないでしょうか。

これはWeb APIスキーマを定義しているもので、このCore APIからOpen API/SwaggerやJSON Hyper-Schemaなどに変換できます。 つまりこれまでは、Django REST FrameworkのViewSetsなどの情報から各ライブラリが頑張ってSwaggerの定義ファイルなどを生成していましたが、Django REST FrameworkがCore APIを生成することによって、SwaggerでもJSON Hyper-Schemaでも簡単に定義ファイルを生成できます。

当時はDjango REST FrameworkのViewSetsなどの情報からJSON Hyper-Schemaを生成するライブラリを開発していたのですが、Core APIの登場で必要なくなりました。完成する前に出てきてくれてよかったです。

Django REST FrameworkでCore APIを使う

それでは使い方を見ていきましょう。 といってもDjango REST Framework側でCore APIスキーマをほとんど自動生成してくれるため、覚えないといけないことは少ししかありません。

APIのdescriptionだけは自分で指定しないと、空文字が挿入されます。 フォーマットも決まっているのでこれに従ってください。

class CategoryViewSet(mixins.ListModelMixin,
                      mixins.RetrieveModelMixin,
                      viewsets.GenericViewSet):
    """
    retrieve:
        カテゴリの詳細を取得

    list:
        全カテゴリーの取得
    """
    queryset = Category.objects.all()
    serializer_class = CategorySerializer

こうしておくとDjango REST SwaggerのようなCore APIを使用するライブラリを使う時に、うまくDescriptionを入れてくれます。

f:id:nwpct1:20161218172232p:plain

REST Framework以外で、Core APIを使ってみたい人へ

DocumentLink など覚えないといけないCore APIの用語がいくつか存在しますが、そちらの解説は公式サイトに少しだけ書かれているので、勉強したい方はそちらを読んで下さい。

開発が活発でAPIもまたすぐに変わる可能性が高いので、特にいま使う予定が無いのであればここは読み飛ばしていただいて大丈夫です。

APIの変更に公式のserver-exampleのアップデートも追いついていない状態なので、Django REST Framework以外でcoreapiを使いたいときは気をつけてください。 coreapi (v2.0.9 現在)のSwaggerの定義ファイルを取得するサンプルは次のようになります。

import coreapi
from kobin import Kobin, Response
from coreapi import codecs
from openapi_codec import OpenAPICodec

app = Kobin()


def get_document():
    return coreapi.Document(
        url='/',
        title='Example API',
        content={
            'integer': 123,
            'dict': {'key': 'value'},
            'list': [1, 2, 3],
            'link': coreapi.Link(
                url='/',
                action='get',
                transform='inplace',
                fields=['optional', coreapi.Field('required', required=True, location='path')]
            ),
            'nested': {'child': coreapi.Link(url='/123')}
        }
    )


@app.route('/')
def swagger():
    codec = OpenAPICodec()
    content = codec.encode(get_document())
    return Response(content)

動かすときはこのようになります。 実際のユースケースでは、Acceptヘッダーの中身から適切なCore APIのcodecsを選択して返すというような形になります。

$ python3.6 -m venv venv
$ source venv/bin/activate
$ pip install coreapi kobin openapi-codec wsgicli
$ wsgicli run core_api_sample.py app
$ curl http://127.0.0.1:8000/ | jq .
{
  "swagger": "2.0",
  "info": {
    "title": "Example API",
    "version": ""
  },
  "host": "localhost:8080",
  "schemes": [
    "http"
  ],
  "paths": {
    "/": {
      "get": {
        "operationId": "link",
        "responses": {
          "200": {
            "description": ""
          }
        },
        "parameters": [
          {
            "name": "optional",
            "required": false,
            "in": "query",
            "description": "",
            "type": "string"
          },
          {
            "name": "required",
            "required": true,
            "in": "path",
            "description": "",
            "type": "string"
          }
        ]
      }
    },
    "/123": {
      "get": {
        "operationId": "child",
        "responses": {
          "200": {
            "description": ""
          }
        },
        "parameters": [],
        "tags": [
          "nested"
        ]
      }
    }
  }
}

Core APIからSwaggerの定義ファイルが取得出来ています。

Core APIまわりのツール群

Django REST Swagger以外のCore API周りのツール群は、Core APIのGithub Organizationにほぼまとまっているようです。 どんどん新しいライブラリが出てきているので、適宜チェックしておくといいかもしれません。

Codecs周り

Core APIは現在、 Core JSON (CoreAPIのJSON表現のようです)と Open API/SwaggerHALJSON Hyper-Schema への変換を正式にサポートしています。 他にも覗くと、API BluePrintなどの定義ファイルへの変換をサポートする予定があることがわかります。

Documentationまわり

またDjango REST Swaggerもかなり早い段階で、Core APIを使うようになりました (refs: Release v2.0.0)。 11月の初め頃までは使ってみると色々辛い部分がありましたが(詳しくは書きませんが)、個人的にはv3.5.3あたりでCoreAPI周りの実装がだいぶ追いついてきた印象です。

またDocumentationに関しては、Core Docsというのも最近登場しました。 まだほとんど使っている人はいないかと思いますが、Core APIスキーマを返すAPIのURLを指定すればドキュメンテーションを生成してくれるようです。

各言語のクライアント

2016/12/18現在だと、ちゃんと使えるそうなのはpython-clientのみのようです。 javascript-clientやswift-clientも作るみたいですね。

おわりに

Core API周りのツール群は、まだまだ整っているとは言えない状況ですが、Django REST Frameworkから利用する分には大体便利に使えるかと思います。 また @_tomcriestie さんの開発スピードが信じられないくらい早いので、近いうちに便利なものが出来るんじゃないかなという期待もあります。

リポジトリを見てみると、OpenAPI/SwaggerやJSON Hyper-Schema、HALなどへの変換ライブラリも @_tomcriestie さんがほぼ1人で実装を進めてて彼の実装力には本当に尊敬しかでないですね。 みなさんも是非使ってみてください。

Test-Driven Development with Python: Obey the Testing Goat - Using Django, Selenium, and Javascript

Test-Driven Development with Python: Obey the Testing Goat - Using Django, Selenium, and Javascript

Two Scoops of Django: Best Practices for Django 1.8

Two Scoops of Django: Best Practices for Django 1.8

rexecute: ファイルの更新を検知して指定したコマンドを自動実行するCLIツールつくった

つくったもの Golang

そんなことより卒論書きなよって話ですが、texファイルの更新を検知して自動でビルドする仕組みを整備しました。

2年前に論文を書いていたときは、RubyのGuardを使っていたのですが久しぶりに試すと動かなくて、それを直すのも面倒だったので、少し汎用的に使えるツールをGolangでつくりました。

github.com

使い方

使い方はシンプルで、lsやfindでファイルの一覧をとってきて、rexecuteコマンドにパイプで渡すだけです。

$ find . -name '*.tex' | rexecute make build

デモの様子

みんなのGo言語で気になったところを読んでいたのですが、CLIツールの作り方の章や、golintやgo vetなどのツールの話がとても参考になりました。 このコマンドもUNIXの哲学にあるような、組み合わせて使える小さなコマンドになっているかなと思っています。

その他の使い方

汎用的なツールなのでわりと何にでも使えます。 例えばSphinxsphinx-autobuildとか使わなくても次のように使えます。

$ find . -name '*.rst' | rexecute make html

みんなのGo言語【現場で使える実践テクニック】

みんなのGo言語【現場で使える実践テクニック】

Released Kobin v0.1.0: Web Framework for Python3.

Python つくったもの

少し開発が停滞気味だったのですが、最近多くのアップデートを加えたので、v0.1.0をリリースしました。それに伴い、WSGIミドルウェアやWSGICLIの開発、ドキュメントの整備を行ったので紹介。

github.com

Kobin

Kobinの説明や使い方は、ドキュメンテーションを書いたのでここでは省略します。

また実際に自分でKobinとSQLAlchemy、Angular2などを使って、サンプルのアプリケーションを書いているので、とりあえず雰囲気を知りたい方はそちらをご覧ください。

Kobin Example Demo

WSGICLI

このツールはKobinに限らず、BottleやFlaskといった他のフレームワークでも利用出来ます。 Kobinはまだまだ開発途中な点もありますが、WSGICLIはもう十分に便利なツールかと思っているので、ぜひ使ってみてください。

簡単な使い方の例をいくつか紹介します。

ISUCONでPython実装をプロファイリング

このツールはLine Profiler連携とLive Reload機能のおかげで、ISUCONの問題を解くときにかなり便利なツールになったかなと個人的に思っています。

$ wsgicli run app.py app -h 0.0.0.0 -p 9000 --reload --lineprof

これを起動しておくと、手元のマシンでコードを変更・git pushして、git pullするだけで反映されます。 今はlineprofilerのみサポートしていますが、vmprofも追加予定です。

wsgicli profiling and live reloading

run コマンドには他にも、静的ファイルの配信機能や、WSGIの仕様(PEP3333)に準拠しているかチェックするミドルウェアフレームワークの開発に便利な機能があります。

wsgicli shellコマンド

django-extensionsのshell_plusをSQLAlchemyやpeeweeでも使用出来るようにしたような機能です。 Pythonの対話シェルを起動して、peeweeやSQLAlchemyのModelクラスをインポートしてゴニョゴニョすることがありますが、wsgicliのshellコマンドを使用すると起動時に自動でモデル定義を探索してimportしてくれます。

$ wsgicli shell app.py -i ipython

wsgicli shell

サポートしているPythonインタプリタは次のものです。

  • Python(Plain)
  • iPython
  • bpython
  • ptpython
  • ptipython

その他

その他にもlinebotのサンプルやWSGIミドルウェアを作っているので、ぜひご覧ください。

kobinpy · GitHub

kobin-linebot

WebフレームワークといくつかのWSGIミドルウェアwsgicli、サンプルアプリ、日英ドキュメントを全て1人で用意するのは思っていたよりも体力と時間が必要みたいです。 tomcriestieさんとか見てるとすごい勢いで開発していて焦りますね。 時間は思っていたよりも少ないみたいなので、2017年はもっとスピードを上げて沢山のコード書いていきたい。

実践 Python 3

実践 Python 3