jpskill.com
🛠️ 開発・MCP コミュニティ

nestjs

NestJSは、Angularに影響を受けた構造で、Node.js上で拡張性の高いサーバーサイドアプリケーションを構築するための、TypeScriptで記述された先進的なフレームワークであり、効率的な開発を支援するSkill。

📜 元の英語説明(参考)

NestJS is a progressive TypeScript framework for building scalable server-side applications on Node.js. It uses decorators, modules, dependency injection, and an opinionated architecture inspired by Angular.

🇯🇵 日本人クリエイター向け解説

一言でいうと

NestJSは、Angularに影響を受けた構造で、Node.js上で拡張性の高いサーバーサイドアプリケーションを構築するための、TypeScriptで記述された先進的なフレームワークであり、効率的な開発を支援するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o nestjs.zip https://jpskill.com/download/15162.zip && unzip -o nestjs.zip && rm nestjs.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/15162.zip -OutFile "$d\nestjs.zip"; Expand-Archive "$d\nestjs.zip" -DestinationPath $d -Force; ri "$d\nestjs.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して nestjs.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → nestjs フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

NestJS

NestJS は、依存性注入を備えたモジュールアーキテクチャ、ルーティングとバリデーションのためのデコレータ、認証のためのガード、および横断的な関心事のためのインターセプターを提供します。

インストール

# 新しい NestJS プロジェクトを作成
npm i -g @nestjs/cli
nest new my-api
cd my-api
npm i @nestjs/typeorm typeorm pg class-validator class-transformer

プロジェクト構造

# 標準的な NestJS プロジェクトのレイアウト
src/
├── main.ts                  # Bootstrap
├── app.module.ts            # ルートモジュール
├── articles/
│   ├── articles.module.ts   # 機能モジュール
│   ├── articles.controller.ts
│   ├── articles.service.ts
│   ├── entities/article.entity.ts
│   └── dto/
│       ├── create-article.dto.ts
│       └── update-article.dto.ts
├── auth/
│   ├── auth.module.ts
│   ├── auth.guard.ts
│   └── auth.service.ts
└── common/
    ├── filters/
    └── interceptors/

モジュール

// src/articles/articles.module.ts — 機能モジュール
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ArticlesController } from './articles.controller';
import { ArticlesService } from './articles.service';
import { Article } from './entities/article.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Article])],
  controllers: [ArticlesController],
  providers: [ArticlesService],
  exports: [ArticlesService],
})
export class ArticlesModule {}

エンティティ

// src/articles/entities/article.entity.ts — TypeORM エンティティ
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, ManyToOne } from 'typeorm';
import { User } from '../../users/entities/user.entity';

@Entity()
export class Article {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 200 })
  title: string;

  @Column('text')
  body: string;

  @ManyToOne(() => User, (user) => user.articles)
  author: User;

  @CreateDateColumn()
  createdAt: Date;
}

バリデーション付き DTO

// src/articles/dto/create-article.dto.ts — バリデーションされた DTO
import { IsString, IsNotEmpty, MaxLength } from 'class-validator';

export class CreateArticleDto {
  @IsString()
  @IsNotEmpty()
  @MaxLength(200)
  title: string;

  @IsString()
  @IsNotEmpty()
  body: string;
}

コントローラ

// src/articles/articles.controller.ts — REST コントローラ
import {
  Controller, Get, Post, Body, Param, Delete,
  ParseIntPipe, UseGuards, Query, HttpCode, HttpStatus,
} from '@nestjs/common';
import { ArticlesService } from './articles.service';
import { CreateArticleDto } from './dto/create-article.dto';
import { AuthGuard } from '../auth/auth.guard';

@Controller('articles')
export class ArticlesController {
  constructor(private readonly articlesService: ArticlesService) {}

  @Get()
  findAll(@Query('page') page = 1, @Query('limit') limit = 20) {
    return this.articlesService.findAll(+page, +limit);
  }

  @Get(':id')
  findOne(@Param('id', ParseIntPipe) id: number) {
    return this.articlesService.findOne(id);
  }

  @Post()
  @UseGuards(AuthGuard)
  @HttpCode(HttpStatus.CREATED)
  create(@Body() dto: CreateArticleDto) {
    return this.articlesService.create(dto);
  }

