前提
CockroachDBという分散型のPostgreSQLに色気を出したばっかりにHasuraがCockroachDBへ完全対応していないという嵌り方で再度設定からやり直すことになった
ふと、何やら目立つNeonへの誘導バナーが有ることに気づく・・・なぜ最初に気づかなかった、いや、今しがた発生したに違いない。
Neon
- ほどほどに良い無料枠が有る
- Hasuraに薦められた今となってはこれ一択
- しかも、どちらも同じGoogleアドレスで設定しておけば1クリックするだけで連携まで完結
- 本日の3時間のエラーとの戦いは全て無に還った
- 接続つまりConnectionした時点でNeon用のデータベースまで作成されている始末
- Hasura + Neon だなこりゃ
チュートリアルでハマったかもしれない型
- なぜにidがTextなんだろうと思うでしょ
- チュートリアルだとTextだけどタイポだと思ってInteger指定して、Todosテーブルの
uiser_id
もInteger
にしたんですよ。 - そりゃそうでしょ、そうおもうでしょ。
- そして、
forign key
でお互い指定し合って -
Relation
設定も完了しました - ここまで全て
success
表示だったんですが気になるのはチュートリアルでText
指定されていること・・・ - 実際クエリを投げると、リレーションしているはずなのに呼び出されなかったんです・・・
- ひょっとしたら私の何らかの間違いかもしれませんが、リレーションするidはHasuraだとText指定にする必要があるかもしれないという勝手な知見でした。
- 該当チュートリアル: https://hasura.io/learn/ja/graphql/hasura/data-modeling/1-users-table/
大文字・小文字
- IntegerのidでRelationできなかった理由がわかったかもしれないしわからないかもしれない
- チュートリアルどおりに、
online_users
のRelationship Name設定している時に、user
指定のものをUser
指定にしたらquery
エラーになった。 - このRelationship nameテーブル名かカラム名かと連携しているのか、そもそも小文字である必要があるのか不明だが、
user
でないと通らない - ただ、
online_users
テーブルとusers
テーブルのid
リレーションだから、User
かuser
かの連動は無いんじゃなかと - そして、
User
でqueryエラーになるなら、そもそもRelation設定時にUser
をエラーにするのでは・・・みたいな勘ぐりがあるものの、そもそもチュートリアル通り小文字にしていない自分が悪い
RulesとHooksは無くなりActionsの利用に移行
Actionsをどう使えばよいかはわかってないがMarketplaceがあるのは好き
Actionsを利用する場合の手順
- Flowsを選択し、Loginを選択
- Add Action を選択し、Custom tab を選択肢、Create Actionをクリック
- Hasura JWT Claims とコピペして記載し、 Login / Post Login を選択肢、Node.jsの一番数字が大きいバージョンを選択し、Createする
- 次のような画面が表示されるので
- 次のコードをコピペして、Deploy を押す
exports.onExecutePostLogin = async (event, api) => {
if (event.authorization) {
// do some custom logic to decide allowed roles
const roles = ['user']
api.accessToken.setCustomClaim('https://hasura.io/jwt/claims', {
'x-hasura-default-role': 'user',
// do some custom logic to decide allowed roles
'x-hasura-allowed-roles': roles,
'x-hasura-user-id': event.user.user_id
});
}
}
なんか追加で設定するHasura Sync Users
- 英語のページに沿ってHasura Sync Usersも設定が必要
- 設定は、Hasura JWT Claims同様に進み、Hasura JWT Claimsの部分を、Hasura Sync Usersに変えることと、次のコードを設定画面にコピペする(Hasuraの公式コードとは違う。違う理由はこの↓のコードはHasuraのTodoチュートリアルのDB仕様に基づいたものだから、UserId->idとUserName->nameが違う)
const fetch = require('node-fetch')
/**
* Handler that will be called during the execution of a PostLogin flow.
*
* @param {Event} event - Details about the user and the context in which they are logging in.
* @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
*/
exports.onExecutePostLogin = async (event, api) => {
const id = event.user.user_id;
const name = event.user.name ?? null;
const admin_secret = "YOUR_HASURA_GRAPHQL_ADMIN_SECRET";
const url = "https://your-hasura-url.hasura.app/v1/graphql";
const query = `mutation Auth0SyncUsersAction($id: String!, $name: String) {
insert_users_one(object: {id: $id, name: $name}, on_conflict: {constraint: users_pkey, update_columns: name}) {
id
name
}
}
`;
const variables = { id, name };
const res = await fetch(url,
{
method: 'POST',
body: JSON.stringify({
query: query,
variables: variables
}),
headers: {
'content-type' : 'application/json',
'x-hasura-admin-secret': admin_secret
}
});
console.log("Response", await res.json())
return res
};
- コピペした中の最初の方に有る次の2つのパラメーターは自分のHasuraの設定値に変更する
const admin_secret = "YOUR_HASURA_GRAPHQL_ADMIN_SECRET";
const url = "https://your-hasura-url.hasura.app/v1/graphql";
-
🗃️みたいなとこをクリックしてAdd Dependencyをクリック
-
node-fetchという名前で指定して、バージョンを2にする
-
終わったらDeployする
-
再度Actionsページに戻り、flows > login > custom選択するとさっき設定した2個の□があるので左側にこんな感じでドラッグアンドドロップする
接続テスト
Auth0 Tokenテスト
-
Extension page で
api debugger
で検索 -
アプリ認証画面になるので
許可
を選択 -
なお、ここまで全てのサービスで同じGmailアドレスを利用しておくことが寛容
-
何も考えずに同じGmailでSNS認証を通していたが、ビジネスロジックを考えると同じじゃなかったらなんかエラーでてたかもと思った
-
Applicationという選択肢で使用するアプリを選択
-
注意点として、
Callback URL
は後で利用するのでメモに貼り付けて保存が必要 -
次に
OAuth2 / OIDC
タブをクリックして -
ページ内検索で
Audience
を探す -
自分のHasuraのURLをコピペ
-
今まで見たこと無いSaveボタンをクリック
-
Application画面に移動して、今回利用するアプリ名を選択肢、メモしていたCallback URLをコピペしてSaveボタンをクリック
-
別タブで開いていたAuth0 Authentication API Debuggerページに戻る。いわゆるさっきの今まで見たこと無いSaveボタンが有るOAuth2 / OIDCページ
-
ここでよく覚えてないけどAuth0のApplicationタブにあるCallbackURLは次のようにした。LoginURIは未指定でいける。結局このあと行う認証自体はGoogleアカウントと認証するのできっとLoginURIは不要なんじゃなかろうか。
-
正直どのサービスで許可したのかさえあやふやだったので、サービスを選択する画面が出たらHasuraとかじゃなくて
All Service
みたいなのを選択したら良い。セキュリティ的には危ういが、初回のチュートリアルとしてはOK. -
とりあえず、Auth0のExtensionページから移動した先で色々設定して次のような状態になればOK
-
同様にHasura側でもGoogleドメインで↑許可したやつが反映される
確認テスト
- その後の公式ページ(英語)には何か操作があったがその画面がでなかったので確認テストをしたら通ったのでOKということにしたい
- HasuraのQuery投げれる次のページで
- 次のようなクエリ投げてデータが返って来たら良いらしいが、どう考えてもHasuraで実行しているのでHasuraのデータをっているようにしか見えないから、Auth0と接続できているかちょっとよくわからん。
- なお、今回のAuth0の件だけで記事書きながらだけど3時間はかかった。
{
users {
id
}
}
hasuraスキーマエクスポートhttps://hasura.io/learn/ja/graphql/hasura-advanced/migrations-metadata/3-metadata/
Firebaseなら
- どこかの記事でFirebaseの方がAuth0より操作が大変って書いてたけど、Hasura公式英語ページ見る限りFirebaseの方が簡単そう
- 実際のところFirebaseの方が慣れているのと、Firebaseは先月末プレでPostgreSQL使えるようになった( Cloud SQL for PostgreSQL:ただし使ってみたけど未完成っぽい)
- そういうの含めFirebaseで認証作業をやってみようと思う
Hasura公式Firebase Doc
- https://hasura.io/learn/graphql/hasura-authentication/integrations/firebase/
- 割と適当に設定コピペでして、ローカルのindex.htmlをプレビューして適当に登録したら
- Firebase側にも反映されてた。ここまで10分たらず。(だがしかし、動作できているか怪しい。なぜならHasuraのFirebaseに関する操作説明がAuth0のそれに比べ薄いから。Auth0を使ったほうが無難なのかもしれない。)
- そんな時に使うパイセンの知見:https://zenn.dev/yubachiri/articles/bb4ac475d7e3560c3913#firebase
- ただ、Hasura側に戻った時に次のエラーが見えてた
- 追記:ここは公式英語ページの内容を正規表現で一括変更していた時に半角スペースが混じっていたから目グレップで修正したらSUCCESSになりました
- ここまでは、htmlプレビューしてFirebaseにユーザ生成するまでなのでよく考えたらHasuraまだ絡んでなかった
HasuraとFirebaseをConnect
- ローカルにFirebase環境を用意(VSCode利用:https://zenn.dev/ko_hei/articles/ab1cc5c1804543
# 次のコマンドはnode.jsを最新にするものです。エラーが出たら無視してください。
npm install -g node
# sampleフォルダを作ります。別の名前でも良いです。
mkdir sample
# sampleフォルダに移動します。
cd sample
# firebaseを利用するツールをインストールします
npm install -g firebase-tools
# firebaseにログインします。大抵はGmailの認証情報です
firebase login
# firebaseを利用できるようにするため初期化しています
firebase init
windowsのwsl
- ここにきてwindows側のwslをクリーンに使いたいと思った
- MacBookのM4ほしい
VSCodeから操作してwsl開く
- VSCode開く
- ctrl+@
- https://learn.microsoft.com/ja-jp/windows/wsl/filesystems
Hasuraチュートリアル
todo
slack clone
React側
やっとReact側の実装に進む
Hasura公式参照
-
Hasura公式React(ただし具体的なReact実装には触れていない。git cloneすれば使える状態のものがあるのみ)https://hasura.io/learn/ja/graphql/react/intro-to-graphql/
-
React同様Svelteもgit cloneすれば使えるものがある(英語)https://hasura.io/learn/
ReactとNext.jsの違い
Reactで作る場合の管理画面テンプレート
とりあえずwindows+docker+reactではじめる
企業支給PC利用の初学者の方はwindows利用の方も多いのでここ頑張って。
Dockerはずっと使います。
何度もやっていると慣れます。
習うより慣れろ。
ホットリリードできない場合
"scripts": {
"start": "WATCHPACK_POLLING=true react-scripts start",
とりあえずHasuraからデータ取得する
- 厳密に言うと今やっている流れだと取得できない。
ただし一旦この部分を飛ばした先に記載した内容に沿うとできる
- 理由としてAuth0認証をしているので、Auth0認証が通らないと取得できないから。
- Auth0認証するページを実装する必要があるが、Hasura内に見当たらない
- とりあえず認証を解除する方法を探るのも一つの手だが、↓の先生のページで何が取得できるかは、ディベロッパーツール上で確認できるとのこと。
- この処理の先生記事:https://zenn.dev/yubachiri/articles/bb4ac475d7e3560c3913#firebase
HasuraからエンドポイントURLをコピペ
赤く塗りつぶしている行のURLをコピーしておく。
とりあえず後で使うのでどこかメモ帳にはるか、↓画面を開きっぱなしにしておけば良い。
このURLを エンドポイントURL
と名付ける
App.tsxに次のコードをコピペする
- App.tsxに次のコードをコピペする
- そのうえで、
HasuraからコピペしたエンドポイントURLを貼る
の部分にエンドポイントURL
をコピペして保存
import React from './App';
function App() {
const queryStr = "query MyQuery { users { id email } }"
const query = { query: queryStr }
const fetchUsers = () => {
fetch('HasuraからコピペしたエンドポイントURLを貼る', {
method: 'POST',
body: JSON.stringify(query)
}).then(response => {
response.json().then(result => {
console.log(result.data)
})
})
}
return (
<div>
<button onClick={fetchUsers}>
クリックするとデータ取得
</button>
</div>
);
}
export default App;
日本語で説明
- 何故ここに来て日本語で説明するかというと初学者用
- Hasura側の設定を説明しなかったのは今は理解しなくて良いから
- 日本語化教材告知
https://www.techpit.jp/courses/257
1. `import React from './App';`
`./App`から`React`をインポートします。
2. `function App() {`
`App`という名前の関数を定義します。この関数はReactのコンポーネントとして機能します。
3. `const queryStr = "query MyQuery { users { id email } }"`
`queryStr`という定数を定義し、GraphQLのクエリ文字列を代入します。このクエリは、ユーザーの`id`と`email`を取得します。
4. `const query = { query: queryStr }`
`query`という定数を定義し、`queryStr`をプロパティとして持つオブジェクトを代入します。
5. `const fetchUsers = () => {`
`fetchUsers`という名前の関数を定義します。この関数は、ユーザー情報を取得するための非同期操作を行います。
6. `fetch('HasuraからコピペしたエンドポイントURLを貼る', {`
`fetch`関数を使用して、指定したエンドポイントURLからデータを取得します。
7. `method: 'POST',`
HTTPメソッドとして`POST`を指定します。
8. `body: JSON.stringify(query)`
リクエストボディとして、`query`オブジェクトをJSON形式の文字列に変換したものを指定します。
9. `}).then(response => {`
`fetch`関数が返すPromiseが解決したとき(つまり、データの取得が完了したとき)に実行する処理を定義します。
10. `response.json().then(result => {`
レスポンスボディをJSON形式のデータに変換し、その結果を処理します。
11. `console.log(result.data)`
取得したデータをコンソールに出力します。
12. `return (`
`App`関数(コンポーネント)がレンダリングする要素を返します。
13. `<div>`
`div`要素を開始します。
14. `<button onClick={fetchUsers}>`
`fetchUsers`関数をクリックイベントハンドラとして持つ`button`要素を作成します。
15. `クリックするとデータ取得`
ボタンのラベルとして表示されるテキストです。
16. `export default App;`
`App`関数(コンポーネント)をデフォルトエクスポートします。これにより、他のファイルからこのコンポーネントをインポートできます。
改とりあえずデータを取得する
-
こちらの大先生の記事を参考にするとログインしない状態のデータ取得ができる
-
ログインしない状態というのは、LPなどで利用すると思うとわかりやすい
-
LPというのはランディングページ。つまり未ログイン・未登録のユーザーに対して見せるページ
-
pagesテーブルを作成しておくと良い:https://kou029w.github.io/hasura-rest-hands-on/create-table.html
-
エンドポイントの作成方法:https://kou029w.github.io/hasura-rest-hands-on/create-rest-endpoint.html
-
ちなみにエンドポイントだが次の画像の
Create REST Endpoint
っていう部分をクリックすると自動生成できる機能ができたらしい。使ったら超便利だった。 -
ここで権限設定する(これで発行されたエンドポイントに行けばデータが取得できた):https://kou029w.github.io/hasura-rest-hands-on/permissions.html
アプリの作成(React予定)
- データの取得まで何日かかんねん・・・これはHasuraとその周辺技術のバージョンの違いで情報が錯綜していることが問題
ご相談はこちら