GitHubじゃ!Pythonじゃ!

GitHubからPython関係の優良リポジトリを探したかったのじゃー、でも英語は出来ないから日本語で読むのじゃー、英語社会世知辛いのじゃー

encode

apistar – Python 3用に設計されたスマートWeb APIフレームワーク。 🌟

投稿日:

Python 3用に設計されたスマートWeb APIフレームワーク。 🌟 https://discuss.apistar.org/

APIスター 🚀 🌟

Python 3用に設計されたスマートWeb APIフレームワーク。

コミュニティ: https : //discuss.apistar.org/ 🤔 💭 🤓 💬 😎


特徴

次のWeb APIプロジェクトにAPI Starを使用することを検討すべき理由は何ですか?

  • APIドキュメント – インタラクティブAPIドキュメント。常にコードベースと同期することが保証されています。
  • クライアントライブラリ – API Starが生成する型システムによって駆動されるJavaScriptおよびPythonクライアントライブラリ。
  • スキーマ生成 – SwaggerまたはRAML APIタイプシステムの生成をサポートします。
  • 表現型 – 表現可能でテスト可能なコードを作成する、注釈付きのビューを入力します。
  • パフォーマンス – 各ビューの実行方法を決定するための動的な動作により、API Starは非常に効率的になります。
  • スループット – 高スループットのノンブロッキングアプリケーションを構築できるasyncioのサポート。

目次


クイックスタート

API Starをインストールする:

$ pip3 install apistar

新しいプロジェクトを作成する:

$ apistar new .
app.py
tests.py
$ cat app.py
from apistar import Include, Route
from apistar.frameworks.wsgi import WSGIApp as App
from apistar.handlers import docs_urls, static_urls


def welcome(name=None):
    if name is None:
        return {'message': 'Welcome to API Star!'}
    return {'message': 'Welcome to API Star, %s!' % name}


routes = [
    Route('/', 'GET', welcome),
    Include('/docs', docs_urls),
    Include('/static', static_urls)
]

app = App(routes=routes)


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

アプリケーションを実行します。

$ apistar run
Running at http://localhost:8080/

テストを実行します。

$ apistar test
tests.py ..
===== 2 passed in 0.05 seconds =====

インタラクティブなAPIドキュメントを表示する:

$ open http://localhost:8080/docs/

フレームワークの選択

API Starを使用すると、標準のスレッド化されたWSGIアプリケーションまたはasyncioアプリケーションを使用できます。

WSGI

標準的なWSGIアプリケーションを選択する利点は、より優れたエコシステムサポートが得られることです。 SQLAlchemyとDjangoのORMバックエンドが利用でき、既存のPythonライブラリを幅広く使用することができます。

新しいwsgiプロジェクトを開始するには:

$ pip install apistar
$ apistar new .

コード内のアプリケーションのインポート行は、次のようになります。

from apistar.frameworks.wsgi import WSGIApp as App

ASyncIO

asyncioアプリケーションを使用する利点は、async / awaitを使用して協調的同時実行性を優先してスレッドブロッキング呼び出しを行うことを避けることができるため、スループットが向上する可能性があることです。 ただし、データベースへの呼び出し、ディスクからの読み取り、ネットワーク要求など、ブロック操作には非同期コンポーネントのみを使用する必要があります。

新しいasyncioプロジェクトを使用するには:

$ pip install apistar[asyncio]
$ apistar new . --framework asyncio

コード内のアプリケーションのインポート行は、次のようになります。

from apistar.frameworks.asyncio import ASyncIOApp as App

これで、通常のハンドラ関数または非同期ハンドラ関数を含めることができます…

def welcome(name=None):
    # A regular handler function that contains no asynchronous operations.
    ...

async def welcome(name=None):
    # An async handler, that may use `async/await` syntax for performing asynchronous operations.
    ...

HTTP

リクエスト

API Starを使用すると、入力注釈を使用して、着信要求に関するさまざまな情報をビューに動的に挿入できます。

from apistar import http

def show_request(request: http.Request):
    return {
        'method': request.method,
        'url': request.url,
        'headers': dict(request.headers)
    }

def show_query_params(query_params: http.QueryParams):
    return {
        'params': dict(query_params)
    }

def show_user_agent(user_agent: http.Header):
    return {
        'user-agent': user_agent
    }

最も頻繁に使用するコンポーネントの一部は次のとおりです。

成分 説明
http.Request HTTPリクエスト。 .method.url 、および.headers属性が.headersます。
http.Headers 要求ヘッダー。ディクショナリのようなオブジェクトとして返されます。
http.Header 引数名に対応する単一のリクエストヘッダを検索します。
文字列またはNone返します。
http.QueryParams 要求クエリパラメータ。辞書的なオブジェクトとして返されます。
http.QueryParam 引数名に対応する単一のクエリパラメータを検索します。
文字列またはNone返します。
http.Body 要求の本文。 バイト文字列を返します。
http.RequestData 解析された要求データ。 データ型は、要求のContent-Typeによって異なります。