  @Delete(':id')
  @UseGuards(AuthGuard)
  @HttpCode(HttpStatus.NO_CONTENT)
  remove(@Param('id', ParseIntPipe) id: number) {
    return this.articlesService.remove(id);
  }
}

サービス

// src/articles/articles.service.ts — DI を使用したビジネスロジック
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Article } from './entities/article.entity';
import { CreateArticleDto } from './dto/create-article.dto';

@Injectable()
export class ArticlesService {
  constructor(
    @InjectRepository(Article)
    private readonly repo: Repository<Article>,
  ) {}

  async findAll(page: number, limit: number) {
    return this.repo.find({
      skip: (page - 1) * limit,
      take: limit,
      order: { createdAt: 'DESC' },
      relations: ['author'],
    });
  }

  async findOne(id: number) {
    const article = await this.repo.findOne({ where: { id }, relations: ['author'] });
    if (!article) throw new NotFoundException(`Article #${id} not found`);
    return article;
  }

  async create(dto: CreateArticleDto) {
    const article = this.repo.create(dto);
    return this.repo.save(article);
  }

  async remove(id: number) {
    const result = await this.repo.delete(id);
    if (result.affected === 0) throw new NotFoundException();
  }
}

ガード

// src/auth/auth.guard.ts — JWT 認証ガード
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<Request>();
    const token = request.headers.authorization?.replace('Bearer ', '');
    if (!token) throw new UnauthorizedException();
    try {
      request['user'] = await this.jwtService.verifyAsync(token);
      return true;
    } catch {
      throw new UnauthorizedException();
    }
  }
}

アプリモジュールとブートストラップ

// src/app.module.ts — TypeORM 設定を持つルートモジュール
import { Module, ValidationPipe } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ArticlesModule } from './articles/articles.module';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DB_HOST ?? 'localhost',
      port: 5432,
      database: process.env.DB_NAME ?? 'mydb',
      username: process.env.DB_USER ?? 'postgres',
      password: process.env.DB_PASSWORD ?? '',
      autoLoadEntities: true,
      synchronize: process.env.NODE_ENV !== 'production',
    }),
    ArticlesModule,
  ],
})
export class AppMo
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

NestJS

NestJS provides a modular architecture with dependency injection, decorators for routing and validation, guards for auth, and interceptors for cross-cutting concerns.

Installation

# Create new NestJS project
npm i -g @nestjs/cli
nest new my-api
cd my-api
npm i @nestjs/typeorm typeorm pg class-validator class-transformer

Project Structure

# Standard NestJS project layout
src/
├── main.ts                  # Bootstrap
├── app.module.ts            # Root module
├── articles/
│   ├── articles.module.ts   # Feature module
│   ├── articles.controller.ts
│   ├── articles.service.ts
│   ├── entities/article.entity.ts
│   └── dto/
│       ├── create-article.dto.ts
│       └── update-article.dto.ts
├── auth/
│   ├── auth.module.ts
│   ├── auth.guard.ts
│   └── auth.service.ts
└── common/
    ├── filters/
    └── interceptors/

Module

// src/articles/articles.module.ts — feature module
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ArticlesController } from './articles.controller';
import { ArticlesService } from './articles.service';
import { Article } from './entities/article.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Article])],
  controllers: [ArticlesController],
  providers: [ArticlesService],
  exports: [ArticlesService],
})
export class ArticlesModule {}

Entity

// src/articles/entities/article.entity.ts — TypeORM entity
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, ManyToOne } from 'typeorm';
import { User } from '../../users/entities/user.entity';

@Entity()
export class Article {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 200 })
  title: string;

  @Column('text')
  body: string;

  @ManyToOne(() => User, (user) => user.articles)
  author: User;

  @CreateDateColumn()
  createdAt: Date;
}

DTOs with Validation

// src/articles/dto/create-article.dto.ts — validated DTO
import { IsString, IsNotEmpty, MaxLength } from 'class-validator';

export class CreateArticleDto {
  @IsString()
  @IsNotEmpty()
  @MaxLength(200)
  title: string;

  @IsString()
  @IsNotEmpty()
  body: string;
}

