[NestJS]少し大きな規模のRESTfull APIを構築するディレクトリ構成を考えてみる

[NestJS]少し大きな規模のRESTfull APIを構築するディレクトリ構成を考えてみる

2022-09-048 min read

目次

  1. 概要
  2. 経緯
  3. やりたいこと
  4. ディレクトリ構成
  5. プロジェクト作成
  6. 参考にしたサイト

概要

NestJSで少し大きな規模のRESTfull APIを構築するディレクトリ構成を考えてみました。 行おうと思った経緯と具体的な構成および構築方法について記載してます。

経緯

モジュラモノリスっぽいことをやりたい

※モジュラモノリス=モノリスと同様に単一リポジトリ・単一デプロイは維持するが、内部のソフトウェアの部品はモジュール単位で分割された状態と定義

アプリケーションの規模が大きくなり何らかの形で分割したいなと思ってましたが、 マイクロサービスを導入するほど大掛かりなこともやりたくないろ感じていた時に、 アプリケーションの中でモジュールという単位でビジネスロジックを線引きを行うことができる "モジュラモノリス" という単語が目に入り試してみようと思いました。

やりたいこと

やりたいことを次のように仮定します。

  1. RESTfull API を構築する
  2. APIのパスにバージョン名を入れてバージョニングを行う
  3. APIは一般公開向けと管理系の2つに大きく分かれる
  4. APIはユーザ・アイテムといったリソース情報を返却する
  5. これらのリソースを一般公開系けと管理系それぞれで利用する
  6. 管理系のレスポンスは機微な情報が含まれることを想定し一般系の混同利用は避ける

具体的にAPIのエンドポイントは以下となります。

GET /v1/front/users
POST /v1/front/users
PATCH /v1/front/users
DELETE /v1/front/users
GET /v1/front/projects
...略
GET /v1/front/issues
...略
GET /v1/admin/users
...略
GET /v2/admin/users

ディレクトリ構成

結果的にディレクトリは以下の構成になりました。

./src
├── app.controller.ts
├── app.module.ts
├── app.service.ts
├── main.ts
├── v1
│   ├── admin
│   │   ├── admin.module.ts
│   │   ├── issues
│   │   │   ├── issues.controller.ts
│   │   │   ├── issues.module.ts
│   │   │   └── issues.service.ts
│   │   ├── projects
│   │   │   ├── projects.controller.ts
│   │   │   ├── projects.module.ts
│   │   │   └── projects.service.ts
│   │   └── users
│   │       ├── users.controller.ts
│   │       ├── users.module.ts
│   │       └── users.service.ts
│   ├── front
│   │   ├── front.module.ts
│   │   ├── issues
│   │   │   ├── issues.controller.ts
│   │   │   ├── issues.module.ts
│   │   │   └── issues.service.ts
│   │   ├── projects
│   │   │   ├── projects.controller.ts
│   │   │   ├── projects.module.ts
│   │   │   └── projects.service.ts
│   │   └── users
│   │       ├── users.controller.ts
│   │       ├── users.module.ts
│   │       └── users.service.ts
│   └── v1.module.ts
└── v2 #おまけ
    ├── front
    │   ├── front.module.ts
    │   └── users
    │       ├── users.controller.ts
    │       ├── users.module.ts
    │       └── users.service.ts
    └── v2.module.ts

プロジェクト作成

$ npx nest new nest-test
$ npx nest generate module v1
# CREATE src/v1/v1.module.ts (79 bytes)
# UPDATE src/app.module.ts (300 bytes)
$ npx nest generate module v1/front
# CREATE src/v1/front/front.module.ts (82 bytes)
# UPDATE src/v1/v1.module.ts (157 bytes)
$ npx nest generate module v1/admin
$ npx nest generate resource v1/front/users
# ? What transport layer do you use? REST API
# ? Would you like to generate CRUD entry points? Yes
# CREATE src/v1/front/users/users.controller.spec.ts (566 bytes)
# CREATE src/v1/front/users/users.controller.ts (894 bytes)
# CREATE src/v1/front/users/users.module.ts (247 bytes)
# CREATE src/v1/front/users/users.service.spec.ts (453 bytes)
# CREATE src/v1/front/users/users.service.ts (609 bytes)
# CREATE src/v1/front/users/dto/create-user.dto.ts (30 bytes)
# CREATE src/v1/front/users/dto/update-user.dto.ts (169 bytes)
# CREATE src/v1/front/users/entities/user.entity.ts (21 bytes)
# UPDATE src/v1/front/front.module.ts (160 bytes)
$ npx nest generate resource v1/front/projects
$ npx nest generate resource v1/front/issues
$ npx nest generate resource v1/admin/users
$ npx nest generate resource v1/admin/projects
$ npx nest generate resource v1/admin/issues
$ npx nest generate module v2
$ npx nest generate module v2/front
$ npx nest generate resource v2/front/users