反応

デフォルトでは、API starはビューがプレーンなデータを返すことを期待し、 200 OK応答を返します。

def create_project():
    return {'name': 'new project', 'id': 123}

代わりに、 Response返すことによってステータスコードまたはヘッダーを設定することができます。

def create_project():
    data = {'name': 'new project', 'id': 123}
    headers = {'Location': 'http://example.com/project/123/'}
    return Response(data, status=201, headers=headers)

URLルーティング

URLパスのパラメータに{curly_braces}を使用すると、URLパスのパラメータを含めることができます。

def echo_username(username):
    return {'message': f'Welcome, {username}!'}

app = App(routes=[
    Route('/{username}/', 'GET', echo_username)
])

ルートのリストをIncludeには、 Includeを使用しInclude

user_routes = [
    Route('/', 'GET', list_users),
    Route('/', 'POST', create_user),
    Route('/{user_id}', 'PUT', edit_user),
    Route('/{user_id}', 'DELETE', delete_user)
]

routes = [
    Include('/users', user_routes),
    ...
]

app = App(routes=routes)

タイプされたURLパス・パラメーターを組み込むには、ビュー・メソッドでタイプ注釈を使用します。

users = {0: 'penny', 1: 'benny', 2: 'jenny'}

def echo_username(user_id: int):
    username = users[user_id]
    return {'message': f'Welcome, {username}!'}

app = App(routes=[
    Route('/{user_id}/', 'GET', echo_username)
])

URLパスパラメータに対応しないパラメータは、 intstrなどのスカラー型、またはdictlist複合型の要求本体の一部のクエリパラメータとして扱われます。

def echo_username(username):
    if username is None:
        return {'message': 'Welcome!'}
    return {'message': f'Welcome, {username}!'}

app = App(routes=[
    Route('/hello/', 'GET', echo_username)
])

URLの逆転

URLを手作業で構築するのではなく、 reverse_url()を使用してエンドポイントに基づいてURLを生成することができます。

from apistar import reverse_url

def get_player_details(player_name):
    score = get_score(player_name)
    return {'name': player_name, 'score': score}

def get_all_players():
    players = get_players()
    player_list = [
        {
            'name': player.name,
            'url': reverse_url('get_player_details', player_name=player.name)
        }
        for player in players
    ]
    return {'players': player_list}

app = App(routes=[
    Route('/players/', 'GET', get_all_players),
    Route('/players/{player_name}/', 'GET', get_player_details),
])

コマンドルーティング

URLのルーティングに加えて、コマンドラインのクライアントに追加の機能を直接利用できるように、コマンドをルーティングすることもできます。

例えば…

from apistar import Command
from apistar.frameworks.wsgi import WSGIApp as App

...

routes = [
    ...
]

commands = [
    Command('create_user', create_user),
    Command('delete_user', delete_user)
]

app = App(routes=routes, commands=commands)

タイプシステム

API Starには、インターフェイスの予想される入力と出力に制約を表すことができるタイプシステムが付属しています。

ここでは、API Starの型システムの例を簡単に示します。

from apistar import typesystem

class Rating(typesystem.Integer):
    minimum = 1
    maximum = 5


class ProductSize(typesystem.Enum):
    enum = ['small', 'medium', 'large']


class Product(typesystem.Object):
    properties = {
        'name': typesystem.string(max_length=100),  # Use lowercase functions for inline declarations.
        'rating': Rating,
        'in_stock': typesystem.Boolean,
        'size': ProductSize,
    }

データ検証

型システムでデータ制約を表現する主な利点は、これらの型をハンドラ関数の注釈として使用できることです。

def create_product(product: Product):
    ...

routes = [
    Route('/create_product/', 'POST', create_product)
]

シリアライゼーション

入力検証に型システム型を使用することに加えて、それらを使用してハンドラ関数の戻り値をシリアル化することもできます。

import typing


def list_products() -> typing.List[Product]:
    queryset = ...  # Query returning products from a data store.
    return [Product(record) for record in queryset]

APIリファレンス

現在サポートされているタイプのシステムタイプは次のとおりです。

文字列

文字列データを検証します。 strのサブクラスです。

  • default – この型システムを使用するフィールドが親Objectない場合に使用されるデフォルト値。
  • max_length – データの最大有効長。
  • min_length – データの有効長の最小値。
  • pattern – データが一致しなければならない文字列またはコンパイルされた正規表現。
  • format – 文字列表現を持つ複合データ型を示す識別子。 たとえば、 "date"はISO 8601形式の日付文字列を表します。
  • trim_whitespace – 先頭と末尾の空白をデータから削除する必要がある場合はTrueです。 デフォルトはTrueです。
  • description – オンラインドキュメントの説明

