軽量かつ非同期で実装できるおすすめのフレームワーク、Starlette👍
Starletteの特徴
開発はDjango Restframeworkを作っているEncodeという会社でTomChristieさんの会社です。彼はすばらしい設計、実装をされる方で、私はよく彼のコードを読んで、自分の書き方を直したりすることがあったりするほど、お手本としている方です。
他にもPythonの有名なライブラリをたくさん開発している@kennethreitzさんがResponderの下地に使っていたり、速くて、マイクロサービス向きなAPIベースのフレームワークです。以下のコードはWebsocketの実装ですが、見たとおりスッキリとしています。
# Pipfile
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[scripts]
dev = "uvicorn main:app --host 127.0.0.1 --debug --port 5000"
[dev-packages]
autopep8 = "*"
flake8 = "*"
ipython = "*"
[packages]
starlette = "*"
starlette-prometheus = "*"
[requires]
python_version = "3.7"
# main.py
import os
import uuid
import logging
import datetime
from os.path import dirname, basename
import uvicorn
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
from starlette.applications import Starlette
from starlette import status
from starlette.types import Receive, Scope, Send
from starlette.websockets import WebSocket
from starlette.endpoints import WebSocketEndpoint
from starlette.responses import PlainTextResponse
from starlette_prometheus import metrics, PrometheusMiddleware
logger = logging.getLogger(__name__)
DEBUG = os.environ.get('DEBUG')
app = Starlette()
# NOTE: You can use prometheus.
app.add_middleware(ProxyHeadersMiddleware)
app.add_middleware(PrometheusMiddleware)
app.add_route("/metrics", metrics)
@app.exception_handler(status.HTTP_403_FORBIDDEN)
@app.exception_handler(status.HTTP_404_NOT_FOUND)
@app.exception_handler(status.HTTP_500_INTERNAL_SERVER_ERROR)
async def server_error(request, exc) -> str:
return PlainTextResponse(f"{exc.status_code} ERROR")
@app.on_event('startup')
async def init_server() -> None:
pass
# DO SOMETHING
@app.websocket_route("/")
class App(WebSocketEndpoint):
async def on_connect(self, socket: WebSocket) -> None:
token = socket.query_params.get('token')
if token:
await socket.accept()
else:
await socket.close()
async def on_disconnect(self, socket: WebSocket, close_code: int) -> None:
pass
async def on_receive(self, socket: WebSocket, data: dict) -> None:
if not data['code']:
await self.send_message(socket, {
'status': 'error',
'result': 'empty code.'
})
else:
await self.send_message(socket, data)
async def send_message(self, socket: WebSocket, data: dict) -> None:
await socket.send_json(data)
if __name__ == "__main__":
uvicorn.run(
app,
port=5000,
proxy_headers=True,
workers=2
)
私は主に解析、非同期で実行したいタスク、スクレイピングなどを別のアプリケーションからエンドポイント経由で実行したい時によく使っています。
ここ最近ではKerasでNNを実行して、モデルを作らせるAPIとして実装しました。
パフォーマンス
PythonのWeb系のフレームワークのうち、Uvicornに次ぐ最高のパフォーマンスを発揮します。実際、StarletteはUvicornを使用して実行していますし、開発者も同じ方です。
Djangoも3.0でasgiへ転換を行っていますし、RX系が流行りだしてから非同期でアプリを作るのがスタンダードなってきています。また、ミドルウェアでCORS, ホストのアクセス制御,Prometheusエクスポーターがあります。こうしてみると、Kubernetesでの利用に向いていて、私はほとんどのインフラ設計をKubernetesで実装しているため、扱いやすく、利用頻度が高いので、お気に入りなんだと思います。
ググると記事もちらほらあるので、意外と人気?
Starlette’s API made this emulator as quick to produce as I could possibly hope for. The framework is still new, but I think it has a very promising future in the Python ecosystem. It already has the best performance of any Python framework in the TechEmpower Benchmarks. I hope you enjoyed looking at some async programming in Python.
引用元: https://www.mattlayman.com/blog/2019/starlette-mock-service/
StarletteでAPIアプリを実装して、GCPにCloudRunでデプロイしてみる
以下の手順で実装からGCPへのデプロイまですぐにできるので、迅速な開発が行えます。
ただ、最初から開発する機能が多く見込まれている場合はDjango+Restframeworkにしておいたほうが、開発スピードが早いです。どちらも同じ作者なのでフルスタック、軽量どちらのAPIも選択肢を用意されている感じでしょうか。
Gitのリポジトリを作っておきましたので、以下のトピックを複数回に渡って紹介したいと思います。