Controller

// src/articles/articles.controller.ts — REST controller
import {
  Controller, Get, Post, Body, Param, Delete,
  ParseIntPipe, UseGuards, Query, HttpCode, HttpStatus,
} from '@nestjs/common';
import { ArticlesService } from './articles.service';
import { CreateArticleDto } from './dto/create-article.dto';
import { AuthGuard } from '../auth/auth.guard';

@Controller('articles')
export class ArticlesController {
  constructor(private readonly articlesService: ArticlesService) {}

  @Get()
  findAll(@Query('page') page = 1, @Query('limit') limit = 20) {
    return this.articlesService.findAll(+page, +limit);
  }

  @Get(':id')
  findOne(@Param('id', ParseIntPipe) id: number) {
    return this.articlesService.findOne(id);
  }

  @Post()
  @UseGuards(AuthGuard)
  @HttpCode(HttpStatus.CREATED)
  create(@Body() dto: CreateArticleDto) {
    return this.articlesService.create(dto);
  }

  @Delete(':id')
  @UseGuards(AuthGuard)
  @HttpCode(HttpStatus.NO_CONTENT)
  remove(@Param('id', ParseIntPipe) id: number) {
    return this.articlesService.remove(id);
  }
}

Service

// src/articles/articles.service.ts — business logic with DI
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Article } from './entities/article.entity';
import { CreateArticleDto } from './dto/create-article.dto';

@Injectable()
export class ArticlesService {
  constructor(
    @InjectRepository(Article)
    private readonly repo: Repository<Article>,
  ) {}

  async findAll(page: number, limit: number) {
    return this.repo.find({
      skip: (page - 1) * limit,
      take: limit,
      order: { createdAt: 'DESC' },
      relations: ['author'],
    });
  }

  async findOne(id: number) {
    const article = await this.repo.findOne({ where: { id }, relations: ['author'] });
    if (!article) throw new NotFoundException(`Article #${id} not found`);
    return article;
  }

  async create(dto: CreateArticleDto) {
    const article = this.repo.create(dto);
    return this.repo.save(article);
  }

  async remove(id: number) {
    const result = await this.repo.delete(id);
    if (result.affected === 0) throw new NotFoundException();
  }
}

Guards

// src/auth/auth.guard.ts — JWT auth guard
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<Request>();
    const token = request.headers.authorization?.replace('Bearer ', '');
    if (!token) throw new UnauthorizedException();
    try {
      request['user'] = await this.jwtService.verifyAsync(token);
      return true;
    } catch {
      throw new UnauthorizedException();
    }
  }
}

App Module and Bootstrap

// src/app.module.ts — root module with TypeORM config
import { Module, ValidationPipe } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ArticlesModule } from './articles/articles.module';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DB_HOST ?? 'localhost',
      port: 5432,
      database: process.env.DB_NAME ?? 'mydb',
      username: process.env.DB_USER ?? 'postgres',
      password: process.env.DB_PASSWORD ?? '',
      autoLoadEntities: true,
      synchronize: process.env.NODE_ENV !== 'production',
    }),
    ArticlesModule,
  ],
})
export class AppModule {}
// src/main.ts — bootstrap with global pipes
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
  app.enableCors();
  await app.listen(3000);
}
bootstrap();

Testing

// src/articles/articles.service.spec.ts — unit test
import { Test } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { ArticlesService } from './articles.service';
import { Article } from './entities/article.entity';

describe('ArticlesService', () => {
  let service: ArticlesService;
  const mockRepo = { find: jest.fn().mockResolvedValue([]), create: jest.fn(), save: jest.fn() };

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        ArticlesService,
        { provide: getRepositoryToken(Article), useValue: mockRepo },
      ],
    }).compile();
    service = module.get(ArticlesService);
  });

  it('returns articles', async () => {
    expect(await service.findAll(1, 20)).toEqual([]);
  });
});

Key Patterns

  • One module per feature; import only what you need
  • Use ValidationPipe with whitelist: true to strip unknown properties
  • Use guards for auth, interceptors for response mapping, filters for exceptions
  • Set synchronize: false in production — use TypeORM migrations instead
  • Use @nestjs/config with ConfigModule.forRoot() for environment variables