gqlgen で generate 時に「unable to open schema」となる場合の対処
事象
以下のように、schema.graphql が見つからない旨のエラーが出ることがある。
$ go run github.com/99designs/gqlgen generate unable to open schema: open schema.graphql: no such file or directory exit status 1
例えば、graphql スキーマは src/resources/graphql の中に入れたいんじゃ!と設定を変えていると見ることになると思われ。
解決方法
gqlgem.yml のスキーマファイルのパスは、go run ~ generate コマンドを実行したディレクトリからの相対パスとなっている模様。
(ここ以外のパス記述するところは gqlgen.yml のあるディレクトリが root となる。)
# Where are all the schema files located? globs are supported eg src/**/*.graphqls schema: - src/resources/graphql/*.graphqls # Where should the generated server code go? exec: filename: src/application/graph/generated.go package: graph
なので、gqlgen.yml を src のあるディレクトリに移動させることで対応できた。
もしくは、gqlgen.yml のあるディレクトリまで cd して go run ~ generate すれば OK。
gqlgen で、オーバーフェッチを防ぐためのそのフィールド専用のリゾルバを定義する
1. gqlgen.yml で設定を有効化する
gqlgen.yml の autobind 設定のコメントを解除し、有効化する。
# gqlgen will search for any type names in the schema in these go packages # if they match it will use them, otherwise it will generate them. autobind: - "github.com/[username]/gqlgen-todos/graph/model"
この設定があることで、スキーマに定義されている型で、github.com/[username]/gqlgen-todos/graph/model
に対応するものがあればそれを利用し、定義されていなければ自動生成してくれるようになる。
2. gqlgen.yml に、リゾルバを利用するフィールドを明記する
gqlgen.yml の下部に記載。
# This section declares type mapping between the GraphQL and go type systems # # The first line in each type will be used as defaults for resolver arguments and # modelgen, the others will be allowed when binding to fields. Configure them to # your liking models: ID: model: - github.com/99designs/gqlgen/graphql.ID - github.com/99designs/gqlgen/graphql.Int - github.com/99designs/gqlgen/graphql.Int64 - github.com/99designs/gqlgen/graphql.Int32 Int: model: - github.com/99designs/gqlgen/graphql.Int - github.com/99designs/gqlgen/graphql.Int64 - github.com/99designs/gqlgen/graphql.Int32 Todo: # Todo型の fields: user: # user フィールドの resolver: true # リゾルバを有効化
3. model を定義する
graph/model/todo.go
にモデルを定義。
package model type Todo struct { ID string `json:"id"` Text string `json:"text"` Done bool `json:"done"` UserID string `json:"userId"` User *User `json:"user"` }
4. generate コマンド実行
go run github.com/99designs/gqlgen generate
5. Todo クラスの user フィールドを解決するリゾルバを実装
新たなリゾルバが生成されているため、中身を実装する。
func (r *todoResolver) User(ctx context.Context, obj *model.Todo) (*model.User, error) { return &model.User{ID: obj.UserID, Name: "user " + obj.UserID}, nil }
todoResolver
というのが、Todo クラスのフィールド用のリゾルバ。
これを実装することによって、Todo.user をクエリに指定された時に初めてユーザを取得する処理が走るようになる。
このように賢くオーバーフェッチを防げるのが、REST にはない、graphql の強みと言える。
(裏を返せば、うまくコントロールしてやらないと強みを活かせないとも言えるが).
最後に
この内容は gqlgen 公式のチュートリアルの内容と全く同じです。
あとで見返すときに英語の意味を考える手間を省くため。
DockerでTypescriptなExpress + Reactの開発環境構築
はじめに
MacBookProを買ったので、どうせならローカル環境を汚さずに開発したかった。
単純にDockerに興味があった。
Dockerとは
VMWareのように仮想環境をいくつも用意できる。
Dockerの仮想環境は「コンテナ」と呼ばれる。(厳密には仮想環境ではない)
公式に用意された「イメージ」を元にコンテナを作成することもできる。
Dockerの何が優れているか
仕事でVMやVagrantを使ったことがある方はわかると思うが、結構リソースを食う。
Dockerはその辺いい感じにしてくれてるので軽い。
「DockerFile」を用意するだけでチーム内で同じ環境を用意することができる。
Dockerだけ入っていれば環境構築が可能になる。
Dockerの仕組みを拡張するような便利なライブラリが多数あるのでさらに便利。
今回は「docker-compose」を利用する。
Expressのコンテナを作成する
下記の記事を参考に、docker-composeでExpressの環境を構築する。(丸投げ)
今回、フロントはReactを使うため、jadeの話は飛ばしても大丈夫です。
めちゃくちゃわかりやすく書いてくださっているので大変助かりました。
Reactのコンテナを作成する
フロントプロジェクト用のディレクトリを作成します
$ mkdir front
docker-compose.yamlを以下のように変更・追記します。
version: '3' services: # サーバサイド server: # 起動イメージ image: node:16 # 環境変数 environment: - DEBUG=app:* tty: true # ホスト側のポート:コンテナのポート ports: - '3000:3000' # ホスト側のsrcをコンテナのappにマウント volumes: - ./server/src:/app # 起動時のカレントフォルダ working_dir: /app # 起動後に実行するコマンド command: sh -c 'npx tsc; npm run dev' # フロントエンド front: # 起動イメージ image: node:16 # 環境変数 environment: - PORT=8000 tty: true # ホスト側のポート:コンテナのポート ports: - '8000:8000' # ホスト側のsrcをコンテナのappにマウント volumes: - ./front/src:/app # 起動時のカレントフォルダ working_dir: /app # 起動後に実行するコマンド command: sh -c 'yarn start'
わかりやすいように、サーバサイドのサービス名を「server」フロントのサービス名を「front」に変更しています。
環境変数のPORT=8000
はReactを8000番のポートで公開するためです。
ports
でホスト側のポートを8000に指定していたのですが、Reactのデフォルト設定では3000で公開されます。
その場合下記のように表示され、コンソールから直接リンクを開くことができないので8000に指定しました。
front用コンテナのbashを呼び出す
$ docker-compose run --rm front /bin/bash
create-react-app
$ npx create-react-app --template typescript .
docker-composeを起動する
$ docker-compose up
下記の画面が表示されれば成功です
最後に
最近「そんなこといちいち説明しなくてもわかるか・・・」と思ってしまうところがあるが、そこできちんと説明できるような大人になりたいなと思う。
この業界、主語が疎かになったり略語やマイナーな呼び方を使って新人エンジニアを困惑させたりする大人が大変多いので、あんまりそんなふうにはなりたくない。
数ヶ月後の自分に届け。
ローカル開発環境を外部公開する
はじめに
LINE BOTを開発する際、開発環境でWebhook(コールバック)を受け取りたいという場面に遭遇したので。
そのために開発環境を外部公開することを「トンネリング」と呼ぶ。
トンネリング
今回は『localtunnnel』というサービスを利用する。
トンネリングサービスって、時間制限があってお金払わないと30分しか公開できません!みたいなのが結構ありますが、『localtunnel』には特に制限がないようなので選択しました。
仕組みを考えたら「そりゃそうだろ」なんですが、localtunnelのサブドメインとして公開されるため、何も設定することなくhttpsで公開されるのもいいんですよね。
企業が公開しているAPIはhttpsでないとコールバックを受け取れないことがほとんどなので。
手順
GithubのREADMEが常に正なので基本はそっちを参考にしてください。
locultunnelをインストール
(特定プロジェクトのみで利用する場合は-gを外してください)
npm install -g localtunnel
ローカルサーバで任意の開発中プロジェクトを起動します
npm start
などlocultunnelを起動します
この時、開発中プロジェクトのポート番号を指定します
lt --port 3030
下記のようにurlが発行されますので、それをWebhook(コールバック)を受け取るURLに指定するだけです
注意
ランダムなURLが生成されるので多分大丈夫ですが、ローカル環境を外部公開してしまうのは結構危険な行為でもあると思います。
今回は個人開発のアプリケーションのため、万が一不正アクセスを受けても大丈夫ですが(PCも趣味にしか使ってないやつなので)、会社の規約的にNGとかは十二分にあり得るので気をつけてください。
最後に
引っ越しが落ち着いて3週間ぶりに開発するぞ!って躍起になったらトンネリングどうやるんだっけ?となったので忘備録的に書いた。
こういう記事、ほんとに数ヶ月後の自分の役に立つので侮れないですよ!
g-notice-client作成
クライアントプロジェクト
PDFのパースに限界があって、壊れたデータがどうしても入ってしまう。
なので、管理画面を作成してそこで手で修正しようと思った。
技術選定
ある程度慣れてるのでReactに決定。
webpack使ってみようかと思ったけど、そこまででかくなる予定ではないし一旦いいかなと思いました。
今後
- カラムクリックで編集画面を表示する
- 👆でCRUD操作可能にする
- ヘッダクリックでソート可能にする
- 認証を実装する
発生している問題
- .envの環境変数が超絶使いにくい
- typescriptの型エラーになっちゃう。
- @types/nodeで対応する予定。
さいごに
先日SmatrHRさんのオンラインミートアップにお呼ばれして、smarthr-uiのお話を聞いたので早速使ってみた。
github.com
忖度抜きで普通に使いやすかったです。
せっかく国産なんだから、日本語のドキュメントもあればいいのにって思わなくもなかった。
MySQLで濁音・半濁音がうまく検索できない
対処
- collationを設定する
経緯
ガンプラ出荷予定を返すアプリを作っていたところ、下記のように濁音・半濁音をうまく検索できていないことを確認。
MySQLって濁音・半濁音はうまく検索できないのね… pic.twitter.com/vswIq6opQS
— 片山 (@poihey) 2021年7月4日
これに対して、友達がcollationだよと教えてくれた。
MySQLの検索で濁音・半濁音 | Komekkun.com/blog
ところで、僕はmigrationツールとしてSequelizeライブラリを利用している。 Sequelizeではどう書けばいいだろうかとなったのである。
実装
下記のようにmigrationファイルを作成すればOKだった。
$ sequelize migration:create --name change_collation
これでmigrationファイルが生成される。
'use strict'; module.exports = { up: async (queryInterface, Sequelize) => { await queryInterface.sequelize.query( `ALTER DATABASE ${ queryInterface.sequelize.config.database } CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;` ); /** * Add altering commands here. * * Example: * await queryInterface.createTable('users', { id: Sequelize.INTEGER }); */ }, down: async (queryInterface, Sequelize) => { /** * Add reverting commands here. * * Example: * await queryInterface.dropTable('users'); */ } };
このように、普通にSQL文を実行させるだけ。 これでローカルではOK!ローカルでは・・・
Herokuの本番環境で問題発生
Herokuにデプロイして動かしたところ、以下のようなエラーが出ていた
Error: Illegal mix of collations
HerokuでcleatDBのMySQLを利用すると、初期設定により別の文字コードが指定されているため、書き込みはUTF8で行ってくれない。 そのため、DBに設定されているcollationと初期設定のcollationが異なるため上記のようなエラーを吐く。
これを回避するため、利用している環境変数を変更する必要があるのだが、コンソール上では変更不可だった。(変更した直後に自動的に前の値でheroku config:setされてしまう)
おそらくHerokuの認証が厳しくなったためと思われる。 WebでHerokuの管理画面を開き、下記のように設定した。
初期設定のDBURLに
&useUnicode=true&encoding=utf8mb4&collation=utf8mb4_general_ci
を追加しただけである。
これによってcollationとDBの設定が一致するため、想定通りに動作する。
g-notice これから
追記
このアプリについての詳細は、githubとtrelloで管理しようと思った(ブログ書くのが結構たいへんなので)
不具合対応の方法などは別途記事に記載しまする
これから
ちょうど転職活動をしていることもあって、g-noticeをポートフォリオ的に使おうと思い、今日から三度開発を始めた。
ロードマップ
今日
- テーブル設計見直し
- ES6に対応
- リファクタリング
7/2~3
- trello作る
- データ登録部分の完成
7/4~5
- LINE連携の完成
7/6~7
- 管理画面作成
工数余ったら
- typescript対応
業務時間外にしか作業時間を取れない(当たり前)ので、結構しんどいかもしれない。
最近ふと思ったこと
あれもやりたい、これもやりたいでいつも結局完成しないから、「まずミニマムな状態でリリースする」ことが個人開発で一番大切かもしれない・・・。