これでファイル・ディレクトリの構成は完成です。 しかしこの状態で起動してもエンドポイントが期待通りマッピングされませんでした。

RouterModuleを利用して解決することにしました。

具体的にはモジュールファイルに対して次のような変更を行います。

例: src/v1/front/front.module.ts の場合

変更前

import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { ProjectsModule } from './projects/projects.module';
import { IssuesModule } from './issues/issues.module';

@Module({
  imports: [UsersModule, ProjectsModule, IssuesModule]
})
export class FrontModule {}

変更後

import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { ProjectsModule } from './projects/projects.module';
import { IssuesModule } from './issues/issues.module';
import { RouterModule } from '@nestjs/core';

const path = 'v1/front'
const modules = [
  UsersModule,
  ProjectsModule,
  IssuesModule,
];
@Module({
  imports: [
    ...modules,
    ...modules.map(module => RouterModule.register([{
      path,
      module,
    }]))
  ]
})
export class FrontModule {}

これを

  • src/v1/front/front.module.ts
  • src/v1/admin/admin.module.ts

等に設定を行います。

これでベースのエンドポイントの調整が可能となります。

$ curl http://localhost:3000/v1/front/users/1
# This action returns a #1 user%  

参考にしたサイト

  1. https://ohbarye.hatenablog.jp/entry/2021/01/22/admin-feature-architecture-patterns
  2. https://docs.nestjs.com/recipes/router-module
  3. https://github.com/nestjsx/nest-router
  4. https://devblog.thebase.in/?page=1650335400
