はじめに
Hasuraという、DBテーブルから自動的にGraphQL APIを作成してくれるGraphQLサーバーがあります。
「Hasuraって何?」という方は、「多機能なGraphQLサーバー: Hasura GraphQL Engineを知っておきたい人が読む記事」を読んでいただけると幸いです。
さて、先日このHasuraのコアとなる、hasura/Graphql-engine
のマイナーアップデート版であるv2.1.0が公開されました。
v2.1.0のアップデート内容には、hasura metadata deploy
コマンドの登場やEvent Trigger transforms
機能など、かなり多くの機能追加・修正が加えられています。
便利な機能が目白押しですが、中でも目玉はActions transformer機能でしょう。
この機能の登場により、HasuraからリクエストメソッドやURLを自由に組み立てて、様々なREST APIへ接続ができるようになりました。
本記事では、このActions transformer
の概要紹介と、ちょっとしたサンプルを使って簡単な使い方の説明を行います。
公式ドキュメントにも使い方は書いてあるのですが、少し説明が足りない部分がある&機能が複雑でわかりにくい部分があるため、日本語の情報源として役に立てればいいかなと思い、本記事を公開しました。
本記事の要約
-
Hasura v2.1.0のアップデートで、Actions transformer機能が追加された
-
今までは
POST
でしかREST APIに接続できなかったが、この機能によりGET
やPATCH
などのリクエストメソッドでHTTPリクエストができるようになった
環境
おさらい: Hasura Action
Hasuraは、DBスキーマから基本的なCRUDと集計(aggregate)スキーマを自動生成してくれます。ではユーザー独自のロジックを組み込むにはどうするかというと、外部APIを使用して拡張するという方法をとります。
Hasura Action
は、外部REST APIと接続し、そのレスポンス結果をGraphQLのスキーマに埋め込めるという機能です1。
図: https://hasura.io/docs/latest/graphql/core/actions/index.html
このHasura Actionはとても便利な機能なのですが、REST APIとの接続をwebhoookで行うため、以下のような制限がありました。
- リクエストメソッドは
POST
のみ - エンドポイントを動的にできない
- 例:
/api/v2/users/:user_id/followers
の:user_id
の部分を動的に変えることができない
- 例:
このため、接続先APIをHasuraに合わせて改修する必要がある・外部サービスのAPIが使えないなどの制限があり、お世辞にも不自由なくREST APIと接続できるとは言いづらい状態でした。
ですが、この度のv2.1.0アップデートにより、接続先のREST APIにかかる制限がほとんどなくなりました。
v2.1.0で導入されたActions transformer
Actions transformer
は、Hasura Acitonで接続するREST APIへのリクエストをカスタマイズできる機能です。
リリースノートやドキュメントを読むと、「Actionによって生成されるHTTPリクエストを変換する」2とあり、webhookリクエストをうまく変換しているようです。
カスタマイズできる接続先APIの設定は、下記に述べるようにかなり多岐にわたります。
- エンドポイント
- クエリパラメータ
- リクエストメソッド
- リクエストヘッダー
- リクエストボディ
- Content Type
設定が細かくできるようになったため、Hasura Action
の設定画面も以前と見比べるとリッチになりました。
v2.1.0以前 | v2.1.0以後 |
---|---|
次章で、Actions transformer
機能でカスタマイズできる設定を1つづつ確認していきます。
【コラム】
Actions transformer
には関係しませんが、Action設定画面に新しく増えた「Declared Global Types」という部分で、
他のActionで作成したスキーマの型が表示されるようになりました。
今まで、それぞれのActionでどんな型が定義されているかはActionの設定画面に行かないとわからなかったため、一眼でどのような型があるかを確認できるようになり非常に便利になりました。
##設定できること
リクエストURL
Webhook(HTTP/S)Handler
リクエストURLは、「Webhook(HTTP/S)Handler」という設定項目で行います。
動的に変化するURLではない限り、対象APIのエンドポイントに含まれるパスの情報はここで設定します。
従来通り、ACTION_BASE_URL
という環境変数を設定し、{{ACTION_BASE_URL}}
とすることで環境変数を埋め込むことができます。
動的に変化する場合やクエリパラメータを含めたい場合は、後述する「Request Options Transformation」で行います。
リクエストメソッド・クエリパラメータ・(動的な)リクエストURL
「Request Options Transformation」という設定項目で、上記項目を設定できます。
Request Method
ここでは、リクエストメソッドをGET / POST / PUT / PATCH / DELETEから選択できます。
Request URL Template
ここでは、動的なURLを設定できます。
{{$base_url}}
+ 「動的なパス」というフォーマットになっており、{{$base_url}}
には、先述した「Webhook(HTTP/S) Handler」で設定したURLが展開されます。
「動的なパス」部分には、Hasura Actionの変数を展開して設定ができます。ここで使用できるHasura Actionの変数は以下になります。
名前 | 説明 | 型 | 書き方例 | 補足 |
---|---|---|---|---|
$body | Hasura Actionで作成したInputスキーマ | Object | {{$body.input.arg}} |
書き方例は、以下のような引数を持つActionスキーマから取得する例SampleAction(arg: String!): |
$session_variables | クライアントから送られてくるHeaderに入っているsession_variables | Array | {{$session_variables['x-hasura-user-id']}} | 書き方例は、session_variablesの中にあるx-hasura-user-id から取得する例 |
変数展開ができることにより、「Action引数の値をパスの一部にする」というような、自由なパス設計が可能になりました。
Query Params
ここでは、クエリパラメータを設定できます。設定はkey_value形式で行います。
下記の図のように、クエリパラメータのKeyとvalueにも、Actionの変数を使用できます。
Payload Transformation
今までは、以下のようなリクエストボディの形式でしかAPIにリクエストができませんでした。"input"
という階層が挟まっています。
input {
# Actionの引数が入る
args: {
...
}
}
v2.1.0からは、Hasuraから送るリクエストのボディを自由に設定ができます。
Actionの変数を利用でき、Configure Request Body
エディタで記述します。どのように変換されるのかは、下のTransformed Request Body
で確認ができます。
実際に試してみる
ここからは、実際にHasuraから外部REST APIに接続してみます。
このチュートリアルでは、「**HasuraからQiita V2 APIに接続し、指定したユーザーの情報を取得する」**までを行います。
今回のチュートリアルで作るサンプルコードは以下のGitHubリポジトリにまとめています。READMEに沿っていただければ、Hasuraの動作環境が立ち上がります。
スキーマ作成
Actionのスキーマを設定します。まずは、Hasuraコンソール画面で[Actions] -> [create]で新しくActionを作成します。
続いて、Actionのスキーマを定義します。今回は以下のように作成しました。
type Query {
find_qiita_user (user_id: String!): qiita_user
}
find_qiita_user
というアクション(リゾルバ)名で、String
型(必須)のuser_id
を引数をとり、qiita_user
という型の値を返します。
今回作成するqiita_user
型は、Qiita APIのレスポンスの形にします。今回は[GET /api/v2/users/:user_id](https://qiita.com/api
/v2/docs#get-apiv2usersuser_id)を叩くため、ドキュメントを参考にしてスキーマを作成します。
type qiita_user {
id: String!
description: String!
followers_count: Int!
followees_count: Int!
name: String!
}
このスキーマは、以下のフィールドを保持しています。
- ユーザーID
- 自己紹介コメント
- フォロワー数
- フォロー数
接続設定
接続先APIを設定します。
ベースとなるURLの設定項目**「Webhook (HTTP/S) Handler」**には、今回叩くQiita APIの動的パス以外の部分を設定します。
https://qiita.com/api/v2
ヘッダーやタイムアウトの設定項目「headers」・「Action Custom Timeout」は今回設定しません(トークンが必要なAPIや、タイムアウトを制限したい場合には設定します)。また、「Sample Context」・「Payload Transformation」も今回は設定しません。
残るは、リクエストメソッドや動的パスの設定項目「Request Options Transformation」です。
Qiita APIのユーザー取得APIのエンドポイントGET /api/v2/users/:user_id
に合わせ、以下のように設定します。
APIに合わせて、リクエストメソッドはGET
とします。
また、{{$body.input.user_id}}
とすることで、アクションの引数user_id
をurlへ埋め込むようにしています。
小ネタとして、[Payload Transformation]->[Preview]には、実際にアクセスするURLが表示されます。
「Sample Input」のuser_id
フィールドの値を変えてみて、発行されるURLをチェックしましょう。
動作確認
実際はappllo
やrelay
などのクライアントライブラリを用いることになりますが、今回の動作確認はHasura Console上のGraphiQLエディタ上で行います。
Qiita APIを叩いて取得したデータがちゃんとレスポンスに入っていますね!🎉
注意点
現在(2021/12/20)、APIのレスポンスのスキーマはネストできないという問題があります。
2022/02追記
Hasura v2.2.0のリリースにより、入れ子構造になった返り値を返せるようになりました!
詳細は以下を参考にしてください。
おわりに
いかかでしたでしょうか。Actions transformer
の登場により、Hasura Actionで接続するAPIの幅がかなり広がりました。
本記事ではQIita APIを取り上げましたが、Hasura公式にData Hubという公式サンプル集があります。FirebaseやElasticSearchなどのサンプルがありますので、軽く読んでみるのも良いでしょう。
-
本題と逸れるため説明を省きましたが、RESTではなく外部GraphQL APIと接続するHasura Remote Schemasという機能もあります。 ↩
-
参考:https://hasura.io/docs/latest/graphql/core/actions/transforms.html#action-transforms ↩