Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8896

NestでTypeORM環境を構築してサンプル実装してみる

$
0
0

背景

前回は純粋なTypeORM環境をCLIで構築してみましたが、TypeORMはNestというフレームワークのORMとして利用されているとのことを知ったので、今度はNestでTypeORM環境を構築してみようと思う。
https://qiita.com/yusuke-ka/items/195e6bba4f21a659b424

Nest環境の構築

前回同様、DBは以前インストールしたpostgresql(windows)を利用する。
https://qiita.com/yusuke-ka/items/448843020c0406363ba5#%E6%BA%96%E5%82%99

pgadmin4でデータベースインスタンスだけ作っておく。

image.png

データベース名("nest_typeorm"とした)を入力して作成。

ここからは、コード エディタ(VS Code)上での作業。

諸事情により、まずは作業用のnode環境を作る。

> mkdir work
> cd work

nestのインストールは通常は下記のコマンドで実施する。
(linux環境の場合は下記でやってしまってOK.)

yarn global add @nestjs/cli

本当は↑でインストールしたいところだけど、windowsだとそのままだと使えずパスを通してやる必要があり面倒なので、↓でインストール。

yarn add @nestjs/cli

続いて、nestで新しいプロジェクトを作る。

以下のようにすれば、今いるフォルダを直接プロジェクトのフォルダにできるけど、すでにpackage.jsonが存在していて怒られるので(globalインストールしていればpackage.jsonがないので実行できる)、今いるフォルダは作業用として、下にプロジェクトを作る。

> npx nest new .

↓今回はこっちで実行。

> npx nest new nest

npmかyarnかを聞かれるので、今回はyarnを選択。

yarnでnestコマンドが使えるように、作成されたnestプロジェクト以下のpackage.jsonにscriptを追加しておく。
(npxで実行するのであれば下記の修正は不要だけど、なんとなくyarnでやりたい。)

package.json
"scripts":{"nest":"nest",...},

typeORM関連の依存をインストールしておく。

> yarn add @nestjs/typeorm typeorm pg

最後に設定ファイル(app.module.ts)を更新。

app.module.ts
import{Module}from'@nestjs/common';import{TypeOrmModule}from'@nestjs/typeorm';@Module({imports:[TypeOrmModule.forRoot({type:'postgres',host:'localhost',port:5432,username:'postgres',password:'postgres',database:'nest_typeorm',entities:[],synchronize:true,}),],controllers:[],providers:[],})exportclassAppModule{}

デフォルトで、AppControllerやAppServiceなどがimportされているが、これらは最初から入っているサンプルコードなので消してもよい。

今回は使わないので消しておいた。

ついでにsrc以下にある下記のファイルもいらないので削除。
app.controller.ts
app.controller.spec.ts
app.service.ts

これでNest環境のベースは整った。

Nestでサンプル実装してみる

最初にCLIのジェネレータでコードのひな型を作っておく。

> yarn nest g service TestObject
> yarn nest g controller TestObject
> yarn nest g module TestObject

test-objectフォルダが作成され、その下に各ひな形が配置される。

さらに以下のコマンドでモデルのひな形も作成。
(こちらは、明示的にフォルダを指定しないと、「test-object」フォルダに入らなかったので、「test-object/TestObject」のように指定。)

> yarn nest g class test-object/TestObject

test-objectフォルダ以下は下のようになる。

 |- src
   |- test-object
     |- test-object.ts
     |- test-object.controller.ts
     |- test-object.controller.spec.ts
     |- test-object.module.ts
     |- test-object.service.ts
     |- test-object.service.spec.ts
     |- test-object.spec.ts

~.spec.tsが一緒に生成されるがテスト用のコードみたいなので、今回は触れない(今度試してみようと思う)。

また、ジェネレートコマンドを実行すると、app.module.tsが自動的に更新されてしまう。
生成したcontrollerやserviceが自動でimportされるみたい。

今回はモジュール化するためのファイルも作っていて、直接app.module.tsにはimportしなくてよいはずなので、以下のように修正しておく。

app.module.ts
import{Module}from'@nestjs/common';import{TypeOrmModule}from'@nestjs/typeorm';import{TestObjectModule}from'./test-object/test-object.module';import{TestObject}from'./test-object/test-object';@Module({imports:[TypeOrmModule.forRoot({type:'postgres',host:'localhost',port:5432,username:'postgres',password:'postgres',database:'nest_typeorm',entities:[TestObject],synchronize:true,}),TestObjectModule,],controllers:[],providers:[],})exportclassAppModule{}

controllerやserviceは直接ここには書かずに、moduleだけを指定する感じ。
ただ、TypeOrmModuleのentitiesには、モデルオブジェクトを直接書いておかないとコンパイル時にエラーになったので注意。

ここからは中身を実装していく。

とその前に、各ファイルの役割を確認しておく。
サンプルのコードとかを見る限り、なんとなくこんな(↓)感じのイメージかな。

