1. HOME
  2. ブログ
  3. IT技術
  4. 【Go言語】クリーンアーキテクチャで作るREST API
【Go言語】クリーンアーキテクチャで作るREST API

【Go言語】クリーンアーキテクチャで作るREST API

【Go言語(Golang)】クリーンアーキテクチャで作るREST API

以前に投稿された以下の笹川先生の実装をクリーンアーキテクチャで作り替えてみよう!という内容です。

クリーンアーキテクチャとは?

クリーンアーキテクチャとは?

参考:https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

クリーンアーキテクチャで調べるとよく出てくる例の円ですね。

ざっくり説明すると、円の中の各項目は矢印の向き(内側)に依存(参照)するようにして、特定の項目の仕様変更が他の項目に影響を及ぼさないようにしています。

それによってそれぞれが外部の項目を気にすることなくテストできたり、仕様変更の影響範囲が少なくなったりといった利点があります。

実装:クリーンアーキテクチャ化

では早速、クリーンアーキテクチャ化を進めていきましょう!

Entities

外側は内側の参照を持つため、内側から順に実装していきます。

こちらはそのままUserの構造体を入れているだけですね。

笹川先生のものと同じく、JSONでの受け取りからJSONでの返却まで、このUser構造体でやりとりするようにします。

Use Cases

UseCasesではFirestoreだったりecho(Http通信)だったりの技術的な要素を省いた、ビジネスルールを記載していきます。

具体的には、今回作成するaddUserの実装は以下のようになっているので、

  1.  echoでユーザーデータ(JSON)を受け取り
  2. Firestoreにユーザーデータを追加
  3. echoで全てのユーザーデータ(JSON)を返す or エラーを返す

技術的要素を省いて、

  1.  ユーザーデータを受け取り
  2. 何かしらにユーザーデータを追加
  3. 全てのユーザーデータを返却する or エラーを返す

といった感じに実装していきます。

また、addUserで全てのユーザーを返却するついでに、全ユーザー返却単品のものも追加してあります。

Portではinterfaceのみを記述し、実体は別のgoファイルで実装します。

次は、同じくUseCasesのInteractorです。

Interactorでは、ユーザーデータを受け取るInputPortの実体と、先ほどの技術的要素を省いた1~3の手順を実装します。

技術的要素を省いた箇所についてはinterfaceを呼び出すことよって、UseCasesの外側にある技術的要素を隠蔽していますね。

これを依存性逆転の原則といい、円の外側への依存を回避した上で、コード変更の影響を最小限にすることができます。

Presenters

Presentersでは、OutputPortの実体を実装します。

また、ここからは技術的要素を含んでの実装になるので、echoやFirestore関連の実装も行なっていきます。

出力自体は、echoが行ってくれるので、echoのPOSTメソッド等でreturnする値を定義しています。

今回実装するREST APIでは、「全てのユーザーを返す」or 「エラーを返す」しかないので、この2パターンのみ実装していますね。

Gateways

Gatewaysでは、DB操作の実体を実装します。

なので、Firestore関連の実装をする感じになりますね。

ここはほとんど、笹川先生が実装したものと同じですね。

少し違う点としては、NewUserRepositoryでFirestoreのClientの初期化用interfaceを要求することで、AddUserとGetUsersそれぞれでFirestoreClientの初期化とClose処理を行うようにしています。

これで本番環境と開発環境を外部から変更することが可能になりますね。

また、errorを返却する際には fmt.Errorf でerror文を加工し、PresentersのOutputErrorに渡した際にそのerrorを表示するようにすることで、出力関連の処理を全てPresentersに任せるようにしています。

Controllers

Controllersでは、InputPort・OutputPort・Repositoryを組み立てて、InputPortを実行します。

UserControllerのメソッドであるAddUserとGetUsersでは、echo.POSTの第二引数の型である func(c echo.Context) error を返しています。

なので、基本的には元々そちらに書かれていた内容を満たすような実装をしているだけですね。

Database(Firestore)

これは単純に、Firestoreのクライアントを取得するための実装です。

Gatewaysで宣言している、FirestoreClientFactoryを実装している感じですね。

Gatewaysの項目でも説明しましたが、これで容易に外部から本番環境とか開発環境の変更をすることが可能です。

Drivers

Driversでは、Controllerを呼び出し、echoの設定を行います。

今回は、笹川先生の記事にはなかったツールとして、wireを使用してみました。

DIする時の面倒な初期化処理を自動で生成してくれるツールです。

上記のコードを書いた後、drivers上でwireコマンドを実行することで、以下のコードが生成されます。

Controllerを初期化するために各interfaceの実装を指定して、最終的にDriversの初期化を行っているだけですね。

main.go

最後に、main.goでuser_driverを呼び出してみましょう!

ここまで複雑な構造でしたが、main.goから見るとすごい簡単ですね!

動作確認

Postmanで確認してみると、以下のようになりました。

GetUsers

GetUsers

AddUser

AddUser

ちゃんと動作してることが確認できました!

まとめ

取り扱ったコードは結構単純な処理だったので、クリーンアーキテクチャ化の恩恵は少し薄いかもしれませんが、仕様変更に強く、テストが書きやすいコードができたと思います。

今回のコードは以下のリポジトリにまとめてありますので、ぜひ確認してみてください!

https://github.com/ryuto-imai/firestore_clean_architecture

関連記事

採用情報

\ あの有名サービスに参画!? /

バックエンドエンジニア

\ クリエイティブの最前線 /

フロントエンドエンジニア

\ 世界を変える…! /

Androidエンジニア

\ みんなが使うアプリを創る /

iOSエンジニア