AWS AppSyncのスキーマ情報からAmplify以外の方法でTypeScriptの型を生成する

メモです。

最近、GraphQLを使い始めた。AWSのAppSyncを使っている。

GraphQLではスキーマの情報をschema.graphqlとかschema.jsonとかってファイルで定義する。AppSyncをマネージメントコンソール上でポチポチと作った場合もこのファイルがダウンロードできる。

さて、実際にGraphQLを使ったアプリはTypeScriptで書いている。TypeScriptと言えば型だ。というわけでGraphQLのスキーマ情報からTypeScriptの型を生成したいんだけどAWSのガイドとかだとこのあたりAmplifyを使ったガイドしかない。そしてAmplifyはいろんな理由でできれば使いたくない。

実際にGraphQLへのクエリとかもAmplifyは使っていない。なのに型情報の生成のためだけにAmplify使うの嫌だなーと思ってTwitterでブツブツ言ってたらこんなのがあるって教えてもらった。

www.graphql-code-generator.com

これは良さげ。ということで早速入れてみる。

インストール。

yarn add -D @graphql-codegen/cli
yarn add -D @graphql-codegen/typescript-operations @graphql-codegen/typescript

初期化

yarn graphql-codegen init

いろいろ聞かれるが正直なところ何を選択すればいいかよくわからない。

実行するとcodegen.ymlが生成される。最後のpackage.jsonにどういう感じで追加するかについてはgenerateを指定した。

自分の場合、こんな感じでできあがった。

overwrite: true
schema: 'schema.graphql'
generates:
  src/generated/graphql.ts:
    plugins:
      - 'typescript'
      - 'typescript-operations'

生成する

yarn generate

実行したらUnknown type: "AWSJSON".と出てしまった。確かにAppSync使ってることもありいくつかのフィールドをAWSJSONという型を指定している。さらに言えばAWSTimestampも使っている。

というわけでこれらをどう扱うか教えてあげる必要がある。

AppSyncの型に対応する

以下のファイルをappsync.graphqlとでも名前をつけて作成する。

scalar AWSDate
scalar AWSTime
scalar AWSDateTime
scalar AWSTimestamp
scalar AWSEmail
scalar AWSJSON
scalar AWSURL
scalar AWSPhone
scalar AWSIPAddress

そしてcodegen.ymlを編集してschemaファイルとして作成したファイルも見るようにする。

schema:
  - schema.graphql
  - appsync.graphql

再度 yarn generateを実行する。

めでたく指定したファイル(ここでは src/generated/graphql.ts)に型の情報が出力された。

あとはこれをインポートして利用するだけだ。

Ubuntuのコンテナにwatchmanを頑張って入れる

メモです。

元はServerless Frameworkでserverless-appsync-simulatorとserverless-offlineを使おうと思ったら Error: spawn watchman ENOENTっていうエラーが出て起動できず、ぐぐったらwatchmanをインストールすればいいってことでその対応。

MacならHomebrewであっさりインストールできるのだが、あいにく自分はVS Code + Remote Containersである。コンテナとしては公式のNode.jsのイメージを使っていてこれはUbuntuベース。

というわけでLinuxにwatchmanをインストールしようとしたらそこそこハマったのでそのメモ。

まず、Linuxにwatchmanを入れるにはソースからコンパイルして入れる必要がある。一応バイナリも配布されているらしいが。

ソースからコンパイルしてインストールするにあたり事前に以下のパッケージをインストールしておく必要がある。

apt install -y make libtool libssl-dev autoconf automake pkg-config g++ libpython-dev

最後のlibpython-devってのは今回自分が使っているようにPythonがインストールされていないイメージではpyconfig.hが存在せずビルドに失敗するから。

これらを入れたら以下のようにGitからソース持ってきて入れる。

git clone https://github.com/facebook/watchman.git -b v2022.07.18.00 --depth 1
cd watchman
./autogen.sh

なお、公式のインストール手順だとGitからクローンするバージョンがv2021.09.20.00と古い。そうするとpcreのダウンロードに失敗するので新しいものを使う。そして公式手順では./autogen.shの次に./configureしてmake installするというおなじみの手順があるのだが、新しいものを使うと./configureが生成されずmake installもできない。というわけで以下のようにやっていく。

まず、そのままだと./autogen.shにも失敗する。どうやら新しいやつだとRustも必要だったのでインストールする。

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

Rustをインストールした後に./autogen.shを実行する。 前述の通り、masterの最新でビルドした場合はconfigureが生成されず、make installもできない。そのためこのあたりを手動でセットアップする必要がある。まず、ビルドされた成果物はbuild/binフォルダにあるのでこのディレクトリに対してPATHを通すか、すでにPATHが通っているどこかのディレクトリに中身をコピーする。自分の場合はひとまずすでにPATHが通っている/usr/local/binにコピーした。

そしてwatchmanを実行してみるとこんなエラーが出る。

./built/bin/watchman: error while loading shared libraries: /usr/local/lib/libgflags.so.2.2: cannot open shared object file: No such file or directory

これはビルドされた共有ライブラリをちゃんと参照できていないということ。これらはbuild/lib以下にあるのでこれを/usr/local/libにコピーした上で環境変数LD_LIBRARY_PATHをセットした。

cp -p ./built/lib/lib*
export LD_LIBRARY_PATH=/usr/local/lib/

そして実行してみると今度は次のエラーである。

[watchman] while computing sockname: failed to create /usr/local/var/run/watchman/root-state: No such file or directory

これは単にディレクトリがないだけなので作成する。

mkdir -p /usr/local/var/run/watchman

