Nestjsをローカルで動かしてみる

まずはやってみるところから。

プロジェクト作成

やってみた系なので、とりあえずnpxでさっとやる。

$ npx @nestjs/cli new my-nestjs-app
⚡  We will scaffold your app in a few seconds..

CREATE /my-nestjs-app/README.md (3370 bytes)
CREATE /my-nestjs-app/nest-cli.json (64 bytes)
CREATE /my-nestjs-app/package.json (1697 bytes)
CREATE /my-nestjs-app/tsconfig.build.json (97 bytes)
CREATE /my-nestjs-app/tsconfig.json (336 bytes)
CREATE /my-nestjs-app/tslint.json (426 bytes)
CREATE /my-nestjs-app/src/app.controller.spec.ts (617 bytes)
CREATE /my-nestjs-app/src/app.controller.ts (274 bytes)
CREATE /my-nestjs-app/src/app.module.ts (249 bytes)
CREATE /my-nestjs-app/src/app.service.ts (142 bytes)
CREATE /my-nestjs-app/src/main.ts (208 bytes)
CREATE /my-nestjs-app/test/app.e2e-spec.ts (630 bytes)
CREATE /my-nestjs-app/test/jest-e2e.json (183 bytes)

npmかyarnかどっちつかうか聞かれます。

? Which package manager would you ❤️  to use? (Use arrow keys)
❯ npm 
  yarn 

このコマンドが案内されたら準備OK

$ cd my-nestjs-app
$ yarn run start

Nestjs APIをローカルで動かす

デフォルトだとlocalhost:3000を使用します。

$ curl https://localhost:3000/
Hello World!

Port3000が使用中だとエラーが出ます。

events.js:174
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE: address already in use :::3000

後半で紹介しますが、NestjsもExpressなどと同じくコード内でポートを指定する仕組みな様子です。

なのでCreate React Appあたりのport3000を使用してくるアプリと並行して作業する場合は環境変数などを使って外からポートを変えれるようにするとよいかもしれません。

開発中はyarn run start:dev

yarn startはコードの変更をwatchしません。

$ cat package.json | jq .scripts | grep start
  "start": "nest start",
  "start:dev": "nest start --watch",
  "start:debug": "nest start --debug --watch",
  "start:prod": "node dist/main",

dev, debug, prodの3種類がありますので、使い分けましょう。

ちょっとだけNestjsのソースを触ってみる

作るだけだとつまらないので、ちょっとだけいろいろ触ってみます。

APIのportを変更する

APIのportはsrc/main.tsに定義されています。

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

変更したい場合は、ここのapp.listenの数字を変えましょう。

環境変数でポートを変える

環境変数を使ってportを上書きできるようにしておくと便利そうです。

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const port = Number(process.env.PORT) || 3000
  await app.listen(port);
}
bootstrap();

起動時は$ export PORT=3001; yarn startのようにしましょう。

APIを追加する

とりあえずAPIを2つほど追加してみましょう。

エンドポイント追加だけを試すため、今回は敢えてcontrollerにレスポンスを直書きしてます。

実践時はちゃんとserviceクラスを作りましょう。

シンプルなGET APIエンドポイント

まずはパラメータのないシンプルなGETを作ります。

import { Controller, Get, Param } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }

  // ここから追加コード
  @Get('my-custom')
  myCustomAPI(): {message: string} {
    return {
      message: 'Hello!'
    }
  }
  // ここまで追加コード
}

簡単ですね。保存するとmy-customというパスを使えるようになります。

$ curl https://localhost:3000/my-custom | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    20  100    20    0     0   2869      0 --:--:-- --:--:-- --:--:--  3333
{
  "message": "Hello!"
}

// 適当に叩くと404
$ curl https://localhost:3000/my-custom-2 | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    74  100    74    0     0   7718      0 --:--:-- --:--:-- --:--:--  8222
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Cannot GET /my-custom-2"
}

パスパラメーターやクエリストリングをつける

パスパラメータやクエリストリングなども設定できます。

import { Controller, Get, Param, Query } from '@nestjs/common';

@Controller()
export class AppController {
  @Get('my-custom/:name')
  myCustomAPIWithPath(@Param('name') name: string, @Query() query: {
    s: string;
    d: number
  }): {
    message: string;
    name: string;
    query: {
      s: string;
      d: number
    }
  } {
    return {
      message: `Hello. ${name}-san!`,
      name,
      query
    }
  }
}

この場合、my-custom/:nameという形でnameを変数に、クエリストリングでsdを想定しているGET APIができあがります。

$ curl "https://localhost:3000/my-custom/john?s=hi&d=1&h=true" | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    82  100    82    0     0   2975      0 --:--:-- --:--:-- --:--:--  3037
{
  "message": "Hello. john-san!",
  "name": "john",
  "query": {
    "s": "hi",
    "d": "1",
    "h": "true"
  }
}

ただし上のサンプルのようにdがstring型で来ていたりhという未定義の値も受け付ける挙動となります。

APIに投げられた値を検証するわけではなく、「この型で来るはずなので、処理してください」という意味合いになることを注意する必要があります。Nest.jsに限った話ではありませんが。

おわりに

デコレーターベースでAPIの定義をもろもろ設定できますので、直感的に触れる印象はあります。

ただしデコレーターというか@を使う書き方に慣れていないとちょっと戸惑うかもしれません。

Express.js未経験でいきなりNest.js触るという一足飛ばしなことをしていますが、個人的にはNest.jsベースでやるのが手軽そうかなとは思いました。

尤も、実案件でいろいろ依存関係が出てきたときに地雷を踏みやすいかどうかはやってみてのお楽しみですが・・・

Comment