アプリケーションの機能を外部から利用できる仕組みであるAPI(Application Programming Interface)。最近ではChatGPTをはじめとした生成系AIサービスの利用拡大などに伴い、自作プログラムにAPIを組み込んで利用したり、システムやサービス間をAPIで疎結合化したり、APIでのデータ連携が主流になってきたりと、APIが身近な存在になっているのではないかと思います。
ところで、APIを利用することはよくありますが、作るとなるとどうでしょうか?裏側の仕組みがよくわからないだけに、なんだか難しそうなイメージがありますよね。実は、クラウドサービス(今回はGCP)を利用することで、そんなAPIを手軽に実現することができます。
具体的なAPIの作り方について、以降で詳しく見ていきましょう!
今回作るAPI
今回作成するのは、以下のようなJSON形式でユーザのID、名前、メールアドレスを受け取り、BigQuery上のテーブルに対して操作を行うシンプルなAPIです。
{
"id": 1,
"name": "レック太郎",
"email": "req-taro@example.com"
}
機能としては、
- ユーザ登録
- ユーザ削除
の2つを考えます。構成図は以下のようになります。
リクエストをAPIゲートウェイが受け付け、登録・削除に応じて2つのファンクションのどちらかが起動され、BigQueryに対して操作を行うという流れです。
テーブル準備
まず、ユーザデータを管理するためのテーブルをBigQuery上に作成します。今回は簡単に以下のようなusersテーブルを用意しました。
バックエンド設定
Cloud Functions
今回作るAPIのバックエンドとなるCloud Functionsのファンクションを作成していきます。
①サービスアカウント設定
最初に、Cloud Functions用のサービスアカウントを作成します。今回はCloud FunctionsからBigQueryにアクセスしたいので、BigQuery管理者の権限を付けておきます。
②ファンクション作成(ユーザ登録)
ファンクションの作成画面に移り、ユーザ登録用ファンクションtest-api-addの設定を行います。
今回はHTTPリクエストを投げる形なので、トリガーはHTTPSです。ランタイムサービスアカウントには先ほど作成したサービスアカウントを指定します。ランタイム環境変数はファンクション起動後にプログラム内で参照できる環境変数で、今回はusersテーブルのテーブルIDを指定しています。
次にプログラムの設定です。
プログラムは「ランタイム」タブからPython, Go, Java, Node.js等を選ぶことができます。今回は以下のようなPythonプログラムを用意しました。main.pyがエントリポイントを含むメインプログラムです。
main.py
import os
import json
import functions_framework
from pydantic import BaseModel
from google.cloud import bigquery
class User(BaseModel):
id: int
name: str
email: str
def entrypoint(request):
# リクエストデータ取得
request_json = request.get_json()
# ユーザデータ取得
user = User(
id=request_json.get("id"),
name=request_json.get("name"),
email=request_json.get("email")
)
# ユーザ登録
add_user(user)
# レスポンス(正常終了)
response_json = {
"code": 200,
"message": "ユーザ登録に成功しました。"
}
response_body = json.dumps(response_json, ensure_ascii=False).encode("utf-8")
return response_body, 200, {"Content-type": "application/json"}
def add_user(user: User):
# BigQueryクライアント設定
bq_client = bigquery.Client()
TABLE_ID = os.environ.get("TABLE_ID")
# クエリ作成
query = f"""
INSERT INTO `{TABLE_ID}` (id, name, email)
VALUES (@id, @name, @email);
"""
job_config = bigquery.QueryJobConfig(
query_parameters=[
bigquery.ScalarQueryParameter("id", "INTEGER", user.id),
bigquery.ScalarQueryParameter("name", "STRING", user.name),
bigquery.ScalarQueryParameter("email", "STRING", user.email),
]
)
try:
result = bq_client.query(query, job_config=job_config, timeout=60).result()
except Exception as e:
raise Exception("クエリ実行に失敗しました。") from e
requirements.txt
functions-framework
requests
pydantic
google-cloud-bigquery
エントリポイントはリクエストデータが引数として渡される関数であり、リクエストを処理する本体部分となります。赤線部分の名前が一致していないとエラーになるのでご注意ください。
デプロイに成功すると、以下のような画面でファンクションの詳細を確認することができます。一部設定を除いて後から編集も可能で、メモリやCPUを増強したい場合は簡単に変更可能です。
③ファンクション作成(ユーザ削除)
ユーザ削除用ファンクションtest-api-delの設定を行います。
②と基本的に同じですが、main.pyのプログラムのみ異なります。こちらのmain.pyは以下の通りです。
main.py
import os
import json
from typing import Optional
import functions_framework
from pydantic import BaseModel
from google.cloud import bigquery
class User(BaseModel):
id: int
name: Optional[str]
email: Optional[str]
def entrypoint(request):
# リクエストデータ取得
request_json = request.get_json()
# ユーザデータ取得
user = User(
id=request_json.get("id"),
name=request_json.get("name"),
email=request_json.get("email")
)
# ユーザ削除
del_user(user)
# レスポンス(正常終了)
response_json = {
"code": 200,
"message": "ユーザ削除に成功しました。"
}
response_body = json.dumps(response_json, ensure_ascii=False).encode("utf-8")
return response_body, 200, {"Content-type": "application/json"}
def del_user(user: User):
# BigQueryクライアント設定
bq_client = bigquery.Client()
TABLE_ID = os.environ.get("TABLE_ID")
# クエリ作成
query = f"""
DELETE FROM {TABLE_ID}
WHERE id = @id
"""
job_config = bigquery.QueryJobConfig(
query_parameters=[
bigquery.ScalarQueryParameter("id", "INTEGER", user.id),
]
)
# クエリ実行
try:
result = bq_client.query(query, job_config=job_config, timeout=60).result()
except Exception as e:
raise Exception("クエリ実行に失敗しました。") from e
こちらも同じようにデプロイします。
以上でCloud Functionsの設定は完了です。
フロントエンド設定
API Gateway
①サービスアカウント設定
Cloud Functionsと同様、サービスアカウントの作成と設定を行います。Cloud Functionsの呼び出しで「未認証の呼び出しを許可」を選択していた場合、権限付与の設定は必要ありません。
②API仕様作成
APIゲートウェイを作成するにあたり、OpenAPI仕様を作成する必要があります。OpenAPIというのは、APIの仕様を定義するためのフォーマットであり、いわばAPIの設計書です。APIのアクセス先のパスとそれに対応するバックエンド、リクエストとレスポンスの内容などをYAMLまたはJSON形式で記述します。
今回設定するOpenAPI仕様は以下の通りです。
test-api-config.yaml
swagger: '2.0'
info:
title: test-api
description: テストAPI
version: 1.0.0
schemes:
- https
tags:
- name: user
description: ユーザ操作
produces:
- application/json
paths:
/api/v1/add:
post:
tags:
- user
summary: ユーザ情報を登録する
description: ユーザ情報を登録する
operationId: addUser
x-google-backend:
address: https://asia-northeast1-xxxxxxxxxxxxx.cloudfunctions.net/test-api-add
path_translation: APPEND_PATH_TO_ADDRESS
deadline: 60
parameters:
- in: body
name: body
description: ユーザ情報登録用データ
required: true
schema:
$ref: '#/definitions/User'
responses:
'200':
description: '成功'
schema:
$ref: '#/definitions/Response'
/api/v1/del:
post:
tags:
- user
summary: ユーザ情報を削除する
description: ユーザ情報を削除する
operationId: delUser
x-google-backend:
address: https://asia-northeast1-xxxxxxxxxxxxx.cloudfunctions.net/test-api-del
path_translation: APPEND_PATH_TO_ADDRESS
deadline: 60
parameters:
- in: body
name: body
description: ユーザ情報削除用データ
required: true
schema:
$ref: '#/definitions/User'
responses:
'200':
description: '成功'
schema:
$ref: '#/definitions/Response'
definitions:
User:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: 'レック太郎'
email:
type: string
example: 'req-taro@example.com'
Response:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: '成功'
x-google-backend
で、先ほど作成したファンクションのURLを指定しています。paths
に指定した各パスが対象の機能をもつバックエンドに対応付けられるため、APIのURLは以下のようになります。
- ユーザ登録:<APIゲートウェイのURL>/api/v1/add
- ユーザ削除:<APIゲートウェイのURL>/api/v1/del
なお、OpenAPIはSwagger Editor等のツールを使って記述します。今回のOpenAPI仕様をSwagger Editorで確認した場合、右側のようにドキュメント化された状態のものを見ることができます。
③ゲートウェイ作成
API Gatewayのコンソール画面からゲートウェイを作成します。API名や構成を設定し、「ゲートウェイを作成」を押すとゲートウェイの作成が始まります。作成には少し時間がかかります。(5~10分程度)
※本記事執筆時点で、OpenAPIはバージョン2.0のみサポートされているようです。バージョン3.0以上のOpenAPI仕様はエラーになるためご注意ください。
問題なく作成完了すれば、ゲートウェイのURLが払い出されます。画像の赤枠部分が今回作成したAPI(ゲートウェイ)本体のURLです。
ちなみに、ゲートウェイのURLはデフォルトの場合https://xxxxxx.an.gateway.dev
のようになりますが、ロードバランサを利用してカスタムドメインを設定することも可能です。詳しくはAPI ゲートウェイの HTTP(S) 負荷分散スタートガイドをご参照ください。
以上で今回のAPIは完成です!
動作確認
完成したAPIがちゃんと動くかどうか見てみましょう。今回作成したAPIは未認証の呼び出しを許可しているので、対象プロジェクト以外の環境からでもアクセス可能です。試しにローカル端末から、Talend API Testerというツールを使ってリクエストを送ってみます。
ユーザ登録リクエストを送ると、期待通り「ユーザ登録に成功しました。」というレスポンスが返ってきました。実際にusersテーブルを確認してみると...
無事に「レック 太郎」さんのデータが入っていました。同様にユーザ削除を試してみると、「レック 太郎」さんのデータが削除されることが確認できます。
あとがき
今回作成したAPIは簡易的なものなので、認証まわりやリクエストの処理、エラーハンドリングなど突っ込みどころの多いものになっていますが、APIの作り方についてざっくりとイメージを掴んでいただけたのではないでしょうか。
今回ご紹介したように、API GatewayやCloud Functionsといったサービスを使うことで、APIを手軽に作ることができます。サーバレスであるためリソースの管理がいらないことに加えて、利用状況に応じて後から柔軟にリソースの増強ができたり、自前であれこれ用意するのに比べ低コストで運用できる点が魅力的です。