動物相を使用してPythonRESTAPIを構築し、DigitalOceanAppPlatformにデプロイする方法

提供:Dev Guides
移動先:案内検索

序章

多くの開発者には、アプリケーションのインフラストラクチャをセットアップおよび管理するための時間や経験がありません。 期限に遅れずにコストを削減するには、開発者は、コードの記述と顧客への新機能の提供に集中するために、アプリをできるだけ迅速かつ効率的にクラウドにデプロイできるソリューションを見つける必要があります。 DigitalOceanのAppPlatformFaunaが一緒になってその機能を提供します。

DigitalOcean App Platformは、アプリを実行するインフラストラクチャを抽象化するPlatform-as-a-Service(PaaS)です。 また、コードをGitブランチにプッシュすることでアプリケーションをデプロイすることもできます。

動物相は、あらゆるサイズのアプリケーション向けの強力なデータレイヤーです。 このチュートリアルでわかるように、Faunaを使用すると、データベースの操作を気にすることなく、データベースをすばやく起動して実行できます。

これら2つのソリューションを組み合わせることで、インフラストラクチャを管理するのではなく、アプリケーションに集中できます。

このチュートリアルでは、 Flaskフレームワークを使用して最小限のRESTAPIを記述し、FaunaをPythonと統合します。 次に、GitリポジトリからDigitalOceanのAppPlatformにAPIをデプロイします。APIは次のもので構成されます。

  • Usersコレクションにユーザーを作成するためのパブリック/signupPOSTエンドポイント。
  • Usersコレクション内のドキュメントで認証するためのパブリック/loginPOSTエンドポイント。
  • Thingsコレクションから動物相ドキュメントのリストをフェッチするためのプライベート/thingsGETエンドポイント。

完成したPythonプロジェクトは、このGithubリポジトリで入手できます。

前提条件

このチュートリアルを開始する前に、次のものが必要です。

ステップ1—動物相データベースの設定

最初のステップでは、動物相データベースを構成し、APIのコレクションを作成します。 動物相は、従来のテーブルベースのリレーショナルデータベースではなく、ドキュメントベースのデータベースです。 動物相は、ドキュメントのグループであるドキュメントとコレクションにデータを保存します。

コレクションを作成するには、Faunaのネイティブクエリ言語であるFQLを使用してクエリを実行します。 FQLは、表現力豊かで強力なクエリ言語であり、Faunaの全機能にアクセスできます。

開始するには、動物相のダッシュボードにログインします。 ログイン後、上部のデータベース作成ボタンをクリックしてください。

New Database フォームで、データベース名にPYTHON_APIを使用します。

デモデータの事前入力のチェックを外したままにします。 保存ボタンを押します。

データベースを作成すると、データベースのホームセクションが表示されます。

次に、2つのコレクションを作成します。

  • 認証情報を含むドキュメントを保存するUsersコレクション。
  • Thingsコレクションは、APIをテストするための模擬データを保存します。

これらのコレクションを作成するには、ダッシュボードのシェルでいくつかのFQLクエリを実行します。 左側のメインダッシュボードメニューからシェルにアクセスします。

シェルの下部パネルに次のFQLクエリを記述し、CreateCollection関数を使用してThingsというコレクションを作成します。

CreateCollection({name: "Things"})

RUNQUERYボタンを押します。 シェルのトップパネルに次のような結果が表示されます。

{
  ref: Collection("Things"),
  ts: 1614805457170000,
  history_days: 30,
  name: "Things"
}

結果は4つのフィールドを示しています。

  • refは、コレクション自体への参照です。
  • tsは、マイクロ秒単位の作成のタイムスタンプです。
  • history_daysは、Faunaがドキュメントの変更に対する変更を保持する期間です。
  • nameはコレクション名です。

次に、次のクエリを使用してUsersコレクションを作成します。

CreateCollection({name: "Users"})

両方のコレクションが配置されたので、最初のドキュメントを作成します。

動物相のドキュメントは、JSONオブジェクトにいくぶん似ています。 ドキュメントには文字列、数値、配列を格納できますが、動物相データ型を使用することもできます。 一般的な動物相のタイプはRefで、コレクション内のドキュメントへの参照を表します。