数値データを検証します。 floatのサブクラスです。

  • default – この型システムを使用するフィールドが親Objectない場合に使用されるデフォルト値。
  • maximum – データの最大有効値を表す浮動小数点数。
  • minimum – データの最小有効値を表す浮動小数点数です。
  • exclusive_maximum – 排他的な最大限度の場合はTrueです。 デフォルトはFalseです。
  • exclusive_minimum – 排他的な最小限度の場合はTrueです。 デフォルトはFalseです。
  • multiple_of – 有効にするには、データを完全に割り切れる必要があります。
  • description – オンラインドキュメントの説明

整数

整数データを検証します。 intのサブクラスです。

  • default – この型システムを使用するフィールドが親Objectない場合に使用されるデフォルト値。
  • maximum – データの最大有効値を表すint
  • minimum – データの最小有効値を表すint
  • exclusive_maximum – 排他的な最大限度の場合はTrueです。 デフォルトはFalseです。
  • exclusive_minimum – 排他的な最小限度の場合はTrueです。 デフォルトはFalseです。
  • multiple_of – 有効にするには、データを完全に割り切れる整数でなければなりません。
  • description – オンラインドキュメントの説明

ブール

ブール値の入力を検証します。 TrueまたはFalse返します。

  • default – この型システムを使用するフィールドが親Objectない場合に使用されるデフォルト値。
  • description – オンラインドキュメントの説明

列挙型

有効な選択肢のリストに対して文字列入力を検証します。 strのサブクラスです。

  • default – この型システムを使用するフィールドが親Objectない場合に使用されるデフォルト値。
  • enum – データの有効な文字列値のリスト。
  • description – オンラインドキュメントの説明

オブジェクト

辞書またはオブジェクトの入力を検証します。 dictのサブクラスです。

  • default – この型システムを使用するフィールドが親Objectない場合に使用されるデフォルト値。
  • properties – 文字列のキー名を型システムまたは型の値にマッピングする辞書。
  • description – オンラインドキュメントの説明

子プロパティがdefault値を持たない場合、子プロパティは必須とみなされることに注意してください。

アレイ

リストまたはタプル入力を検証します。 listのサブクラスです。

  • items – タイプシステムまたはタイプ、またはタイプシステムまたはタイプのリスト。
  • additional_items – リストされた型システムタイプの最後を過ぎた追加アイテムが許可されるかどうか。
  • min_items – 配列に含める必要があるアイテムの最小数。
  • max_items – 配列に含まれるアイテムの最大数。
  • unique_items – 配列内で繰り返し項目を許可するかどうかを指定します。
  • description – オンラインドキュメントの説明

APIスキーマの生成

API Starは「APIスキーマ」と呼ばれるAPI記述形式にうまく対応できるように設計されています。

現在、Swagger、RAML、またはCoreJSONタイプシステムを作成するためのサポートがあります。 ここでもやるべき作業の詳細については、 #69を参照してください。

デフォルトの出力形式は、組み込みのCoreJSONサポートです。

$ apistar schema
{"_type":"document", ...}

OpenAPI(Swagger)コーデックとRAMLコーデックはオプションで、追加パッケージのインストールが必要です。

ふらふら

$ pip install openapi-codec
$ apistar schema --format openapi
{"swagger": "2.0", "info": ...}

RAML

$ pip install raml-codec
$ apistar schema --format raml
#%RAML 0.8
...

ウェブサイトの構築

API Starは主にWeb APIを念頭に置いて設計されていますが、汎用フレームワークであり、通常のWebサイトを構築するために必要なツールも提供します。

テンプレート

API Starには、Jinja2を使用してテンプレートレスポンスを返すことができるテンプレートコンポーネントが含まれています。

templates / index.html:

<html>
    <body>
        <h1>Hello, {{ username }}</h1>
    </body>
</html>

app.py:

from apistar import Route, annotate, render_template
from apistar.frameworks.wsgi import WSGIApp as App
from apistar.renderers import HTMLRenderer

@annotate(renderers=[HTMLRenderer()])
def hello(username: str):
    return render_template('index.html', username=username)

routes = [
    Route('/', 'GET', hello)
]

settings = {
    'TEMPLATES': {
        'ROOT_DIR': 'templates',     # Include the 'templates/' directory.
        'PACKAGE_DIRS': ['apistar']  # Include the built-in apistar templates.
    }
}

app = App(routes=routes, settings=settings)

ビューから文字列レスポンスを返すのは、デフォルトでtext/jsonコンテンツタイプを使用することです。 つまり、HTMLビューでtext/htmlコンテンツタイプを使用するように、これをオーバーライドする必要があります。 これを行うには、次のようないくつかの方法があります。

  1. HTMLRenderer使用するようにハンドラ関数に注釈を付けることによって(上記のように)
  2. 明示的なContent-Typeヘッダーを含むResponseを返すことで(例については、 Renderersセクションを参照)

