こんにちは。プロダクト基盤グループの inari111 です。STORES の各プロダクトへ導入する共通基盤を開発しています。
私の部署内で2つ目の基盤プロダクトとなる組織管理基盤を作ったのでご紹介します。
社内では「maja(マヤ)」と呼ばれています。
この記事では maja の Go アプリケーション部分について説明します。
maja とは
事業者、店舗、従業員、従業員の権限を管理する基盤プロダクトです。
各プロダクトがそれぞれ実装していた事業者や従業員といったデータを集約していくために maja を作ることになりました。
maja を作ることになった詳しい経緯はこちらの記事をご覧ください。
maja フロントエンドはこちらで紹介されています。
バックエンドは Go で実装していて、 GraphQL の API を提供しています。
アーキテクチャ
シンプルなレイヤードアーキテクチャで実装しています。
以前実装した ID 基盤とほぼ同じアーキテクチャで各レイヤーの責務は同じです。
DI
google/wire を使って DI を行っています。
Handler
ルーターに go-chi/chi を使っています。
GraphQL を採用しているので 99designs/gqlgen を使ってスキーマから resolver やモデルを生成し使っています。
Application
ユースケースと言われるような、アプリケーションのビジネスルールを表現するレイヤーです。
具体的には、Domain 層の呼び出し、 Repository を使ったデータの永続化や取得、外部 API 出しなどを行います。
また、DB のトランザクション処理はここで行っています。
Domain
ドメインモデル、ドメインロジックの一部、Repository 等の interface を置いています。
Infra
Infra 層では DB モデル、ドメイン層で定義した Repository の実装、その他 interface の実装を置いています。
DB まわりは jmoiron/sqlx を使って素朴に実装しています。
テスト
テストは主に2種類あります。
Application 層(ユースケース)のユニットテスト
下記のような方針で書いています。
- 外部へのリクエストはモック
- DB はモックしない
- API の E2E テストでカバーできている場合はなくても OK
API の E2E テスト
方針は Application 層とほぼ同じですが、権限のチェックなど Application 層に来る前に行っている処理のテストケースも書いています。
- 外部へのリクエストはモック
- DB はモックしない
- 権限がないときにエラーになることのテストケースも書く
- Yamashou/gqlgenc を使って GraphQL スキーマと Query から Client 用のコードを生成する
E2E テストは下記のような流れです。
- go test 内で API サーバを起動
- 生成した Client を使って API にリクエスト
- E2E テスト終了後、 API サーバのシャットダウン
バリデーション
GraphQL のスキーマにバリデーション用のディレクティブを定義し、 input のフィールドに指定しています。
constraint directiveの定義はこちら。
directive @constraint( maxLength: Int format: String pattern: String startsWith: String endsWith: String required: Boolean ) on INPUT_FIELD_DEFINITION
input のフィールドに下記のようにバリデーションルールを記載します。
# 例 input AddEmployeeInput { """ 従業員の名前 """ name: String! @constraint(required: true, maxLength: 100) """ 招待を送るメールアドレス """ email: Email @constraint(format: "email") }
これらのバリデーションルールからバリデーション用のコードを生成しています。
バックエンドは gqlgen を使ったコード生成をするときに go-playground/validator 用のタグをstruct のフィールドに付与しています。
// GraphQL スキーマから生成した Go の struct type AddEmployeeInput struct { // 従業員の名前 Name string `json:"name" validate:"required,max=40"` // 招待を送るメールアドレス Email *string `json:"email,omitempty" validate:"omitempty,email"` }
各レイヤーの依存関係のチェック
fe3dback/go-arch-lint を使いCIでチェックしています。
各レイヤーの依存関係は人間の目でチェックするのは限界があるので、こういったツールでチェックするのがおすすめです。
おわりに
Go アプリケーションまわりについて書きました。
今回説明できなかったところや詳しい解説は別記事にて書いていけたらと思います。