Create 関数は、指定されたコレクションに新しいドキュメントを作成します。 次のクエリを実行して、Thingsコレクションに2つのフィールドを持つドキュメントを作成します。

Create(
  Collection("Things"),
  {
    data: {
      name: "Banana",
      color: "Yellow"
    }
  }
)

そのクエリを実行した後、Faunaは作成されたドキュメントを返します。

{
  ref: Ref(Collection("Things"), "292079274901373446"),
  ts: 1614807352895000,
  data: {
    name: "Banana",
    color: "Yellow"
  }
}

結果には、次のフィールドが表示されます。

  • タイプRefrefは、ID292079274901373446Thingsコレクションにあるこのドキュメントへの参照です。 ドキュメントのIDは異なることに注意してください。
  • tsは、マイクロ秒単位の作成のタイムスタンプです。
  • dataは、ドキュメントの実際のコンテンツです。

この結果は、コレクションを作成したときに得られた結果と似ています。 これは、Faunaのすべてのエンティティ(コレクション、インデックス、ロールなど)が実際にはドキュメントとして保存されているためです。

ドキュメントを読み取るには、ドキュメントの参照を受け入れるGet関数を使用します。 ドキュメントの参照を使用して、Getクエリを実行します。

Get(Ref(Collection("Things"), "292079274901373446"))

結果は完全なドキュメントです:

{
  ref: Ref(Collection("Things"), "292079274901373446"),
  ts: 1614807352895000,
  data: {
    name: "Banana",
    color: "Yellow"
  }
}

コレクションに保存されているドキュメントのすべての参照を取得するには、Documents関数とPaginate関数を使用します。

Paginate(Documents(Collection("Things")))

このクエリは、参照の配列を含むページを返します。

{
  data: [Ref(Collection("Things"), "292079274901373446")]
}

参照の代わりに実際のドキュメントを取得するには、Mapを使用して参照を繰り返し処理します。 次に、 Lambda (無名関数)を使用して、参照の配列とGet各参照を反復処理します。

Map(
  Paginate(Documents(Collection("Things"))),
  Lambda("ref", Get(Var("ref")))
)

結果は、完全なドキュメントを含む配列です。

{
  data: [
    {
      ref: Ref(Collection("Things"), "292079274901373446"),
      ts: 1614807352895000,
      data: {
        name: "Banana",
        color: "Yellow"
      }
    }
  ]
}

次に、Users_by_usernameインデックスを作成します。 通常、Faunaでインデックスを使用してデータをカタログ化、フィルタリング、および並べ替えますが、一意の制約を適用するなどの他の目的にも使用できます。

Users_by_usernameインデックスは、usernameでユーザーを検索し、2つのドキュメントが同じusernameを持つことを防ぐために一意の制約を適用します。

シェルで次のコードを実行して、インデックスを作成します。

CreateIndex({
  name: "Users_by_username",
  source: Collection("Users"),
  terms: [{ field: ["data", "username"] }],
  unique: true
})

CreateIndex 関数は、構成された設定でインデックスを作成します。

  • nameはインデックスの名前です。
  • sourceは、インデックスがデータのインデックスを作成する1つまたは複数のコレクションです。
  • termsは、このインデックスを使用してドキュメントを検索するときにこのインデックスに渡す検索/フィルター用語です。
  • uniqueは、インデックス付けされた値が一意になることを意味します。 この例では、Usersコレクション内のドキュメントのusernameプロパティが一意として適用されます。

インデックスをテストするには、Faunaシェルで次のコードを実行して、Usersコレクション内に新しいドキュメントを作成します。

Create(
  Collection("Users"),
  {
    data: {
      username: "sammy"
    }
  }
)

次のような結果が表示されます。

{
  ref: Ref(Collection("Users"), "292085174927098368"),
  ts: 1614812979580000,
  data: {
    username: "sammy"
  }
}

次に、同じusername値でドキュメントを作成してみます。

Create(
  Collection("Users"),
  {
    data: {
      username: "sammy"
    }
  }
)

今すぐエラーが表示されます:

Error: [
  {
    "position": [
      "create"
    ],
    "code": "instance not unique",
    "description": "document is not unique."
  }
]