静的ファイル

静的ファイルを提供するために、API Starはwhitenoiseを使用します

まず、 whitenoiseパッケージをインストールしてwhitenoise

$ pip install whitenoise

次に、あなたのルートにserve_staticハンドラを含める必要があります。 この関数は、 pathという単一のURL引数を取ることを想定していpath

from apistar import Route
from apistar.handlers import serve_static

routes = [
    # ...
    Route('/static/{path}', 'GET', serve_static)
]

最後に、静的ファイルを提供するディレクトリを以下のように設定します。

settings = {
    'STATICS': {
        'ROOT_DIR': 'statics',       # Include the 'statics/' directory.
        'PACKAGE_DIRS': ['apistar']  # Include the built-in apistar static files.
    }
}

app = App(routes=routes, settings=settings)

HTTPセッション

API Starは永続的なHTTPセッションをサポートします。 辞書に似たオブジェクトとしてセッションにアクセスできます。 このセッションは、 http.Sessionクラスをハンドラ上の注釈として含めることによって利用可能になります。 例えば:

from apistar import Response, http

def login(username: str, password: str, session: http.Session):
    if authenticate(username, password):
        session['username'] = username
        return Response(status=302, headers={'location': '/'})
    else:
        ...

def logout(session: http.Session):
    if 'username' in session:
        del session['username']
    return Response(status=302, headers={'location': '/'})

def homepage(session: http.Session):
    username = session.get('username')
    ...

デフォルトの実装では、セッション情報がローカルメモリに格納されますが、これは開発やテスト以外の目的には適していません。 プロダクションでは、何らかの永続ストレージと統合するセッションストアを実装する必要があります。

from apistar import Component
from apistar.interfaces import SessionStore
from myproject import RedisSessionStore  # A SessionStore implementation.

routes = [
    ...
]

components = [
    Component(SessionStore, init=RedisSessionStore)
]

app = App(routes=routes, components=components)

レンダラー&パーサー

レンダラーとパーサーは、着信または発信のバイトストリームの翻訳を処理します。

たとえば、レスポンスを返すときには、 dictlistなどのネイティブのPythonデータ構造を返すだけです。 レンダラークラスは、レスポンス本文に使用する必要があるバイトを生成します。

レンダラー

API StarはデフォルトでJSONレスポンスを返します。 この動作を変更するには、サポートするレンダラーを設定します。

インストールされているレンダラの設定

レンダラーは、設定に追加してインストールすることができます。 RENDERERS設定はリストにする必要があります。 たとえば、ほとんどのハンドラがHTMLレスポンスを返す場合は、次のようにします。

settings = {
    'RENDERERS': [HTMLRenderer()]
}

あるいは、特定のハンドラ関数で使用するレンダラを指定することもできます。

from apistar import annotate
from apistar.renderers import JSONRenderer
from myproject.renderers import CSVRenderer

@annotate(renderers=[JSONRenderer(), CSVRenderer()])
def download_current_dataset():
    # Return some data, formatted either as JSON or CSV,
    # depending on the request Accept header.
    ...

レンダラーの決定方法

API Starは、HTTPコンテンツネゴシエーションを使用して、返されるレンダラーを決定します。 Acceptヘッダーが検査され、使用可能なインストールされているレンダラーの1つが選択されます。 Acceptヘッダーがインストールされているレンダラーのいずれとも一致しない場合、 406 Not Acceptable応答が返されます。

Response返すときに明示的なcontent_type引数を含めることによって、コンテンツネゴシエーションを無効にすることができます。 例えば…

content = template.render(...)
return http.Response(content, content_type='text/html')

パーサー

要求のContent-Typeが指定されている場合、パーサーは受信した要求本体を取り出し、それが表すデータ構造体を返す責任があります。

デフォルトでは、API StarはJSONの解析やエンコードされたリクエストの作成をサポートしています。

インストールされているパーサーの設定

1つ以上のパーサーは、設定に追加してインストールできます。 PARSERS設定はリストにする必要があります。 たとえば、フォームの解析を無効にし、JSONリクエストのみをサポートする場合は、次のようにします。

settings = {
    'PARSERS': [JSONParser()]
}

あるいは、特定のハンドラ関数で使用するパーサを指定することもできます。

from apistar import annotate
from apistar.parsers import MultiPartParser

@annotate(parsers=[MultiPartParser()])
def file_upload():
    # Handles a file upload, using a multipart encoded request.
    ...

認証と権限

認証とは、受信した要求を、その要求が出されたユーザーやそれが署名されたトークンなどの識別証明書のセットに関連付けるメカニズムです。 アクセス許可は、要求を許可する必要があるかどうかを判断するために、これらの資格情報を使用するプロセスです。

