iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 4
1

Nest.js framework 30天初探系列 第 4

Nestjs framework 30天初探:Day04 Modules

Modules

https://ithelp.ithome.com.tw/upload/images/20171207/20107195Uj31hIrver.png

Module是帶有@Module()裝飾器的class,@Module()裝飾器提供metadata,Nestjs用其來構建整個程式架構,使用Nestjs可以將專案的架構寫成Module Tree(模組樹),架構會更顯分明清楚,在後面的示範,會看到專案架構最終變成模組樹的架構。

  1. @Module()裝飾器需要傳入一個物件,物件有以下幾個屬性,用來描述這個Module。
    https://ithelp.ithome.com.tw/upload/images/20171207/20107195n6u5LHrrUF.png

默認情況下,Module會封裝好Component和Controller的依賴關係,故Module無法直接去使用另一個Module底下的Component和Controller,必須import該Module,才能使用其底下的Component和Controller,在後續示範會演示給大家看。

  1. 開始打造Module Tree模組樹架構(其實之前的資料夾規劃就是朝這方向了XD),承之前的專案,我們在Users資料夾新增一個user.module.ts,並在內寫些程式。
    src/modules/Users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './Services/users.service';

@Module({
    //傳入UsersController
    controllers: [UsersController],
    //傳入UsersService
    components: [UsersService]
})
export class UsersModule { }
  1. 接著在ApplicationModule import UsersModule,程式碼如下。
    src/modules/app.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './Users/users.controller';
import { UsersService } from './Users/Services/users.service';
import { UsersModule } from './Users/users.module';

@Module({
  modules: [UsersModule]
})
export class ApplicationModule { }
  1. 最後打開Postmanhttp://localhost:3000/users 發出GET 請求。
    https://ithelp.ithome.com.tw/upload/images/20171207/20107195dPeA2XMELD.png

符合先前所看到的結果,代表UsersModule有正常的load進去。
這邊大家就已經學會了分拆Module,構建Module Tree了XDDDD

  1. 接下來,我們實驗一下是否A Module不能直接的使用B Module的Component或Controller,所以新增一個Products 資料夾並比照Users的模式產生相關程式碼(程式碼),為直接帶重點,過程不加贅述。
    src/modules/app.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './Users/users.controller';
import { UsersService } from './Users/Services/users.service';
import { UsersModule } from './Users/users.module';
import { ProductsModule } from './Products/products.module';

@Module({
  //load ProductsModule
  modules: [UsersModule, ProductsModule]
})
export class ApplicatioModule { }

-----------------經過一番敲打----------------------------

  1. 完成Products的部分,我們在UsersController注入ProductsService,並改了一下程式碼,最後寫了一段可以請求的route,要求返回Products陣列,程式碼如下。
    src/modules/Users/user.controller.ts
import { Controller, Get, Post, Request, Response, Param, Next, HttpStatus, Body } from '@nestjs/common';
import { CreateUserDTO } from './DTO/create-users.dto';
import { UsersService } from '../Users/Services/users.service';
import { ProductsService } from '../Products/Services/products.service';

@Controller()
export class UsersController {

    //依賴注入,建議要使用,這是低耦合作法
    constructor(private userService: UsersService, private productsService: ProductsService) { }

    @Get('users')
    //使用Express的參數
    async getAllUsers( @Request() req, @Response() res, @Next() next) {
        //Promise 有then catch方法可以調用
        await this.userService.getAllUsers()
            .then((users) => {
                //多種Http的Status可以使用
                res.status(HttpStatus.OK).json(users);
            })
            .catch((error) => {
                console.error(error);
                res.status(HttpStatus.INTERNAL_SERVER_ERROR);
            })
    }

    @Get('users/:id')
    //使用Express的參數
    //@Param('id')可以直接抓id參數
    async getUser( @Response() res, @Param('id') id) {
        //+id ,+符號可以直接把string 轉換成number
        await this.userService.getUser(+id)
            .then((user) => {
                res.status(HttpStatus.OK).json(user);
            })
            .catch((error) => {
                console.error(error);
                res.status(HttpStatus.INTERNAL_SERVER_ERROR);
            })
    }

