とりあえずHasuraチュートリアルのデータベースはNeonがよい

# 前提

https://qiita.com/nakamoto/items/69a382aecfd8b01aebfc

CockroachDBという分散型のPostgreSQLに色気を出したばっかりにHasuraがCockroachDBへ完全対応していないという嵌り方で再度設定からやり直すことになった

ふと、何やら目立つNeonへの誘導バナーが有ることに気づく・・・なぜ最初に気づかなかった、いや、今しがた発生したに違いない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/7064641e-1897-b525-c502-c0e1d69fe420.png)

## Neon

- ほどほどに良い無料枠が有る
- Hasuraに薦められた今となってはこれ一択
- しかも、どちらも同じGoogleアドレスで設定しておけば1クリックするだけで連携まで完結
- 本日の3時間のエラーとの戦いは全て無に還った
- 接続つまりConnectionした時点でNeon用のデータベースまで作成されている始末
- Hasura + Neon だなこりゃ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/a2a8b82c-5df5-7dd9-7bac-71d696cb2207.png)

## チュートリアルでハマったかもしれない型

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/5c7152fa-eb56-77f0-789d-abf01d12499a.png)

- なぜに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/
-  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/58194920-8095-bdad-1be1-e021e45f4f34.png)

## 大文字・小文字

- IntegerのidでRelationできなかった理由がわかったかもしれないしわからないかもしれない
- チュートリアルどおりに、 `online_users`のRelationship Name設定している時に、 `user` 指定のものを `User` 指定にしたら `query` エラーになった。
- このRelationship nameテーブル名かカラム名かと連携しているのか、そもそも小文字である必要があるのか不明だが、 `user` でないと通らない
- ただ、 `online_users` テーブルと `users` テーブルの `id` リレーションだから、 `User` か `user` かの連動は無いんじゃなかと
- そして、 `User` でqueryエラーになるなら、そもそもRelation設定時に `User` をエラーにするのでは・・・みたいな勘ぐりがあるものの、そもそもチュートリアル通り小文字にしていない自分が悪い



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/c91a20d2-42ab-b1b7-5e38-dbfe510ef902.png)

## RulesとHooksは無くなりActionsの利用に移行

Actionsをどう使えばよいかはわかってないがMarketplaceがあるのは好き

https://auth0.com/blog/jp-preparing-for-rules-and-hooks-end-of-life/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/0946d6ec-2cc1-98e7-3366-214233b2f4a2.png)

## Actionsを利用する場合の手順

https://hasura.io/learn/graphql/hasura-authentication/integrations/auth0/

1. Flowsを選択し、Loginを選択
1. ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/e26c108e-e9b8-5822-9ece-f8733bf3c5e4.png)
1. Add Action を選択し、Custom tab を選択肢、Create Actionをクリック
1. ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/809b6487-519c-9fc9-ee86-bac1dbd413f7.png)
1.  Hasura JWT Claims とコピペして記載し、 Login / Post Login を選択肢、Node.jsの一番数字が大きいバージョンを選択し、Createする
1.  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/5bfe46e1-0d66-032c-c945-aba95bdc040e.png)
1.  次のような画面が表示されるので![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/ebfbabf4-6634-758a-ebee-0e0a8a639c9b.png)
1.  次のコードをコピペして、Deploy を押す
1.  
```javascript:Hasura JWT Claims
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
    });
  }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/05047819-a214-bc39-a3e6-8ce2b41bb3ee.png)

### なんか追加で設定するHasura Sync Users

- 英語のページに沿ってHasura Sync Usersも設定が必要
- 設定は、Hasura JWT Claims同様に進み、Hasura JWT Claimsの部分を、Hasura Sync Usersに変えることと、次のコードを設定画面にコピペする(Hasuraの公式コードとは違う。違う理由はこの↓のコードはHasuraのTodoチュートリアルのDB仕様に基づいたものだから、UserId->idとUserName->nameが違う)
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/3ff6906c-e54f-9a57-17d7-9633d7a5b78f.png)


```javascript:Hasura Sync Users(Auth0)
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の設定値に変更する
```javascript:Hasura Sync Users(Auth0)
const admin_secret = "YOUR_HASURA_GRAPHQL_ADMIN_SECRET";
  const url = "https://your-hasura-url.hasura.app/v1/graphql";
```