ここまでやってようやく起動に成功する。ちなみにautogen.shの実行は結構時間がかかる。コンテナのなかで実行してるからかもしれないが。自分の環境だと10分以上は平気でかかった。

本来の目的であったsls offline startも問題なく実行できた。めでたし。

あとはこれをDockerfileに起こすだけ。

Remote Container 間で通信する

Remote Containerで実行している環境間で通信をする場合についてのメモ。

状況としては開発中のプロジェクトAとプロジェクトBがあって、それぞれ同じマシン上でRemote Containersを使って開発をしている状況。

プロジェクトAREST APIを提供するプロジェクトでコンテナ内でローカル開発サーバが起動していて、仮にhttp://localhost:3000/で待ち受けてるとしよう。

その状態でプロジェクトBからこのAPIをコールしたい。

まず、普通にlocalhostでアクセスするのはもちろんダメ。

ではコンテナに割り振られてるIPでのアクセスはどうかを試してみる。コンテナに割り振られてるIPアドレスdocker inspectで確認できる。

docker psで確認したいコンテナのIDを確認してdocker inspect <コンテナID>を実行して出力結果のIPAddressを確認すればいい。

さて、IPアドレスを確認すると

プロジェクトA: 172.17.0.1
プロジェクトB: 172.17.0.2

という感じだったのでhttp://127.17.0.1:3000/でアクセスしてみたがこれもConnection Refusedになる。

その後、あれやこれやとポートのフォワーディング周りで関係しそうな設定を探したり試したりしたところ、結果的には以下の設定を有効にすることでプロジェクトBのコンテナ内からプロジェクトAに対してアクセスができるようになった。

"remote.localPortHost": "allInterfaces",

デフォルトではここがlocalhostになっているんだがその場合全てのポートはlocalhostあてに転送するようにVSCodeが振る舞うみたい。

というわけで解決。

2022年6月に買った書籍/マンガ

6月も仕事が忙しく本を読む時間はあまり取れなかった。電車移動中に読むくらい。とはいえ購入はしたので紹介していく。

最近はKindleの日替わりセールがとてもお得なことを知ったのでちょっとでも興味あるものがセール対象になってたらすぐ買うようにしてる。

6月に買ったもので印象に残ったのはやはり山野一の『四丁目の夕日』と荒川弘の新作『黄泉のツガイ』かな。

書籍

親子で作れる! 摩訶不思議なサイエンススイーツ

  • 化学反応とかを利用したお菓子の作り方
  • とても面白く読めた
  • だがそうは言ってもお菓子作りなわけで材料も道具も必要なので料理しない自分にはハードル高い
  • 読むだけで満足したので、あとは娘がやりたいって言ったら考える

頸椎症の名医が教える 竹谷内式 首トレ 5分の体操で首の痛み・肩こり・腕のしびれが消える

  • 日替わりセールになってたので購入
  • 首と肩の慢性的なひどいこりに悩まされてるので

WEB+DB PRESS Vol.129

  • Reactの深淵を覗くために購入

システムを作らせる技術 エンジニアではないあなたへ

  • 以前からタイトルが気に入らないと言い続けてたやつ
  • レビューもいいし、内容はいいって話もちらほら寄せられたので半額になってるし購入してみた

地球の歩き方 ムー 異世界(パラレルワールド)の歩き方ー超古代文明 オーパーツ 聖地 UFO UMA

  • これは前に発表されたときに買おうと思ったまま買ってなかったやつ
  • 調べたら地球の歩き方ってこれ以外にも変わった企画とかコラボをやってた

デザイナーじゃないのに!

  • 日替わりセールだかで安くなってたので購入
  • 未読

パソコンも持ってなかった私がTwitterで年商1億円稼ぐ理由。

  • たまたま見かけて気になって仕方なかったので購入して読んでみた
  • 情報商材系かと思ってたけど内容は至極まとも
  • Twitterそのもので稼ぐのではなくマーケティングチャネルとして活用
  • 前に話題になったオンラインキャバクラの人
  • SNS運用代行とコンサルの会社
  • すごくよく考えてTwitterを上手く使って仕事を作り出してる内容で、ツイート一つに対してめっちゃ考えてる
  • バズらせるのに再現性もあるみたい。すごい

プロの「引き出し」を増やす HTML+CSSコーディングの強化書

  • 最近CSS周りに課題感感じてたので安くなってたし購入
  • 未読

イラスト記憶法で脳に刷り込む英単語1880

  • これも安くなってたので購入

コミック

弱虫ペダル 78

  • 今回は主人公出てこない
  • 新開兄弟のエピソード

ケンガンオメガ(13)

ミステリと言う勿れ(11)

  • 前半は退屈、後半から新展開

黄泉のツガイ 1巻

  • これは面白い
  • 特に最初の3話くらいが秀逸
  • 作者の最近の傾向とは違う
  • ハガレンを思い出す感じ
  • 荒川弘すごい

東京卍リベンジャーズ(28)

  • そろそろ終わりかと思いきやなかなか終わらない
  • 前半の喧嘩シーンは能力者同士の戦いみたいになってたw
  • なんで最後の最後に千咒とかの新しいキャラクターをいっぱい出したのかな

四丁目の夕日

  • 山野一の問題作が99円になってたので迷わず購入した
  • 最初から最後までこれでもかってくらい悲惨で絶望しかなかった

夏目アラタの結婚(8)

  • クライマックスに差し掛かりつつある
  • 真珠がついに外に

小説

プロジェクト・ヘイル・メアリー

  • プライムデー前の大規模セールで安くなってたので上下巻を購入
  • オデッセイの作者による本
  • まだ読み始めなのでなんとも
©Keisuke Nishitani, 2020   プライバシーポリシー