test-object.ts : モデルを定義するファイル
test-object.service.ts : TypeORMの機能を直接使ってDBを操作するファイル
test-object.controller.ts : APIを定義するファイル。serviceの提供するメソッドを呼び出す。
test-object.module.ts : 定義したserviceとかcontrollerとかを一つのモジュールにして提供するファイル。

ということで、まずはモデルファイルを実装。

test-object.ts
import{Entity,PrimaryGeneratedColumn,Column}from'typeorm';@Entity()exportclassTestObject{@PrimaryGeneratedColumn()id:number;@Column()attr1:string;}

シンプルに属性はidとattr1だけ。

続いてサービスの実装。

test-object.service.ts
import{Injectable}from'@nestjs/common';import{InjectRepository}from'@nestjs/typeorm';import{Repository}from'typeorm';import{TestObject}from'./test-object';@Injectable()exportclassTestObjectService{constructor(@InjectRepository(TestObject)privatereadonlyrepository:Repository<TestObject>,){}asyncall():Promise<TestObject[]>{returnthis.repository.find();}asyncone(id:number):Promise<TestObject>{returnthis.repository.findOne(id);}asynccreate(data:Partial<TestObject>):Promise<TestObject>{returnthis.repository.save(data);}asyncupdate(id:number,data:Partial<TestObject>):Promise<void>{constorigin=awaitthis.repository.findOne(id);constupdateData=Object.assign(origin,data);// 上書きthis.repository.save(updateData);}asyncremove(id:number):Promise<void>{constobj=awaitthis.repository.findOne(id);this.repository.remove(obj);}}

こちらもシンプルなCRUDだけを実装してみました。
(read系は全件取得と単独指定で取得の2つ)

次は、このサービスを呼び出すコントローラの実装。

test-object.controller.ts
import{Controller,Get,Post,Param,Body,Delete,HttpCode,HttpStatus,Put,}from'@nestjs/common';import{TestObjectService}from'./test-object.service';import{CreateTestDataDTO,UpdateTestDataDTO}from'./test-object.dto';import{TestObject}from'./test-object';@Controller('test-object')exportclassTestObjectController{constructor(privatereadonlyservice:TestObjectService){}@Get()@HttpCode(HttpStatus.OK)all():Promise<TestObject[]>{returnthis.service.all();}@Get(':id')@HttpCode(HttpStatus.OK)one(@Param('id')id:number):Promise<TestObject>{returnthis.service.one(id);}@Post('create')@HttpCode(HttpStatus.CREATED)asynccreate(@Body()createTestDataDto:CreateTestDataDTO,):Promise<TestObject>{returnthis.service.create(createTestDataDto);}@Put('update/:id')@HttpCode(HttpStatus.NO_CONTENT)asyncupdate(@Param('id')id:number,@Body()updateTestDataDto:UpdateTestDataDTO,):Promise<void>{this.service.update(id,updateTestDataDto);}@Delete(':id')@HttpCode(HttpStatus.NO_CONTENT)asyncremove(@Param('id')id:number):Promise<void>{this.service.remove(id);}}

こちらもCRUD操作のAPIを定義。HTTPリクエストをここで処理している感じですね。

更新系の操作は引数にData Transfer Object(DTO)を渡している、これは、src/test-objectの下にtest-object.dto.tsとして別途定義した。

test-object.dto.ts
exportclassCreateTestDataDTO{attr1:string;}exportclassUpdateTestDataDTO{attr1:string;}

最後に、serviceやcontrollerをモジュール化するファイルの実装。

test-object.module.ts
import{Module}from'@nestjs/common';import{TypeOrmModule}from'@nestjs/typeorm';import{TestObjectService}from'./test-object.service';import{TestObjectController}from'./test-object.controller';import{TestObject}from'./test-object';@Module({imports:[TypeOrmModule.forFeature([TestObject])],exports:[TypeOrmModule],providers:[TestObjectService],controllers:[TestObjectController],})exportclassTestObjectModule{}

このモジュールを大元のapp.module.tsでimportする感じになっている。

実行

起動して確認してみる。

> yarn start:dev

確認はいつもの「Advanced REST client」。
http://localhost:3000/test-objectに各種リクエストを送ってみる。

説明は省略(全部問題なく動きました。)。

作成

image.png

全件取得

image.png

更新

image.png

1件取得

image.png

削除

image.png

さいごに

今回はNestでTypeORM環境を構築してサンプル実装してみた。

前回、素のTypeORM環境をCLIで作成したときよりは時間がかかったけど、構造がなんとなく理解できたら、すんなりとコードを書くことができた。

そこそこの規模のコードを書くなら、こういったフレームワークを利用して書いた方が、コードを整理できて良さそうですね。テストのフレームワークも付いてるみたいだし。


Viewing all articles
Browse latest Browse all 8896

Trending Articles