- 🗃️みたいなとこをクリックしてAdd Dependencyをクリック
- node-fetchという名前で指定して、バージョンを2にする
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/696be935-7086-525a-3cae-9d6395144ffb.png)

- 終わったらDeployする
- 再度Actionsページに戻り、flows > login > custom選択するとさっき設定した2個の□があるので左側にこんな感じでドラッグアンドドロップする
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/3d7af63b-f799-ff2e-71ea-c9305568a4bf.png)



### 接続テスト
- Hasura Sync Usersに移動
- 左側▲を押すと、Testが現れるのでしたにスクロールして `Run` するとテストが通る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/2c40bfe7-a554-2f63-bfc1-17f08ed8a301.png)
- テストに通ったらDB側にもデータが追加されてる![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/372ebf83-00a2-b0e0-574d-1bfb038da9b8.png)


### Auth0 Tokenテスト
- Extension page で `api debugger` で検索
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/9051e5ba-7e9b-f849-578a-09117e83c478.png)
- アプリ認証画面になるので `許可` を選択
- なお、ここまで全てのサービスで同じGmailアドレスを利用しておくことが寛容
- 何も考えずに同じGmailでSNS認証を通していたが、ビジネスロジックを考えると同じじゃなかったらなんかエラーでてたかもと思った
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/3ac8d0ee-ca6a-7d7f-d4a3-fff89e905a86.png)
- Applicationという選択肢で使用するアプリを選択
- 注意点として、 `Callback URL` は後で利用するのでメモに貼り付けて保存が必要
- 次に `OAuth2 / OIDC` タブをクリックして
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/4c020f77-1186-f0d4-5be5-e395e7d072a7.png)
- ページ内検索で `Audience` を探す
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/25ee873c-4f33-d47d-e688-883230fcbb18.png)
- 自分のHasuraのURLをコピペ
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/67e40c59-6f8f-9dd6-840c-0d887689d3f8.png)
- 今まで見たこと無いSaveボタンをクリック
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/23887302-af03-8c35-e8bd-20cb5b6f437b.png)

- Application画面に移動して、今回利用するアプリ名を選択肢、メモしていたCallback URLをコピペしてSaveボタンをクリック
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/b1dfb33e-051e-54c3-ed9f-1b0dde0d110e.png)
- 別タブで開いていたAuth0 Authentication API Debuggerページに戻る。いわゆるさっきの今まで見たこと無いSaveボタンが有るOAuth2 / OIDCページ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/c7e7d201-f3e5-d34a-0861-04d32036c188.png)
- ここでよく覚えてないけどAuth0のApplicationタブにあるCallbackURLは次のようにした。LoginURIは未指定でいける。結局このあと行う認証自体はGoogleアカウントと認証するのできっとLoginURIは不要なんじゃなかろうか。
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/31973156-4f24-7948-a1ec-0931ba2b01a4.png)

- 正直どのサービスで許可したのかさえあやふやだったので、サービスを選択する画面が出たらHasuraとかじゃなくて `All Service` みたいなのを選択したら良い。セキュリティ的には危ういが、初回のチュートリアルとしてはOK.
- とりあえず、Auth0のExtensionページから移動した先で色々設定して次のような状態になればOK
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/df3eb37e-63f2-3f14-cb5a-b90601067cca.png)
- 同様にHasura側でもGoogleドメインで↑許可したやつが反映される
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/208b26df-073d-950f-aedd-4ed81f828db8.png)


