2
Help us understand the problem. What are the problem?

posted at

updated at

NestJS のチュートリアル、nest new ~ 基本的なCRUD の作成まで

プロジェクトの作成

NestJS CLI の導入

先ず、NestJS CLI をインストールします。

npm i -g @nestjs/cli

nest new の実行

次に、nest new コマンドを使い、プロジェクトを作成します。
今回は、tutorial-app というプロジェクト名を指定しています。

nest new tutorial-app

実行すると、使用するパッケージマネージャーを聞かれます。
今回は、npm を選択します。
Untitled.png

CRUD の実装

nest g コマンド の実行

nest g コマンドを実行し、BooksModule、BooksController、BooksService を作成します。

nest g module books
nest g controller books --no-spec
nest g service books --no-spec

Controller とService は、オプションをつけずに実行すると、 books.controller.spec.ts のようなテストファイルが自動で作成されます。

今回はテストは行わないので、--no-spec オプションをつけて、テストファイルなしで、Controller とService を作成します。
Untitled (1).png

依存性の注入

BooksService で定義したメソッドをBooksController で呼び出せるように、依存性の注入を行います。

src/books/books.controller.ts
import { Controller, Get } from '@nestjs/common';
import { BooksService } from './books.service';

@Controller('books')
export class BooksController {
  constructor(private readonly booksService: BooksService) {} // booksService をインスタンス化する
}

Book Model の作成

Book の型を定義したModel を定義します。

src/books/book.model.ts
import { BookStatus } from './book-status.enum';

export interface Book {
  id: string;
  name: string;
  status: BookStatus;
}

本の貸し出し状況をstatus で管理するため、enum として、別ファイルに切り出す。

src/books/book-status.enum.ts
export enum BookStatus {
  RENTABLE = 'RENTABLE',
  LENT_OUT = 'LENT_OUT',
}

TypeORM の導入時にModel とTable の紐付けを定義するBookEntity というものを作成します。
その時にBook Model は不要になるので、全てBookEntity に置き換えることになります。

Create 機能の実装

先ず、 値を保存するためのcreate メソッドをBooksServiceに用意します。

src/books/books.service.ts
import { Injectable } from '@nestjs/common';
import { Book } from './book.model';

@Injectable()
export class BooksService {
  private books: Book[] = [];

  create(book: Book) {
    this.books.push(book);
    return book;
  }
}

保存する値は、Post リクエストのBody からBooksController を介してBooksService に渡します。

BooksController にPost リクエストに対して、BooksService のcreate メソッドを呼び出す処理を書いていきます。

src/books/books.controller.ts
import { Body, Controller, Get, Post } from '@nestjs/common';
import { BookStatus } from './book-status.enum';
import { Book } from './book.model';
import { BooksService } from './books.service';

@Controller('books')
export class BooksController {
  constructor(private readonly booksService: BooksService) {}

  @Post()
  create(@Body('id') id: string, @Body('name') name: string): Book {
    const book: Book = {
      id,
      name,
      status: BookStatus.RENTABLE,
    };

    return this.booksService.create(book);
  }
}

動作確認として、Postman を使います
http://localhost:3000/books にBody に保存するプロパティの値を渡し、POST でリクエストを送ります。

保存が成功していいるとリクエストに対してbook 変数の値が返ってきます。

Untitled (2).png

Read 機能の実装

保存したBook の値を確認するため、BooksService にBook の内容を取得するためのロジックを記述します。

全件取得機能

保存したBook の値を全て取得するfindAll メソッドをBooksService に記述していきます。

src/books/books.service.ts
import { Injectable } from '@nestjs/common';
import { Book } from './book.model';

@Injectable()
export class BooksService {
  private books: Book[] = [];
  findAll() {
    return this.books;
  }

  create(book: Book) {
    this.books.push(book);
    return book;
  }
}

BooksController にGet リクエストに対し、BooksService のfindAll メソッドを呼び出す処理を追記します。

src/books/books.controller.ts
import { Body, Controller, Get, Post } from '@nestjs/common';
import { BookStatus } from './book-status.enum';
import { Book } from './book.model';
import { BooksService } from './books.service';

@Controller('books')
export class BooksController {
  constructor(private readonly booksService: BooksService) {}
  @Get()
  findAll() {
    return this.booksService.findAll();
  }

  @Post()
  create(@Body('id') id: string, @Body('name') name: string): Book {
    const book: Book = {
      id,
      name,
      status: BookStatus.RENTABLE,
    };

    return this.booksService.create(book);
  }
}

http://localhost:3000/books にGET でリクエストを送り、Books の配列の値が返ってくれば成功です。

配列には、Post で保存したBook の値が入っています。
Untitled.png

ID を指定した取得

全件取得機能が作れたら、次に指定したID を持ったBook を取り出すfindById メソッドをBooksService に記述します。

src/books/books.service.ts
import { Injectable } from '@nestjs/common';
import { Book } from './book.model';