認証

Authコンポーネントは、現在認証されているユーザーに関する情報を提供します。

from apistar.interfaces import Auth

def display_user(auth: Auth):
    return {
        'is_authenticated': auth.is_authenticated(),
        'user': auth.get_display_name()
    }

次のインタフェースを提供します。

  • .get_display_name() – ユーザ名を表示するときに使用する文字列を返します。認証されていないリクエストの場合はNoneを返します。
  • .get_user_id() – ユーザーを一意に識別するために使用できる文字列、または認証されていない要求の場合はNoneを返します。
  • .is_authenticated() – 認証された要求に対してはTrueを、そうでなければFalse返します。
  • .user – 永続的なユーザー情報への参照。
  • .token – 着信要求に関連する他の認証情報への参照。

上記の例ではまだ認証ポリシーを設定していないので、 auth引数は常にUnauthenticatedインスタンスに設定されます。

エンドポイントへのリクエストは、現在、次のような応答を返します。

{
    "is_authenticated": false,
    "user": null
}

認証クラスの作成

受信リクエストを認証するために、認証クラスを作成する必要があります。

認証クラスはauthenticateメソッドを実装する必要があり、 Authサブクラスを返します。要求が認証されていない場合はNoneを返します。

authenticateメソッドは、署名内にインストールされているコンポーネントを受け入れることができます。

import base64
from apistar import http
from apistar.authentication import Authenticated

class BasicAuthentication():
    def authenticate(self, authorization: http.Header):
        """
        Determine the user associated with a request, using HTTP Basic Authentication.
        """
        if authorization is None:
            return None

        scheme, token = authorization.split()
        if scheme.lower() != 'basic':
            return None

        username, password = base64.b64decode(token).decode('utf-8').split(':')
        return Authenticated(username)

Authenticatedクラスは、 Authサブクラスを実装する代わりに使用できるショートカットを提供することに注意してください。

認証ポリシーの設定

1つまたは複数の認証ポリシーを設定に追加してインストールできます。 AUTHENTICATION設定はリストにする必要があります。 各認証ポリシーは順番に試行されます。

settings = {
    'AUTHENTICATION': [BasicAuthentication()]
}

あるいは、特定のハンドラ関数に対して認証ポリシーを指定することもできます。

from apistar import annotate
from apistar.interfaces import Auth
from myproject.authentication import BasicAuthentication

@annotate(authentication=[BasicAuthentication()])
def display_user(auth: Auth):
    # There are no required permissions set on this handler, so all requests
    # will be allowed.
    # Requests that have successfully authenticated using basic authentication
    # will include user credentials in `auth`.
    ...

アクセス許可

通常は、提供された認証資格情報に基づいて、着信要求を許可または拒否する必要があります。

API Starには、組み込みのIsAuthenticatedパーミッションクラスが1つ含まれているか、より複雑なケースに対して独自に実装することができます。

アクセス許可クラスの作成

許可クラスはhas_permission()メソッドを実装し、要求を許可するかどうかに応じてTrueまたはFalseを返す必要があります。

たとえば、ユーザーモデルにis_adminフィールドが含まれている場合、そのユーザーに対してのみ特定の操作を許可することができます。

class IsAdminUser():
    def has_permission(self, auth: Auth):
        if not auth.is_authenticated():
            return False
        return auth.user.is_admin

アクセス許可ポリシーの設定

権限を設定することは認証を設定することと非常によく似ています。設定を使用してグローバルに行うことができます…

settings = {
    'AUTHENTICATION': [BasicAuthentication()],
    'PERMISSIONS': [IsAuthenticated()]
}

または、特定のハンドラにアクセス許可を設定する…

@annotate(
    authentication=[BasicAuthentication()],
    permissions=[IsAuthenticated()]
)
def display_user(auth: Auth):
    # Only authenticated requests will be allowed to access this handler.
    ...

設定と環境

アプリケーションの設定

アプリケーション設定は、アプリケーションをインスタンス化する時点で設定されます。

routes = [
    # ...
]

settings = {
    'TEMPLATES': {
        'ROOT_DIR': 'templates',
        'PACKAGE_DIRS': ['apistar']
    }
}

app = App(routes=routes, settings=settings)

Settingsタイプ注釈を使用すると、アプリケーション設定をビューに含めることができます。

from apistar import Settings


def debug_settings(settings: Settings):
    """
    Return a JSON response containing the application settings dictionary.
    """
    return settings

より一般的には、カスタムコンポーネントのbuildメソッドに設定を含めることで、アプリケーション設定に基づいて初期化を制御できるようにします。

環境

通常、「12因子アプリ」パターンに従って、 設定変数をソース管理下に置くのではなく、環境に保存したいと思うでしょう。