Recommends
[NestJS]少し大きな規模のRESTfull APIを構築するディレクトリ構成を考えて...
2022-09-04
nestjs
typescript
%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3
NestJSアプリケーションをwebpackでBundle
2022-02-20
javascript
typescript
nestjs
Fisher-Yates shuffleで配列シャッフル [js/ts/php]
2022-06-19
javascript
node.js
typescript
javascriptで累積和を解く
2022-02-27
%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0
%E7%AB%B6%E6%8A%80%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%83%9F%E3%83%B3%E3%82%B0
atcoder
TypeScriptに入門した
2021-01-04
javascript
typescript
npm
Vue/Nuxt.js 触ってた人が Next.js に入門する
2021-01-03
javascript
react
next.js
Prisma MySQL でUTC以外の任意のタイムゾーンを利用するのが難しい件
2022-08-08
prisma
typescript
mysql
Prisma TypeScript MySQLなプロジェクトの構築
2022-08-08
prisma
typescript
mysql
Prisma TypeScript SQLiteなプロジェクトの構築
2022-08-06
prisma
typescript
sqlite
JavaScriptでUTF-16コードを文字列に変換
2022-06-18
javascript
node.js
[JS]乱数でランダムな整数を生成する
2022-06-18
javascript
node.js
[JS]BigIntでMathが使えない件
2022-06-12
javascript
node.js
atcoder
[AWS CDK]ECS FargateでNestJSで作成したRESTfull APIデ...
2022-05-24
nestjs
amazon%20aws
aws%20cdk
[CDK]SNS+SQS+DynamoDBでBounceとComplaint情報を収集する...
2022-04-11
amazon%20aws
node.js
typescript
[AmazonSES] node.js と ejs を利用してEメールを送信する
2022-04-09
javascript
node.js
amazon%20aws
New Posts
zplug 環境の構築とpromptの調整
2022-11-13
zsh
mac
linux
バッチ処理を採用する際に考慮したことと実装の諸々
2022-10-30
%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3
[JS]Intl.DateTimeFormatで和暦と西暦を変換
2022-08-18
javascript
[NestJS]少し大きな規模のRESTfull APIを構築するディレクトリ構成を考えて...
2022-09-04
nestjs
typescript
%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3
Prisma MySQL でUTC以外の任意のタイムゾーンを利用するのが難しい件
2022-08-08
prisma
typescript
mysql
Prisma TypeScript MySQLなプロジェクトの構築
2022-08-08
prisma
typescript
mysql
Prisma TypeScript SQLiteなプロジェクトの構築
2022-08-06
prisma
typescript
sqlite
[AWS]Lambda vs Fargate. APIを実装する場合に思うこと
2022-07-30
amazon%20aws
amazon%20ecs
%E9%9B%91%E8%AB%87
macOSにzigをインストールしてHello World!する
2022-07-18
zig
mac
[AWS CDK] Cognito の OIDC プロバイダに Auth0 を設定
2022-07-03
auth0
amazon%20aws
aws%20cdk
Amazon S3 でライフサイクルポリシーを設定する
2022-06-19
amazon%20aws
amazon%20s3
AWS Certified Developer Associate に合格した
2022-06-19
amazon%20aws
%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93
Fisher-Yates shuffleで配列シャッフル [js/ts/php]
2022-06-19
javascript
node.js
typescript
JavaScriptでUTF-16コードを文字列に変換
2022-06-18
javascript
node.js
[JS]乱数でランダムな整数を生成する
2022-06-18
javascript
node.js
Hot posts!
Proxy環境下でcurlを実行する
2019-12-07
linux
curl
OpenCVのMatのタイプ一覧表
2018-11-25
%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86
opencv
Macでも利用できるDBクライアント MySQL PostgreSQL Oracle など
2019-12-21
linux
%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9
mysql
TablePlusを使ってみる。シンプルでモダンなSQLクライアントツール
2018-09-30
%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9
DBクライアントツールはDBeaverをおすすめしたい
2021-03-08
oracle
mysql
sqlite
AWS S3のアクセスキーIDとシークレットアクセスキーの取得 作業用ユーザを作成
2019-06-12
amazon%20aws
linux
amazon%20s3
AtCoderで初めて色がつくまでの話(茶色) レートが中々上がらなかった原因
2018-11-25
%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0
%E7%AB%B6%E6%8A%80%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0
%E9%9B%91%E8%AB%87
CentOS8でEPELとPowerToolsリポジトリの有効化
2020-11-30
centos
red%20hat
EPEL
Macでターミナルからポートスキャンを行う方法。
2018-12-09
linux
mac
apple
Python + OpenCVのfillConvexPolyで複雑なポリゴンを描画する
2018-11-27
python
%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86
opencv
Date
▶︎
2022 年 (41)
▶︎
2021 年 (40)
▶︎
2020 年 (30)
▶︎
2019 年 (90)
▶︎
2018 年 (89)
▶︎
2017 年 (1)
Tags
javascript(98)
linux(48)
amazon%20aws(47)
node.js(38)
%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0(36)
%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86(30)
html5(29)
typescript(28)
php(24)
centos(24)
python(22)
%E7%AB%B6%E6%8A%80%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0(21)
mac(20)
mysql(19)
canvas(18)
opencv(17)
%E9%9B%91%E8%AB%87(16)
wordpress(15)
atcoder(14)
docker(14)
apache(12)
%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92(12)
%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9(12)
amazon%20s3(12)
red%20hat(12)
ubuntu(11)
github(10)
git(10)
vue.js(10)
%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86100%E6%9C%AC%E3%83%8E%E3%83%83%E3%82%AF(10)
mariadb(10)
aws%20cdk(9)
css3(8)
%E5%8F%AF%E8%A6%96%E5%8C%96(8)
%E5%B0%8F%E3%83%8D%E3%82%BF(8)
amazon%20lightsail(7)
react(7)
%E3%83%96%E3%83%AD%E3%82%B0(6)
cms(6)
oracle(6)
perl(6)
gitlab(6)
next.js(6)
iam(5)
amazon%20ec2(5)
%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93(5)
aws%20amplify(5)
curl(4)
webassembly(4)
ssh(4)
Author
s-yoshiki
s-yoshiki
githubzennqiita
ただの備忘録です。
JavaScript/TypeScript/node.js/React/AWS/OpenCV
※このブログの内容は個人の見解であり、所属する組織等の見解ではありません。