インデックスが作成されたので、インデックスをクエリして1つのドキュメントをフェッチできます。 シェルで次のコードを実行して、インデックスを使用してsammyユーザーをフェッチします。

Get(
  Match(
    Index("Users_by_username"),
    "sammy"
  )
)

仕組みは次のとおりです。

  • Index は、Users_by_usernameインデックスへの参照を返します。
  • Match は、一致したドキュメント(sammyの値を持つusernameを持つドキュメント)への参照を返します。
  • Getは、Matchによって返された参照を取得し、実際のドキュメントをフェッチします。

このクエリの結果は次のようになります。

{
  ref: Ref(Collection("Users"), "292085174927098368"),
  ts: 1614812979580000,
  data: {
    username: "sammy"
  }
}

Delete 関数への参照を渡して、このテストドキュメントを削除します。

Delete(Ref(Collection("Users"), "292085174927098368"))

次に、Faunaのセキュリティ設定を構成して、コードからFaunaに接続できるようにします。

ステップ2—サーバーキーと承認ルールの構成

このステップでは、PythonアプリケーションがFaunaとの通信に使用するサーバーキーを作成します。 次に、アクセス許可を構成します。

キーを作成するには、左側のメインメニューを使用して、動物相ダッシュボードのセキュリティセクションに移動します。 そこに着いたら:

  1. 新しいキーボタンを押します。
  2. サーバーの役割を選択します。
  3. 保存を押します。

保存後、ダッシュボードにキーの秘密が表示されます。 シークレットを安全な場所に保存し、Gitリポジトリにコミットしないでください。

警告サーバーの役割は全能であり、この秘密を持っている人は誰でもデータベースに完全にアクセスできます。 その名前が示すように、これは信頼できるサーバーアプリケーションで通常使用される役割ですが、特権が制限されたカスタム役割でキーを作成することもできます。 本番アプリケーションを作成するときは、より制限的な役割を作成する必要があります。


デフォルトでは、Faunaのすべてが非公開であるため、ログインしたユーザーがThingsコレクションからドキュメントを読み取れるようにする新しい役割を作成します。

ダッシュボードのセキュリティセクションで、ロールに移動し、Userという名前の新しいカスタムロールを作成します。

コレクションドロップダウンで、Thingsコレクションを追加し、読み取り権限を押して、緑色のチェックマークを表示します。

ロールを保存する前に、メンバーシップタブに移動し、Usersコレクションをロールに追加します。

保存ボタンを押すと、Userカスタムロールを保存できるようになりました。

これで、Usersコレクションのドキュメントからログインしているユーザーは、Thingsコレクションのすべてのドキュメントを読み取ることができます。

認証と承認が整ったら、Faunaと通信するPythonAPIを作成しましょう。

ステップ3—Pythonアプリケーションの構築

このステップでは、Flaskフレームワークを使用して小さなREST APIを構築し、PythonでFQLクエリを記述し、Faunaドライバーを使用してFaunaデータベースに接続します。

開始するには、プロジェクトフォルダを作成し、ターミナルからアクセスします。

最初にFlaskをインストールします。

pip install flask

次に、FaunaPythonドライバーを次のコマンドでインストールします。

pip install faunadb

プロジェクトフォルダーで、ファイルmain.pyを作成し、次のコードをファイルに追加します。これにより、必要なインポート、FAUNA_SECRET環境変数、およびFlaskアプリケーションの基本構成が追加されます。

main.py

import os
FAUNA_SECRET = os.environ.get('FAUNA_SECRET')

import flask
from flask import request

import faunadb
from faunadb import query as q
from faunadb.client import FaunaClient

app = flask.Flask(__name__)
app.config["DEBUG"] = True

FAUNA_SECRET環境変数は、前に作成したサーバーシークレットを保持します。 このアプリケーションをローカルまたはクラウドで実行できるようにするには、この変数を挿入する必要があります。 これがないと、アプリケーションは動物相に接続できません。 アプリを起動するときに、この環境変数を指定します。

次に、/signupルートをmain.pyファイルに追加します。 これにより、Usersコレクションに新しいドキュメントが作成されます。

main.py