API Starには、 Environmentを読み込み、正しく設定されていることを確認できるEnvironmentクラスが用意されています。

from apistar import environment, typesystem


class Env(environment.Environment):
    properties = {
        'DEBUG': typesystem.boolean(default=False),
        'DATABASE_URL': typesystem.string(default='sqlite://')
    }

env = Env()

Environmentインスタンスを作成したら、アプリケーション設定を作成するときに使用できます。

settings = {
    'DATABASE': {
        'URL': env['DATABASE_URL']
    }
}

テスト

API Starにはpy.testのテストフレームワークが含まれてます。 次のコマンドを使って、すべてのテストをtests.pyモジュールまたはtests/ディレクトリで実行できます。

$ apistar test

ビューをテストする最も簡単な方法は、ビューを直接呼び出すことです。

from app import hello_world

def test_hello_world():
    assert hello_world() == {"hello": "world"}

また、 requestsライブラリーを使用して、アプリケーションに直接HTTP要求を行うことを可能にするテスト・クライアントもあります。

from app import app
from apistar import TestClient

def test_hello_world():
    client = TestClient(app)
    response = client.get('/hello_world/')
    assert response.status_code == 200
    assert response.json() == {"hello": "world"}

テストクライアントを使用して行われたリクエストは、相対URLまたは絶対URLのいずれかを使用できます。 いずれの場合も、外部リクエストを行うのではなく、すべてのリクエストがアプリケーションに送られます。

response = client.get('http://www.example.com/hello_world/')

バックエンド

SQLAlchemy

API StarにはSQLAlchemyのオプションサポートがあります。 これを使用するには、最初にsqlalchemyと選択したデータベース・ドライバーをインストールする必要があります。

$ pip install sqlalchemy
$ pip install psycopg2

設定

次に、設定にデータベース設定を追加し、SQLAlchemyの追加のコンポーネントとコマンドをインストールする必要があります。

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from apistar.frameworks.wsgi import WSGIApp as App
from apistar.backends import sqlalchemy_backend

Base = declarative_base()

class Customer(Base):
    __tablename__ = "Customer"
    id = Column(Integer, primary_key=True)
    name = Column(String)

routes = [
    # ...
]

# Configure database settings.
settings = {
    "DATABASE": {
        "URL": "postgresql://:@localhost/apistar",
        "METADATA": Base.metadata
    }
}

app = App(
    routes=routes,
    settings=settings,
    commands=sqlalchemy_backend.commands,  # Install custom commands.
    components=sqlalchemy_backend.components  # Install custom components.
)

いくつかの一般的なドライバ設定を以下に示します。

データベース ドライバ URLフォーマット
PostgreSQL psycopg2 postgresql://<username>:<password>@localhost/example
MySQL pymysql mysql+pymysql://<username>:<password>@localhost/example
SQLite sqlite3 (Python組み込み) sqlite:///example.db

データベーステーブルの作成

アプリケーションを起動する前に、次のコマンドで実行できるMetaDataで宣言されたデータベーステーブルを作成する必要があります。

$ apistar create_tables

マイグレーション SQLアルケミーでアルレビックマイグレーションを使用する場合は、以下のパッケージを使用できます

https://github.com/colanconnon/apistar_alembic_migrations

データベースとのやりとり

データベースと対話するには、 Sessionコンポーネントを使用します。 これにより、ビューが正常に戻るか、例外が発生するかによって、コミット/ロールバックの動作が自動的に処理されます。

from apistar.backends.sqlalchemy_backend import Session

def create_customer(session: Session, name: str):
    customer = Customer(name=name)
    session.add(customer)
    session.flush()  # Flush the changes to the database. This will populate the customer id.
    return {'id': customer.id, 'name': customer.name}

def list_customers(session: Session):
    queryset = session.query(Customer).all()
    return [
        {'id': customer.id, 'name': customer.name}
        for customer in queryset
    ]

代わりに、ハンドラ内の基本的なデータベース構成情報にアクセスするには、 SQLAlchemyコンポーネントを使用します。

これには次の属性があります。

  • engine – グローバルEngineインスタンス。
  • metadata – 設定に渡されるMetaDataオブジェクトです。
  • Session – バインドされたSession sessionmakerファクトリです。

Django ORM

API Starには、 Django ORMのオプションサポートがあります。 これを使うには、まずdjangoと選択したデータベースドライバをインストールする必要があります。

$ pip install django
$ pip install psycopg2

設定

次に、あなたの設定とdjangoの移行コマンドにデータベース設定を追加する必要があります:

from apistar.frameworks.wsgi import WSGIApp as App
from apistar.backends import django_orm


routes = [
   # ...
]