@Injectable()
export class BooksService {
  private books: Book[] = [];
  findAll() {
    return this.books;
  }

  findById(id: string): Book {
    return this.books.find((book) => book.id === id);
  }

  create(book: Book) {
    this.books.push(book);
    return book;
  }
}

取得したいID は、books/1 のようにURL に記述して渡します。
BooksController にGet リクエストに対し、BooksService のfindById メソッドを呼び出す処理を追記します。

src/books/books.controller.ts
import { Body, Controller, Get, Post } from '@nestjs/common';
import { BookStatus } from './book-status.enum';
import { Book } from './book.model';
import { BooksService } from './books.service';

@Controller('books')
export class BooksController {
  constructor(private readonly booksService: BooksService) {}
  @Get()
  findAll() {
    return this.booksService.findAll();
  }

  @Get(':id')
  findById(@Param('id') id: string): Book {
    return this.booksService.findById(id);
  }

  @Post()
  create(@Body('id') id: string, @Body('name') name: string): Book {
    const book: Book = {
      id,
      name,
      status: BookStatus.RENTABLE,
    };

    return this.booksService.create(book);
  }
}

http://localhost:3000/books/:id にGET でリクエストを送り、指定したid のBook の値が返ってくれば成功です。

Untitled.png

Update 機能の実装

指定したID を持ったBook のstatus を更新するupdateStatus メソッドをBooksService に記述します。

リクエストで渡したID と一致するBook はfindById を使って取得します。

src/books/books.service.ts
import { Injectable } from '@nestjs/common';
import { Book } from './book.model';

@Injectable()
export class BooksService {
  private books: Book[] = [];
  findAll() {
    return this.books;
  }

  findById(id: string): Book {
    return this.books.find((book) => book.id === id);
  }

  create(book: Book) {
    this.books.push(book);
    return book;
  }

  updateStatus(id: string): Book {
    const book = this.findById(id);
    book.status = BookStatus.LENT_OUT;
    return book;
  }
}

BooksController にPATCH リクエストに対し、BooksService のfindById メソッドを呼び出す処理を追記します。

src/books/books.controller.ts
import { Body, Controller, Get, Post } from '@nestjs/common';
import { BookStatus } from './book-status.enum';
import { Book } from './book.model';
import { BooksService } from './books.service';

@Controller('books')
export class BooksController {
  constructor(private readonly booksService: BooksService) {}
  @Get()
  findAll() {
    return this.booksService.findAll();
  }

  @Get(':id')
  findById(@Param('id') id: string): Book {
    return this.booksService.findById(id);
  }

  @Post()
  create(@Body('id') id: string, @Body('name') name: string): Book {
    const book: Book = {
      id,
      name,
      status: BookStatus.RENTABLE,
    };

    return this.booksService.create(book);
  }

	@Patch(':id')
    updateStatus(@Param('id') id: string): Item {
     return this.itemsService.updateStatus(id);
  }
}

http://localhost:3000/books/:id にPATCH でリクエストを送り、指定したid のBook status の値がRENTABLE からLENT_OUT に更新されていれば成功です。

Untitled.png

Delete 機能の実装

BooksService に リクエストで指定したid の値と一致した、id を持つBook を削除するdelete メソッドを用意します。

src/books/books.service.ts
import { Injectable } from '@nestjs/common';
import { Book } from './book.model';
import { BookStatus } from './book-status.enum';

@Injectable()
export class BooksService {
  private books: Book[] = [];
  findAll() {
    return this.books;
  }

  findById(id: string): Book {
    return this.books.find((book) => book.id === id);
  }

  create(book: Book) {
    this.books.push(book);
    return book;
  }

  updateStatus(id: string): Book {
    const book = this.findById(id);
    book.status = BookStatus.LENT_OUT;
    return book;
  }

  delete(id: string): void {
    this.books = this.books.filter((book) => book.id !== id);
  }
}

BooksController にDELETE リクエストに対し、BooksService のdelete メソッドを呼び出す処理を追記します。

src/books/books.controller.ts
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common';
import { BookStatus } from './book-status.enum';
import { Book } from './book.model';
import { BooksService } from './books.service';

@Controller('books')
export class BooksController {
  constructor(private readonly booksService: BooksService) {}
  @Get()
  findAll() {
    return this.booksService.findAll();
  }

  @Post()
  create(@Body('id') id: string, @Body('name') name: string): Book {
    const book: Book = {
      id,
      name,
      status: BookStatus.RENTABLE,
    };

    return this.booksService.create(book);
  }

  @Delete()
  delete(@Param('id') id: string): void {
    this.booksService.delete(id);
  }
}

http://localhost:3000/books/:id にDELETE でリクエストを送った後、http://localhost:3000/books にGET でリクエストを送ります。

指定したid のBook が削除されていれば成功です。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
2
Help us understand the problem. What are the problem?