@app.route('/signup', methods=['POST'])
def signup():

    body = request.json
    client = FaunaClient(secret=FAUNA_SECRET)

    try:
        result = client.query(
            q.create(
                q.collection("Users"),
                {
                    "data": {
                        "username": body["username"]
                    },
                    "credentials": {
                        "password": body["password"]
                    }
                }
            )
        )

        return {
            "userId": result['ref'].id()
        }

    except faunadb.errors.BadRequest as exception:
        error = exception.errors[0]
        return {
            "code": error.code,
            "description": error.description
        }, 409

Faunaクライアントは、サーバーシークレットを使用してすべてのリクエストでインスタンス化されていることに注意してください。

main.py

...
client = FaunaClient(secret=FAUNA_SECRET)
...

ユーザーがログインすると、APIは異なるシークレットを使用して各ユーザーに代わってクエリを実行します。そのため、リクエストごとにクライアントをインスタンス化するのが理にかなっています。

他のデータベースとは異なり、Faunaクライアントは永続的な接続を維持しません。 外の世界から見ると、FaunaはAPIのように動作します。 すべてのクエリは単一のHTTPリクエストです。

クライアントの準備が整うと、FQLクエリが実行され、Usersコレクションに新しいドキュメントが作成されます。 各Faunaドライバーは、慣用的な構文をFQLステートメントに変換します。 このルートでは、次のクエリを追加しました。

main.py

...
q.create(
    q.collection("Users"),
    {
        "data": {
            "user": json["user"]
        },
        "credentials": {
            "password": json["password"]
        }
    }
)
...

これは、このクエリがネイティブFQLでどのように表示されるかを示しています。

Create(
    Collection("Users"),
    {
        "data": {
            "user": "sammy"
        },
        "credentials": {
            "password": "secretpassword"
        }
    }
)

ドキュメントデータに加えて、ユーザーのパスワードを使用してcredentials構成を追加します。 ドキュメントのこの部分は完全に非公開です。 その後、ドキュメントのクレデンシャルを読み取ることはできなくなります。 動物相の認証システムを使用する場合、ユーザーのパスワードを誤って公開することはできません。

最後に、同じユーザー名のユーザーがすでに存在する場合、faunadb.errors.BadRequest例外が発生し、エラー情報を含む409応答がクライアントに返されます。

次に、main.pyファイルに/loginルートを追加して、ユーザーとパスワードを認証します。 これは、前の例と同様のパターンに従います。 動物相接続を使用してクエリを実行し、認証が失敗した場合、faunadb.errors.BadRequest例外を発生させ、エラー情報を含む401応答を返します。 このコードをmain.pyに追加します。

main.py

@app.route('/login', methods=['POST'])
def login():

    body = request.json
    client = FaunaClient(secret=FAUNA_SECRET)

    try:
        result = client.query(
            q.login(
                q.match(
                    q.index("Users_by_username"),
                    body["username"]
                ),
                {"password": body["password"]}
            )
        )

        return {
            "secret": result['secret']
        }

    except faunadb.errors.BadRequest as exception:
        error = exception.errors[0]
        return {
            "code": error.code,
            "description": error.description
        }, 401

これは、Faunaでユーザーを認証するために使用されるFQLクエリです。

main.py

q.login(
    q.match(
        q.index("Users_by_username"),
        body["username"]
    ),
    {"password": body["password"]}
)

これは、このクエリがネイティブFQLでどのように表示されるかを示しています。

Login(
    Match(
        Index("Users_by_username"),
        "sammy"
    ),
    {"password": "secretpassword"}
)

Matchは、前に作成したUsers_by_usernameインデックスを使用してドキュメントへの参照を返します。

提供されたパスワードが参照されたドキュメントと一致する場合、Loginは新しいトークンを作成し、次のキーを持つ辞書を返します。

  • ref新しいドキュメントのトークンへの参照。
  • tsとトランザクションのタイムスタンプ。
  • instance認証に使用されたドキュメントへの参照。
  • secretは、動物相へのさらなるクエリを行うために使用されるトークンの秘密を持ちます。

そのFQLクエリをFaunaダッシュボードのシェルに実行すると、次のようなものが表示されます。

{
  ref: Ref(Ref("tokens"), "292001047221633538"),
  ts: 1614732749110000,
  instance: Ref(Collection("Users"), "291901454585692675"),
  secret: "fnEEDWVnxbACAgQNBIxMIAIIKq1E5xvPPdGwQ_zUFH4F5Dl0neg"
}