# Configure database settings.
settings = {
    'DATABASES': {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': '...',
            'HOST': 'localhost',
            'USER': '...',
            'PASSWORD': ''
        }
    },
    'INSTALLED_APPS': ['project',]
}


app = App(
    routes=routes,
    settings=settings,
    commands=django_orm.commands,  # Install custom commands.
    components=django_orm.components  # Install custom components.
)

移行

また、 migrationsディレクトリをprojectディレクトリ内に手動で作成する必要があります。

アプリを起動する前に、次のコマンドを使って移行する必要があります。

$ apistar makemigrations
$ apistar migrate

新しいモデルを作成する

新しいDjangoモデルを作成するには、新しいmodels.pyファイルを作成し宣言したいと思うでしょう。

from django.db import models

class Customer(models.Model):
    name = models.CharField(max_length=255)

Accessing the database

To interact with the database, use the Session component. This will automatically handle commit/rollback behavior, depending on if the view returns normally, or raises an exception:

from apistar.backends.django_orm import Session

def create_customer(session: Session, name: str):
    customer = session.Customer(name=name)
    customer.save()
    return {'id': customer.id, 'name': customer.name}

def list_customers(session: Session):
    queryset = session.Customer.objects.all()
    return [
        {'id': customer.id, 'name': customer.name}
        for customer in queryset
    ]

コンポーネント

You can create new components to inject into your views. 例えば:

import base64

class User(object):
    """
    A component representing the user that the incoming request is associated with.
    """
    def __init__(self, username):
        self.username = username


def authenticate_user(authorization: http.Header):
    """
    Determine the user associated with a request, using HTTP Basic Authentication.
    """
    if authorization is None:
        return None
    scheme, token = authorization.split()
    if scheme.lower() != 'basic':
        return None
    username, password = base64.b64decode(token).decode('utf-8').split(':')
    return User(username)

Next, register your component with the application:

from apistar import Component

components = [
    Component(User, init=authenticate_user)
]

app = App(
    routes=routes,
    components=components
)

You can then use your component in a view:

def say_hello(user: User):
    return {'hello': user.username}

Component Reference

A complete listing of the available built-in components:

成分 説明
http.Method The HTTP method of the request, such as GET .
http.Host The host component of the request URL, such as 'example.com' .
http.Port The port number that the request is made to, such as 443.
http.Scheme The scheme component of the request URL, such as ‘https’.
http.Path The path component of the request URL, such as /api/v1/my_view/ .
http.QueryString The query component of the request URL, such as page=2 .
http.URL The full URL of the request, such as https://example.com/api/v1/my_view/?page=2 .
http.Body The body of the request, as a bytestring.
http.QueryParams A multi-dict containing the request query parameters.
http.QueryParam A single request query parameter, corresponding to the keyword argument name. Automatically used for data arguments.
http.Headers A multi-dict containing the request headers parameters.
http.Header A single request query parameter, corresponding to the keyword argument name.
http.Request The full request instance.
interfaces.App The current application.
interfaces.Console The console interface. Supports the .echo(message) interface.
interfaces.CommandLineClient The command line parsing component. Supports the .parse(args) interface.
interfaces.Injector Makes the dependency injection available to handler. Supports the .run(func) interface.
interfaces.Router The router for the application instance. Supports the reverse_url(name, **values) interface.
interfaces.Schema The CoreAPI schema used to represent the API.
interfaces.StaticFiles The static files component. Supports the get_url(path) interface.
interfaces.Templates The template environment. Supports the get_template(path) interface.
types.KeywordArgs A dictionary containing all the matched URL path arguments, or parsed command line parameters.
types.ParamName A string representing the keyword argument with which a component is being injected into the view. May be for components that vary depending on the parameter name used.
types.PathWildcard 文字列。 May be used for URL path components that should support full wildcard matches, allowing ‘/’ characters.
types.Settings A dictionary containing the application settings.
types.WSGIEnviron A dictionary containing the raw WSGI environ of the incoming request.

Performance

API Star dynamically determines exactly what does and does not need to run for any given view, based on the annotations it includes. This means that it can be incredibly efficient.

For a simple JSON serialization test case, the TechEmpower benchmarks rank API Star as achieving the highest throughput of any Python, JavaScript, Ruby, or Go framework.

We’ll be working towards adding further test case types to the TechEmpower benchmarks in the coming weeks, and including results from both WSGIApp and ASyncIOApp deployment modes.

Its also important to recognize that raw latency or throughput numbers are typically not the most important factor to take into consideration when choosing a framework. Having said that, one aim for API Star is to hit the sweet spot for both performance and for productivity.


配置

The Development Server

A development server is available, using the run command:

$ apistar run
# Specify the port or interface via --port and --host
# Serve on port 9001 and use IPv6 only
$ apistar run --port 9001 --host ::1
# If you don't like the Werkzeug web debugger, turn it off
$ apistar run --no-debugger

