体重133キロからのプログラミング

体重はちょっと減って今125キロです。

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 公式のチュートリアルの内容と全く同じです。
あとで見返すときに英語の意味を考える手間を省くため。

gqlgen.com

DockerでTypescriptなExpress + Reactの開発環境構築

はじめに

MacBookProを買ったので、どうせならローカル環境を汚さずに開発したかった。
単純にDockerに興味があった。

Dockerとは

VMWareのように仮想環境をいくつも用意できる。
Dockerの仮想環境は「コンテナ」と呼ばれる。(厳密には仮想環境ではない)
公式に用意された「イメージ」を元にコンテナを作成することもできる。

Dockerの何が優れているか

仕事でVMVagrantを使ったことがある方はわかると思うが、結構リソースを食う。
Dockerはその辺いい感じにしてくれてるので軽い。
「DockerFile」を用意するだけでチーム内で同じ環境を用意することができる。
Dockerだけ入っていれば環境構築が可能になる。
Dockerの仕組みを拡張するような便利なライブラリが多数あるのでさらに便利。
今回は「docker-compose」を利用する。

Expressのコンテナを作成する

下記の記事を参考に、docker-composeでExpressの環境を構築する。(丸投げ)

qiita.com

今回、フロントは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に指定しました。

f:id:poinorou:20211212133853p:plain
コンソールには3000番ポートで公開されていると表示される

front用コンテナのbashを呼び出す
$ docker-compose run --rm front /bin/bash

create-react-app
$ npx create-react-app --template typescript .

docker-composeを起動する
$ docker-compose up

下記の画面が表示されれば成功です f:id:poinorou:20211212134939p:plain

最後に

最近「そんなこといちいち説明しなくてもわかるか・・・」と思ってしまうところがあるが、そこできちんと説明できるような大人になりたいなと思う。
この業界、主語が疎かになったり略語やマイナーな呼び方を使って新人エンジニアを困惑させたりする大人が大変多いので、あんまりそんなふうにはなりたくない。
数ヶ月後の自分に届け。

ローカル開発環境を外部公開する

はじめに

LINE BOTを開発する際、開発環境でWebhook(コールバック)を受け取りたいという場面に遭遇したので。
そのために開発環境を外部公開することを「トンネリング」と呼ぶ。

トンネリング

今回は『localtunnnel』というサービスを利用する。
トンネリングサービスって、時間制限があってお金払わないと30分しか公開できません!みたいなのが結構ありますが、『localtunnel』には特に制限がないようなので選択しました。

github.com

仕組みを考えたら「そりゃそうだろ」なんですが、localtunnelのサブドメインとして公開されるため、何も設定することなくhttpsで公開されるのもいいんですよね。
企業が公開しているAPIhttpsでないとコールバックを受け取れないことがほとんどなので。

手順

GithubのREADMEが常に正なので基本はそっちを参考にしてください。

  • locultunnelをインストール
    (特定プロジェクトのみで利用する場合は-gを外してください)
    npm install -g localtunnel

  • ローカルサーバで任意の開発中プロジェクトを起動します
    npm startなど

  • locultunnelを起動します
    この時、開発中プロジェクトのポート番号を指定します
    lt --port 3030

下記のようにurlが発行されますので、それをWebhook(コールバック)を受け取るURLに指定するだけです f:id:poinorou:20210731103806p:plain

注意

ランダムなURLが生成されるので多分大丈夫ですが、ローカル環境を外部公開してしまうのは結構危険な行為でもあると思います。
今回は個人開発のアプリケーションのため、万が一不正アクセスを受けても大丈夫ですが(PCも趣味にしか使ってないやつなので)、会社の規約的にNGとかは十二分にあり得るので気をつけてください。

最後に

引っ越しが落ち着いて3週間ぶりに開発するぞ!って躍起になったらトンネリングどうやるんだっけ?となったので忘備録的に書いた。
こういう記事、ほんとに数ヶ月後の自分の役に立つので侮れないですよ!

g-notice-client作成

f:id:poinorou:20210708224326p:plain

クライアントプロジェクト

PDFのパースに限界があって、壊れたデータがどうしても入ってしまう。
なので、管理画面を作成してそこで手で修正しようと思った。

技術選定

ある程度慣れてるのでReactに決定。
webpack使ってみようかと思ったけど、そこまででかくなる予定ではないし一旦いいかなと思いました。

github.com

今後

  • カラムクリックで編集画面を表示する
  • 👆でCRUD操作可能にする
  • ヘッダクリックでソート可能にする
  • 認証を実装する

発生している問題

  • .envの環境変数が超絶使いにくい
    • typescriptの型エラーになっちゃう。
    • @types/nodeで対応する予定。

さいごに

先日SmatrHRさんのオンラインミートアップにお呼ばれして、smarthr-uiのお話を聞いたので早速使ってみた。
github.com 忖度抜きで普通に使いやすかったです。
せっかく国産なんだから、日本語のドキュメントもあればいいのにって思わなくもなかった。

MySQLで濁音・半濁音がうまく検索できない

対処

  • collationを設定する

経緯

ガンプラ出荷予定を返すアプリを作っていたところ、下記のように濁音・半濁音をうまく検索できていないことを確認。

これに対して、友達がcollationだよと教えてくれた。

f:id:poinorou:20210706000325p:plain

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の管理画面を開き、下記のように設定した。

f:id:poinorou:20210706001852p:plain

初期設定のDBURLに &useUnicode=true&encoding=utf8mb4&collation=utf8mb4_general_ci
を追加しただけである。

これによってcollationとDBの設定が一致するため、想定通りに動作する。

f:id:poinorou:20210706002058p:plain

g-notice これから

追記

このアプリについての詳細は、githubとtrelloで管理しようと思った(ブログ書くのが結構たいへんなので)
不具合対応の方法などは別途記事に記載しまする

これから

ちょうど転職活動をしていることもあって、g-noticeをポートフォリオ的に使おうと思い、今日から三度開発を始めた。

ロードマップ

  • 今日

  • 7/2~3

    • trello作る
    • データ登録部分の完成
  • 7/4~5

    • LINE連携の完成
  • 7/6~7

    • 管理画面作成
  • 工数余ったら

    • typescript対応

業務時間外にしか作業時間を取れない(当たり前)ので、結構しんどいかもしれない。

最近ふと思ったこと

あれもやりたい、これもやりたいでいつも結局完成しないから、「まずミニマムな状態でリリースする」ことが個人開発で一番大切かもしれない・・・。