    @Post('users')
    async addUser( @Response() res, @Body() createUserDTO: CreateUserDTO) {
        //使用Rx.js,所以回傳可以做更多資料流的處理
        await this.userService.addUser(createUserDTO).subscribe((users) => {
            res.status(HttpStatus.OK).json(users);
        })
    }

    @Get('testProducts')
    //使用Express的參數
    async testGetAllProducts( @Request() req, @Response() res, @Next() next) {
        //Promise 有then catch方法可以調用
        await this.productsService.getAllProducts()
            .then((products) => {
                //多種Http的Status可以使用
                res.status(HttpStatus.OK).json(products);
            })
            .catch((error) => {
                console.error(error);
                res.status(HttpStatus.INTERNAL_SERVER_ERROR);
            })
    }
}

console結果如下:

λ npm start

> nest-typescript-starter@1.0.0 start C:\30Days\正式比賽\Nestjs30Days\day04\Day04_Modules\project
> node index.js

[Nest] 11688   - 2017-12-7 15:35:25   [NestFactory] Starting Nest application...
[Nest] 11688   - 2017-12-7 15:35:25   [InstanceLoader] ApplicationModule dependencies initialized +15ms
[Nest] 11688   - 2017-12-7 15:35:25   [ExceptionHandler] Nest can't resolve dependencies of the UsersController (+, ?). Please verify whether [1] argument is available in the current context.
Error: Nest can't resolve dependencies of the UsersController (+, ?). Please verify whether [1] argument is available in the current context.
    at Injector.<anonymous> (C:\30Days\正式比賽\Nestjs30Days\day04\Day04_Modules\project\node_modules\@nestjs\core\injector\injector.js:15
6:23)
    at Generator.next (<anonymous>)
    at fulfilled (C:\30Days\正式比賽\Nestjs30Days\day04\Day04_Modules\project\node_modules\@nestjs\core\injector\injector.js:4:58)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
    at Function.Module.runMain (module.js:678:11)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3
npm ERR! code ELIFECYCLE
npm ERR! errno 3
npm ERR! nest-typescript-starter@1.0.0 start: `node index.js`
npm ERR! Exit status 3
npm ERR!
npm ERR! Failed at the nest-typescript-starter@1.0.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\user\AppData\Roaming\npm-cache\_logs\2017-12-07T07_35_25_899Z-debug.log

nestjs無法解決UserController和ProductsService的依賴關係,因為ProductsService是在ProductsModule裡。

  1. 我們來解決上述問題,首先在ApplicationModule刪除load ProductsModule那段,因為這無用。
    src/modules/app.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './Users/users.controller';
import { UsersService } from './Users/Services/users.service';
import { UsersModule } from './Users/users.module';

@Module({
  modules: [UsersModule]
})
export class ApplicationModule { }
  1. 接著改寫一下ProductsModule,程式碼如下:
    src/modules/Products/products.module.ts
import { Module } from '@nestjs/common';
import { ProductsController } from './products.controller';
import { ProductsService } from './Services/products.service';

@Module({
    //傳入ProductsController
    controllers: [ProductsController],
    //傳入ProductsService
    components: [ProductsService],
    //輸出ProductsService
    exports: [ProductsService]
})
export class ProductsModule { }

注意:不能export Controller!

  1. UsersModule 要import ProductsModule,改寫程式碼如下:
    src/modules/Users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './Services/users.service';
import {ProductsModule} from '../Products/products.module';

@Module({
    //傳入ProductModule
    modules: [ProductsModule],
    //傳入UsersController
    controllers: [UsersController],
    //傳入UsersService
    components: [UsersService]
})
export class UsersModule {}

處理一下依賴關係,將ProductModule傳入UserModule。

  1. 大功告成,打開Postmanhttp://localhost:3000/testProducts 進行GET請求,結果如下圖。
    https://ithelp.ithome.com.tw/upload/images/20171207/20107195NyZl1nsoab.png

程式碼在github


上一篇
Nestjs framework 30天初探:Day03 Components
下一篇
Nestjs framework 30天初探:Day05 Middlewares
系列文
Nest.js framework 30天初探10

尚未有邦友留言

立即登入留言