プロジェクトのセキュリティ要件に応じて、トークンのシークレットを処理する方法を決定する必要があります。 このAPIがブラウザーによって使用されることを意図している場合は、安全なCookieまたは暗号化されたJSON Webトークン(JWT)内にシークレットを返すことができます。 または、Redisインスタンスなど、別の場所にセッションデータとして保存することもできます。 このデモの目的のために、HTTP応答の本文でそれを返します。

最後に、このコードをmain.pyに追加します。これにより、Flaskアプリケーションが起動します。

main.py

app.run(host=os.getenv('IP', '0.0.0.0'), port=int(os.getenv('PORT', 8080)))

0.0.0.0アドレスを指定することが重要です。 クラウドにデプロイされると、このアプリケーションはDockerコンテナで実行されます。 Flaskアプリケーションのデフォルトアドレスである127.0.0.1で実行されている場合、リモートクライアントからのリクエストを受信することはできません。

これは、これまでの完全なmain.pyファイルです。

main.py

import os
FAUNA_SECRET = os.environ.get('FAUNA_SECRET')

import flask
from flask import request

import faunadb
from faunadb import query as q
from faunadb.client import FaunaClient

app = flask.Flask(__name__)
app.config["DEBUG"] = True

@app.route('/signup', methods=['POST'])
def signup():

    body = request.json
    client = FaunaClient(secret=FAUNA_SECRET)

    try:
        result = client.query(
            q.create(
                q.collection("Users"),
                {
                    "data": {
                        "username": body["username"]
                    },
                    "credentials": {
                        "password": body["password"]
                    }
                }
            )
        )

        return {
            "userId": result['ref'].id()
        }

    except faunadb.errors.BadRequest as exception:
        error = exception.errors[0]
        return {
            "code": error.code,
            "description": error.description
        }, 409

@app.route('/login', methods=['POST'])
def login():

    body = request.json
    client = FaunaClient(secret=FAUNA_SECRET)

    try:
        result = client.query(
            q.login(
                q.match(
                    q.index("Users_by_username"),
                    body["username"]
                ),
                {"password": body["password"]}
            )
        )

        return {
            "secret": result['secret']
        }

    except faunadb.errors.BadRequest as exception:
        error = exception.errors[0]
        return {
            "code": error.code,
            "description": error.description
        }, 401

app.run(host=os.getenv('IP', '0.0.0.0'), port=int(os.getenv('PORT', 8080)))

ファイルを保存します。

ターミナルからこのサーバーをローカルで起動するには、サーバーキーの作成時に取得したシークレットを使用してFAUNA_SECRET環境変数を指定して次のコマンドを使用します。

FAUNA_SECRET=your_fauna_server_secret python main.py

そのコマンドをトリガーした後、Flaskは開発WSGIサーバーで実行されていることを通知する警告を表示します。 このデモではこれで問題ないため、この警告は無視してかまいません。

curlコマンドを使用してHTTPリクエストを作成し、APIをテストします。 新しいターミナルウィンドウを開き、次のコマンドを実行します。

次のコマンドでユーザーを作成します。

curl -i -d '{"user":"sammy", "password": "secretpassword"}' -H 'Content-Type: application/json' -X POST http://0.0.0.0:8080/signup

ユーザーの作成が成功したことを示す次の応答が表示されます。

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 37
Server: Werkzeug/1.0.1 Python/3.9.2
Date: Thu, 04 Mar 2021 01:00:47 GMT

{
  "userId": "292092166117786112"
}

次に、次のコマンドでそのユーザーを認証します。

curl -i -d '{"user":"sammy", "password": "secretpassword"}' -H 'Content-Type: application/json' -X POST http://0.0.0.0:8080/login

この成功した応答が得られます:

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 70
Server: Werkzeug/1.0.1 Python/3.9.2
Date: Thu, 04 Mar 2021 01:01:19 GMT

{
  "secret": "fnEEDbhO3jACAAQNBIxMIAIIOlDxujk-VJShnnhkZkCUPKIHxbc"
}

curlコマンドを実行したターミナルウィンドウを閉じて、Pythonサーバーが実行されているターミナルに戻ります。 CTRL+Cを押してサーバーを停止します。

アプリケーションが機能するようになったので、ユーザーの認証を必要とするプライベートエンドポイントを追加します。

ステップ4—プライベートエンドポイントを追加する

このステップでは、APIにプライベートエンドポイントを追加します。これには、最初にユーザーを認証する必要があります。

まず、main.pyファイルに新しいルートを作成します。 このルートは、/thingsエンドポイントに応答します。 app.run()メソッドでサーバーを起動する行の上に配置します。

main.py

@app.route('/things', methods=['GET'])
def things():

次に、/thingsルートで、Faunaクライアントをインスタンス化します。

main.py

    userSecret = request.headers.get('fauna-user-secret')
    client = FaunaClient(secret=userSecret)

このルートでは、サーバーシークレットを使用する代わりに、Faunaクライアントのインスタンス化に使用されるfauna-user-secretHTTPヘッダーからのユーザーシークレットを使用します。 サーバーシークレットの代わりにユーザーシークレットを使用することにより、FQLクエリは、ダッシュボードで以前に構成した承認ルールの対象になります。

次に、このtryブロックをルートに追加して、クエリを実行します。

main.py

    try:
        result = client.query(
            q.map_(
                q.lambda_("ref", q.get(q.var("ref"))),
                q.paginate(q.documents(q.collection("Things")))
            )
        )

        things = map(
            lambda doc: {
                "id": doc["ref"].id(),
                "name": doc["data"]["name"],
                "color": doc["data"]["color"]
            },
            result["data"]
        )

        return {
            "things": list(things)
        }

これにより、FQLクエリが実行され、Fauna応答がシリアル化可能な型に解析され、HTTP応答の本文でJSON文字列として返されます。

最後に、このexceptブロックをルートに追加します。

main.py

    except faunadb.errors.Unauthorized as exception:
        error = exception.errors[0]
        return {
            "code": error.code,
            "description": error.description
        }, 401

リクエストに有効なシークレットが含まれていない場合、faunadb.errors.Unauthorized例外が発生し、エラー情報を含む401応答が返されます。

これは、/thingsルートの完全なコードです。

main.py

@app.route('/things', methods=['GET'])
def things():

    userSecret = request.headers.get('fauna-user-secret')
    client = FaunaClient(secret=userSecret)

    try:
        result = client.query(
            q.map_(
                q.lambda_("ref", q.get(q.var("ref"))),
                q.paginate(q.documents(q.collection("Things")))
            )
        )

        things = map(
            lambda doc: {
                "id": doc["ref"].id(),
                "name": doc["data"]["name"],
                "color": doc["data"]["color"]
            },
            result["data"]
        )

        return {
            "things": list(things)
        }

    except faunadb.errors.Unauthorized as exception:
        error = exception.errors[0]
        return {
            "code": error.code,
            "description": error.description
        }, 401

ファイルを保存して、サーバーを再度実行します。

FAUNA_SECRET=your_fauna_server_secret python main.py

このエンドポイントをテストするには、最初に有効な資格情報で認証してシークレットを取得します。 新しいターミナルウィンドウを開き、次のcurlコマンドを実行します。

curl -i -d '{"username":"sammy", "password": "secretpassword"}' -H 'Content-Type: application/json' -X POST http://0.0.0.0:8080/login

secretの値は異なりますが、このコマンドは成功した応答を返します。

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 70
Server: Werkzeug/1.0.1 Python/3.9.2
Date: Thu, 04 Mar 2021 01:01:19 GMT

{
  "secret": "fnEEDb...."
}

次に、シークレットを使用して/thingsに対してGETリクエストを実行します。

curl -i -H 'fauna-user-secret: fnEEDb...' -X GET http://0.0.0.0:8080/things

別の成功した応答が得られます:

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 118
Server: Werkzeug/1.0.1 Python/3.9.2
Date: Thu, 04 Mar 2021 01:14:49 GMT

{
  "things": [
    {
      "color": "Yellow",
      "id": "292079274901373446",
      "name": "Banana"
    }
  ]
}

curlコマンドを実行したターミナルウィンドウを閉じます。 サーバーが実行されているウィンドウに戻り、CTRL+Cでサーバーを停止します。

動作するアプリができたので、それをデプロイする準備が整いました。

ステップ4—DigitalOceanへのデプロイ

このチュートリアルの最後のステップでは、App Platformでアプリを作成し、GitHubリポジトリからデプロイします。

プロジェクトをGitリポジトリにプッシュする前に、プロジェクトのフォルダーで次のコマンドを実行してください。

pip freeze > requirements.txt

これにより、アプリケーションのデプロイ後にインストールする必要のある依存関係のリストを含むrequirements.txtファイルが作成されます。

次に、プロジェクトディレクトリをGitリポジトリとして初期化します。

git init

次に、次のコマンドを実行して、リポジトリにファイルを追加します。

git add .

これにより、現在のディレクトリ内のすべてのファイルが追加されます。

ファイルを追加したら、最初のコミットを行います。

git commit -m "Initial version of the site"

ファイルがコミットされます。

ブラウザを開いてGitHubに移動し、プロファイルを使用してログインし、sharkopediaという名前の新しいリポジトリを作成します。 READMEまたはライセンスファイルなしで空のリポジトリを作成します。

リポジトリを作成したら、コマンドラインに戻ってローカルファイルをGitHubにプッシュします。

まず、GitHubをリモートリポジトリとして追加します。

git remote add origin https://github.com/your_username/sharkopedia

次に、デフォルトのブランチの名前をmainに変更して、GitHubが期待するものと一致させます。

git branch -M main

最後に、mainブランチをGitHubのmainブランチにプッシュします。

git push -u origin main

ファイルが転送されます。 これで、アプリをデプロイする準備が整いました。

:App Platformでアプリを作成できるようにするには、最初にDigitalOceanアカウントに支払い方法を追加する必要があります。

アプリケーションは月額5ドルのコンテナで実行されますが、テストに必要なのはわずか数セントです。 完了したら、アプリケーションを削除することを忘れないでください。削除しないと、引き続き課金されます。


DigitalOceanダッシュボードのAppsセクションに移動し、 Launch YourAppをクリックします。

展開するソースを選択します。 Githubリポジトリを読み取るには、DigitalOceanを承認する必要があります。 アクセスを承認したら、Pythonプロジェクトと、デプロイするアプリのバージョンを含むブランチを含むリポジトリを選択します。

この時点で、App PlatformはプロジェクトがPythonを使用していると判断し、いくつかのアプリケーションオプションを構成できるようにします。

次のオプションを設定します

  • タイプWebサービスであることを確認してください。
  • サーバーシークレットを使用してFAUNA_SECRET環境変数を作成します。
  • 実行コマンドpython main.pyに設定します。
  • HTTPポート8080に設定します。

次に、アプリの名前を入力し、デプロイリージョンを選択します。

次に、ベーシックプランとベーシックサイズを選択します。料金は月額5ドルです。

その後、下にスクロールしてアプリの起動をクリックします。

アプリの構成が完了すると、コンテナーが作成され、アプリケーションとともにデプロイされます。 この最初の初期化には数分かかりますが、その後のデプロイははるかに高速になります。

アプリのダッシュボードに、デプロイプロセスが正常に終了したことを示す緑色のチェックマークが表示されます。

これで、提供されたアプリドメインに対してHTTPリクエストを実行できるようになります。 ターミナルで次のコマンドを実行し、your_app_nameを実際のアプリ名に置き換えて、sammyユーザーの新しいシークレットを返します。

curl -i -d '{"user":"sammy", "password": "secretpassword"}' -H 'Content-Type: application/json' -X POST https://your_app_name.ondigitalocean.app/login

次のような応答が返されます。

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 70
Server: Werkzeug/1.0.1 Python/3.9.2
Date: Thu, 04 Mar 2021 01:01:19 GMT

{
  "secret": "fnAADbhO3jACEEQNBIxMIAOOIlDxujk-VJShnnhkZkCUPKIskdjfh"
}

これで、アプリケーションがDigitalOceanで稼働します。

結論

このチュートリアルでは、Faunaをデータレイヤーとして使用してPython REST APIを作成し、それをDigitalOceanAppPlatformにデプロイしました。

動物相について学び続け、FQLをさらに深く掘り下げるには、動物相のドキュメントを確認してください。