記事におけるNext.jsは、v13以降のApp Router (Server Components)を用いる前提での説明となります。
Pages Routerを用いている場合は、適宜Pages Routerでの書き方として読み替えてください。
この記事は何
最近Next.jsでウェブアプリケーションを作ることが多いのですが、
その時にオニオンアーキテクチャを採用してアプリケーションを作ることが多く、型も固まってきたので数回の記事にわたり紹介をしていきたいと思っています。
前回は
でApplication Serviceについて紹介しました。
今回はinfrastructures
ディレクトリやutils
ディレクトリに実装していくInfrastructureについて説明をしていきます。
Infrastructureとは
Infrastructureとは、アプリケーションを構築する上で必要になる外部システムへのアクセスを行う処理を実装するレイヤーです。
Infrastructuresには、以下のようなものを実装していきます。
- データベースアクセスを伴う処理
- ファイルシステムへのアクセス
- APIコール
- etc
基本的にディレクトリの分け方は自由ですが、僕はinfrastructures
には、いわゆるRepository
やFactory
など、主にDomain Objectの永続化に関わる処理を実装していき、それ以外の処理はutils
に実装していることが多いです。
Infrastructureレイヤーで実装したコードは、依存性の注入 (DI) を用いてApplication Serviceに依存するように実装します。
結果Infrastructureレイヤーは最も外側のレイヤーになります。
依存については以前↓の記事で説明しています。
実装例
今回は、
- Userの永続化を行うUserRepository
- ユーザーへの通知を行う処理
の実装を行なっていきます。
Infrastructureは性質上、外部のライブラリに強く依存することが多いので、今回は擬似的なコードで紹介できればと思います。
DBへのアクセスは実際はPrismaなどのDBクライアントを使うことが多いと思います。
import { IUserRepository } from '~/models/user/IUserRepository'
import { User } from '~/models/user/User'
import { dbClient } from 'dbClient' // 擬似ライブラリ
class UserRepository implements IUserRepository {
async save(user: User) {
if(await this.findByUuid(user.uuid)) {
const result = await dbClient.user.update({
where: {
uuid: user.uuid,
},
data: {
// 更新処理を記述する
},
})
return new User({
uuid: result.uuid,
... // Userオブジェクトを返す処理を実装する
})
} else {
const result = await dbClient.user.create({
data: {
// 作成処理を記述する
},
})
return new User({
uuid: result.uuid,
... // Userオブジェクトを返す処理を実装する
})
}
}
async findByUuid(uuid: string) {
const reuslt = dbClient.user.find({ where: { uuid: user.uuid } });
if(!result) return null
return new User({
uuid: result.uuid,
... // Userオブジェクトを返す処理を実装する
})
}
}
import { notificationClient } from 'notificationClient' // 擬似ライブラリ
export const sendNotification = async (userUuid: string) => {
await notificationClient.send(userUuid);
}
最後に
今回の記事では、Infrastructureの実装を行なってきました。
次回はPresentationレイヤーについて紹介していきます。
今までの記事