### 確認テスト
- その後の公式ページ（英語）には何か操作があったがその画面がでなかったので確認テストをしたら通ったのでOKということにしたい
- HasuraのQuery投げれる次のページで
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/d3b18b73-a9f6-17b3-ef73-1517dbed4457.png)
- 次のようなクエリ投げてデータが返って来たら良いらしいが、どう考えてもHasuraで実行しているのでHasuraのデータをっているようにしか見えないから、Auth0と接続できているかちょっとよくわからん。
- なお、今回のAuth0の件だけで記事書きながらだけど3時間はかかった。
```sql:hasura
{
  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をプレビューして適当に登録したら
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/6b000644-ae7b-9c10-6d62-e42370a95e2e.png)
- Firebase側にも反映されてた。ここまで10分たらず。（だがしかし、動作できているか怪しい。なぜならHasuraのFirebaseに関する操作説明がAuth0のそれに比べ薄いから。Auth0を使ったほうが無難なのかもしれない。）
- そんな時に使うパイセンの知見：https://zenn.dev/yubachiri/articles/bb4ac475d7e3560c3913#firebase
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/36cabfd7-680c-af0a-07f4-87049f2c96c2.png)
- ただ、Hasura側に戻った時に次のエラーが見えてた
- 追記：ここは公式英語ページの内容を正規表現で一括変更していた時に半角スペースが混じっていたから目グレップで修正したらSUCCESSになりました
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/9c841720-043a-1700-5857-27636ac2e032.png)
- ここまでは、htmlプレビューしてFirebaseにユーザ生成するまでなのでよく考えたらHasuraまだ絡んでなかった
- 
### HasuraとFirebaseをConnect
- ローカルにFirebase環境を用意(VSCode利用:https://zenn.dev/ko_hei/articles/ab1cc5c1804543
```shell: firebase-tools-login-init
# 次のコマンドは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

https://zenn.dev/algorithms/articles/783c4a3123c7dc


### slack clone

https://hasura.io/hub/slack-clone-data-model-postgres/


## 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の違い

https://qiita.com/hiroki-yama-1118/items/b3388c5dcb155e2e367d

### Reactで作る場合の管理画面テンプレート

https://qiita.com/midiambear/items/76cf71142dd5abbec181


### とりあえずwindows+docker+reactではじめる

企業支給PC利用の初学者の方はwindows利用の方も多いのでここ頑張って。

Dockerはずっと使います。

何度もやっていると慣れます。

習うより慣れろ。

https://qiita.com/_KAYATO/items/110952e722ef73ded728

### ホットリリードできない場合

``` json:package.json
"scripts": {
  "start": "WATCHPACK_POLLING=true react-scripts start",
```

https://zenn.dev/nifumafu/articles/ef84d9f1c38de3



## とりあえずHasuraからデータ取得する

- 厳密に言うと今やっている流れだと取得できない。
- `ただし一旦この部分を飛ばした先に記載した内容に沿うとできる` 
- 理由としてAuth0認証をしているので、Auth0認証が通らないと取得できないから。
- Auth0認証するページを実装する必要があるが、Hasura内に見当たらない
- とりあえず認証を解除する方法を探るのも一つの手だが、↓の先生のページで何が取得できるかは、ディベロッパーツール上で確認できるとのこと。
- この処理の先生記事：https://zenn.dev/yubachiri/articles/bb4ac475d7e3560c3913#firebase

### HasuraからエンドポイントURLをコピペ

赤く塗りつぶしている行のURLをコピーしておく。

とりあえず後で使うのでどこかメモ帳にはるか、↓画面を開きっぱなしにしておけば良い。

このURLを `エンドポイントURL` と名付ける

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/77f45432-43b2-5019-6187-a7559ab2accd.png)


### App.tsxに次のコードをコピペする

1. App.tsxに次のコードをコピペする
2. そのうえで、 `HasuraからコピペしたエンドポイントURLを貼る` の部分に `エンドポイントURL` をコピペして保存


```typescript:App.tsx
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

```typescript:App.tsx
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` っていう部分をクリックすると自動生成できる機能ができたらしい。使ったら超便利だった。
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/1feac587-ccc3-40fa-6030-6d3f08308ba1.png)
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/ae370883-cf24-d097-5d8f-fca9000220ee.png)


- ここで権限設定する（これで発行されたエンドポイントに行けばデータが取得できた）：https://kou029w.github.io/hasura-rest-hands-on/permissions.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/83590cc8-bd00-b0c4-2af3-fd26739802f5.png)


## アプリの作成（React予定）
- データの取得まで何日かかんねん・・・これはHasuraとその周辺技術のバージョンの違いで情報が錯綜していることが問題



## ご相談はこちら

https://park.jp/service_menu/2491