Running in Production

Running a WSGIApp project

For WSGI applications, the recommended production deployment is Gunicorn, using the Meinheld worker.

$ pip install gunicorn
$ pip install meinheld
$ gunicorn app:app --workers=4 --bind=0.0.0.0:5000 --pid=pid --worker-class=meinheld.gmeinheld.MeinheldWorker

Typically you’ll want to run as many workers as you have CPU cores on the server.

Running an ASyncIOApp project

For asyncio applications, use uvicorn .

$ uvicorn app:app --workers=4 --bind=0.0.0.0:5000 --pid=pid

Again, you’ll typically want to run as many workers as you have CPU cores on the server.

“Serverless” deployments

API Star can also be deployed on so called “serverless” platforms. A good option for using API Star with this style of deployment is Zappa , which allows you to deploy any Python WSGI server onto AWS Lambda.

Note that only WSGIApp is supported using Zappa. You cannot run an ASyncIOApp under this deployment, as a standard WSGI interface is expected.

For Zappa to execute it needs to be provided with the path to your app instance in its app_function key. Given that your app is contained within app.py , eg

# app.py
app = App(routes=routes, settings=settings)

Your zappa_settings.json configuration file should then look something like this:

{
    "dev": {
        "app_function": "app.app",
        "aws_region": "us-east-1",
        "profile_name": "default",
        "s3_bucket": "<a-unique-s3-bucket-name>",
        "keep_warm": false
    },
    "prod": {
        "app_function": "app.app",
        "aws_region": "us-east-1",
        "profile_name": "default",
        "s3_bucket": "<a-unique-s3-bucket-name>",
        "debug": false,
        "log_level": "WARNING",
        "apigateway_description": "Description of your app on AWS API Gateway",
        "lambda_description": "Description of your app on AWS Lambda",
    }
}

See Zappa’s installation instructions for full configuration details.

ノート

  • keep_warm is a four minute callback to AWS to ensure your function stays loaded in AWS, decreasing the initial response time. When doing development work you don’t really need the function to stay ‘warm’ 24/7 so by setting it to false in dev it will save you some AWS invocation requests. The free tier at AWS gives you 1,000,000 free requests so it shouldn’t matter too much.
  • profile_name specifies which alias to use in your AWS Credentials file. This is usually located at ~/.aws/credentials .
[default]
aws_access_key_id = 'xxx'
aws_secret_access_key = 'xxx'

To successfully run zappa deploy you will need an IAM user on your AWS account with the a sufficiently permissive policy attached. See the discussions on Zappa’s minimum policy requirements for more details.


変更ログ

0.3 Release

  • Added Authentication & Permissions support.
  • Added Parsers & Renderers support, with content negotiation.
  • Added HTTP Session support.
  • Added BEFORE_REQUEST / AFTER_REQUEST settings.
  • Added SCHEMA settings.
  • Added support for using Injector component inside a handler.

Note: Because we now support configurable renderers, there’s a difference in the behaviour of returning plain data, or a Response without a content_type set. Previously we would return HTML for strings/bytes, and JSON for anything else. Now, JSON is the default for everything, unless alternative renderers are specified. See the “Renderers & Parsers” and “Requests & Responses” section for more detail.

0.2 Release

  • Added asyncio support.
  • Added app.main() .
  • Added Session support for both SQLAlchemy and DjangoORM backends.
  • Added proper support for registering commands, and using components in command handler functions.
  • Added proper support for registering new components, and separating component interfaces from component implementations.
  • Introduced from apistar.frameworks.wsgi import WSGIApp as App instead of from apistar import App .
  • Introduced from apistar.frameworks.asyncio import ASyncIOApp as App instead of from apistar import App .
  • Changed apistar new --layout [minimal|standard] to apistar new --framework [wsgi|asyncio] .
  • The TestClient() class now explicitly requires the app instance to be passed as an argument.
  • Dropped overloaded typesystem classes. Use eg. typesystem.String for declarations and typesystem.string() for inlines.
  • Dropped single-lookup component Template . Just use Templates instead.
  • Dropped single-lookup component Setting . Just use Settings instead.
  • Dropped unneccessary ResponseData annotation.
  • Dropped WSGIResponse . Either return data or a Response .
  • Dropped build() method on components. See the docs for information on creating and registering components.
  • Rationalized the ‘TEMPLATES’ and ‘STATICS’ settings.

開発

To work on the API Star codebase, you’ll want to clone the repository, and create a Python virtualenv with the project requirements installed:

$ git clone git@github.com:tomchristie/apistar.git
$ cd apistar
$ ./scripts/setup

To run the continuous integration tests and code linting:

$ ./scripts/test
$ ./scripts/lint

API Star is BSD licensed code.
Designed & built in Brighton, England.

⭐️







-encode
-, ,

執筆者: