動物相を使用してPythonRESTAPIを構築し、DigitalOceanAppPlatformにデプロイする方法
序章
多くの開発者には、アプリケーションのインフラストラクチャをセットアップおよび管理するための時間や経験がありません。 期限に遅れずにコストを削減するには、開発者は、コードの記述と顧客への新機能の提供に集中するために、アプリをできるだけ迅速かつ効率的にクラウドにデプロイできるソリューションを見つける必要があります。 DigitalOceanのAppPlatformとFaunaが一緒になってその機能を提供します。
DigitalOcean App Platformは、アプリを実行するインフラストラクチャを抽象化するPlatform-as-a-Service(PaaS)です。 また、コードをGitブランチにプッシュすることでアプリケーションをデプロイすることもできます。
動物相は、あらゆるサイズのアプリケーション向けの強力なデータレイヤーです。 このチュートリアルでわかるように、Faunaを使用すると、データベースの操作を気にすることなく、データベースをすばやく起動して実行できます。
これら2つのソリューションを組み合わせることで、インフラストラクチャを管理するのではなく、アプリケーションに集中できます。
このチュートリアルでは、 Flaskフレームワークを使用して最小限のRESTAPIを記述し、FaunaをPythonと統合します。 次に、GitリポジトリからDigitalOceanのAppPlatformにAPIをデプロイします。APIは次のもので構成されます。
Users
コレクションにユーザーを作成するためのパブリック/signup
POSTエンドポイント。Users
コレクション内のドキュメントで認証するためのパブリック/login
POSTエンドポイント。Things
コレクションから動物相ドキュメントのリストをフェッチするためのプライベート/things
GETエンドポイント。
完成したPythonプロジェクトは、このGithubリポジトリで入手できます。
前提条件
このチュートリアルを開始する前に、次のものが必要です。
- 動物相アカウント。
- 支払い方法が設定されたDigitalOceanアカウント。
- プロジェクトをAppPlatformにデプロイできるようにするためのGithubアカウント。
- Python3と
pip
が開発マシンにインストールされています。 Python 3のローカルプログラミング環境をインストールしてセットアップする方法に従って、これをセットアップします。 - Gitがローカルマシンにインストールされています。 チュートリアルオープンソースに貢献する方法:Gitの使用開始に従って、コンピューターにGitをインストールしてセットアップすることができます。
- テキストエディタ。 Visual StudioCodeまたはお好みのテキストエディターを使用できます。
ステップ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" } }
結果には、次のフィールドが表示されます。
- タイプ
Ref
のref
は、ID292079274901373446
のThings
コレクションにあるこのドキュメントへの参照です。 ドキュメントの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との通信に使用するサーバーキーを作成します。 次に、アクセス許可を構成します。
キーを作成するには、左側のメインメニューを使用して、動物相ダッシュボードのセキュリティセクションに移動します。 そこに着いたら:
- 新しいキーボタンを押します。
- サーバーの役割を選択します。
- 保存を押します。
保存後、ダッシュボードにキーの秘密が表示されます。 シークレットを安全な場所に保存し、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-secret
HTTPヘッダーからのユーザーシークレットを使用します。 サーバーシークレットの代わりにユーザーシークレットを使用することにより、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をさらに深く掘り下げるには、動物相のドキュメントを確認してください。