0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

最初の1行のコードからライブデプロイまで10分:超高速Nest.jsブログコース

Last updated at Posted at 2025-09-16

Cover

これは Nest.js の速習コースです。このチュートリアルでは、わずか数ステップで、10 分未満で最初のコード行からデプロイまでのブログを構築します。

これほど速い理由は、このチュートリアルではプロセスの詳細な説明には踏み込まず、代わりに完成品を構築するように直接案内するからです。フレームワークの学習は、既存のプロジェクトを自分のニーズに合わせて変更する方が速いと信じています。

このブログは、純粋な Node.js バックエンドプロジェクトで一般的なテクノロジースタックを表す 3 つの機能モジュールで構成されています。

  • Nest.js
  • データベースとして PostgreSQL
  • ページレンダリングのために ejs

早速始めましょう。

1. プロジェクトの初期化

Nest.js プロジェクトは、プロジェクト管理のために CLI ツールに大きく依存しています。まず、Nest.js CLI をインストールしましょう。

npm i -g @nestjs/cli

CLI を使用して新しいプロジェクトを作成します。

nest new personal-blog

これにより、personal-blogという名前の新しいフォルダが作成され、必要なすべての依存関係がインストールされます。お好みのエディタでこのディレクトリを開いて、正式に編集を開始してください。

2. PostgreSQL データベースへの接続

次に、PostgreSQL データベースを統合します。公式の推奨事項に従って、ORM として TypeORM を使用します。ORM の役割は、データベースをコードに統合することです。

依存関係のインストール

npm install @nestjs/typeorm typeorm pg
  • @nestjs/typeorm: TypeORM の公式 Nest.js モジュールで、TypeORM を Nest.js に適応させます。
  • typeorm: TypeORM ライブラリ自体。
  • pg: PostgreSQL 用の Node.js ドライバーで、Node.js が PostgreSQL の読み書きを可能にします。

データベースの設定

チュートリアルを高速化するために、ローカルでのデータベースのインストールとセットアップの手順はスキップします。代わりに、オンラインデータベースを直接プロビジョニングします。

Leapcellでワンクリックで無料データベースを作成できます。

Leapcell

ウェブサイトでアカウントを登録した後、「Create Database」をクリックします。

ImageP1

データベース名を入力し、デプロイメントリージョンを選択すると、PostgreSQL データベースを作成できます。

表示される新しいページで、データベースに接続するために必要な情報が見つかります。下部にはコントロールパネルが用意されており、ウェブページ上で直接データベースを読み取ったり変更したりできます。

ImageP2

データベース接続の設定

src/app.module.tsファイルを開き、TypeOrmModuleをインポートします。

Leapcell からのデータベース設定を使用して接続情報に記入します。ssltrueに設定する必要があることに注意してください。そうしないと、接続が失敗します。

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'your_leapcell_host', // Replace with your Leapcell host
      port: 5432,
      username: 'your_postgres_username', // Replace with your PostgreSQL username
      password: 'your_postgres_password', // Replace with your PostgreSQL password
      database: 'personal_blog_db', // Replace with your database name
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true, // Set to true in development, it automatically syncs the database schema
      ssl: true, // Required for services like Leapcell
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Posts モジュールの作成

次に、ブログ投稿を管理するモジュールを作成します。

Nest CLI を使用して、必要なファイルを迅速に生成できます。

nest generate module posts
nest generate controller posts
nest generate service posts

その後、データベースに接続するためにPostエンティティファイルを作成する必要があります。src/postsディレクトリで、post.entity.tsという名前のファイルを作成します。

// src/posts/post.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn } from 'typeorm';

@Entity()
export class Post {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  title: string;

  @Column('text')
  content: string;

  @CreateDateColumn()
  createdAt: Date;
}

次に、データベースに接続する必要があります。

PostsModuleTypeOrmModuleを登録します。src/posts/posts.module.tsを開き、TypeOrmModule.forFeature([Post])をインポートします。

// src/posts/posts.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PostsController } from './posts.controller';
import { PostsService } from './posts.service';
import { Post } from './post.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Post])],
  controllers: [PostsController],
  providers: [PostsService],
})
export class PostsModule {}

Leapcellのデータベース詳細ページに移動し、Web エディタで次のコマンドを実行して、対応するテーブルを生成します。

CREATE TABLE "post" (
    "id" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    "title" VARCHAR NOT NULL,
    "content" TEXT NOT NULL,
    "createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

最後に、PostsServiceを作成する必要があります。PostsServiceは、投稿に関連するすべてのビジネスロジックを処理する責任があります。src/posts/posts.service.tsを開き、次のコードを追加します。

// src/posts/posts.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Post } from './post.entity';

@Injectable()
export class PostsService {
  constructor(
    @InjectRepository(Post)
    private postsRepository: Repository<Post>
  ) {}

  findAll(): Promise<Post[]> {
    return this.postsRepository.find({
      order: {
        createdAt: 'DESC',
      },
    });
  }

  findOne(id: string): Promise<Post> {
    return this.postsRepository.findOneBy({ id });
  }

  async create(post: Partial<Post>): Promise<Post> {
    const newPost = this.postsRepository.create(post);
    return this.postsRepository.save(newPost);
  }
}

EJS によるページレンダリングの設定

次に、動的な HTML ページをレンダリングできるように EJS を設定します。

依存関係のインストール

npm install ejs

ビューエンジンの統合

src/main.tsファイルを開き、次のように変更します。

// src/main.ts
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  app.useStaticAssets(join(__dirname, '..', 'public'));
  app.setBaseViewsDir(join(__dirname, '..', 'views'));
  app.setViewEngine('ejs');

  await app.listen(3000);
}
bootstrap();

プロジェクトのルートディレクトリ(srcと同じレベル)に、viewspublicフォルダを作成します。

- personal-blog
    - src
    - views
    - public

フロントエンドページの実装

viewsフォルダに次のファイルを作成します。

  • _header.ejs (再利用可能なヘッダー)

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title><%= title %></title>
        <link rel="stylesheet" href="/css/style.css" />
      </head>
      <body>
        <header>
          <h1><a href="/">My Blog</a></h1>
          <a href="/posts/new" class="new-post-btn">New Post</a>
        </header>
        <main></main>
      </body>
    </html>
    
  • _footer.ejs (再利用可能なフッター)

        </main>
        <footer>
            <p>&copy; 2025 My Blog</p>
        </footer>
    </body>
    </html>
    
  • index.ejs (ブログホームページ)

    <%- include('_header', { title: 'Home' }) %>
    
    <div class="post-list">
      <% posts.forEach(post => { %>
      <article class="post-item">
        <h2><a href="/posts/<%= post.id %>"><%= post.title %></a></h2>
        <p><%= post.content.substring(0, 150) %>...</p>
        <small><%= new Date(post.createdAt).toLocaleDateString() %></small>
      </article>
      <% }) %>
    </div>
    
    <%- include('_footer') %>
    
  • post.ejs (投稿詳細ページ)

    <%- include('_header', { title: post.title }) %>
    
    <article class="post-detail">
      <h1><%= post.title %></h1>
      <small><%= new Date(post.createdAt).toLocaleDateString() %></small>
      <div class="post-content"><%- post.content.replace(/\n/g, '<br />') %></div>
    </article>
    <a href="/" class="back-link">&larr; Back to Home</a>
    
    <%- include('_footer') %>
    
  • new-post.ejs (新規投稿ページ)

    <%- include('_header', { title: 'New Post' }) %>
    
    <form action="/posts" method="POST" class="post-form">
      <div class="form-group">
        <label for="title">Title</label>
        <input type="text" id="title" name="title" required />
      </div>
      <div class="form-group">
        <label for="content">Content</label>
        <textarea id="content" name="content" rows="10" required></textarea>
      </div>
      <button type="submit">Submit</button>
    </form>
    
    <%- include('_footer') %>
    

2. CSS スタイルの追加

public/css/style.cssに簡単なスタイルを追加します。

/* public/css/style.css */
body {
  font-family: sans-serif;
  line-height: 1.6;
  margin: 0;
  background-color: #f4f4f4;
  color: #333;
}
header {
  background: #333;
  color: #fff;
  padding: 1rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
header a {
  color: #fff;
  text-decoration: none;
}
main {
  max-width: 800px;
  margin: 2rem auto;
  padding: 1rem;
  background: #fff;
  border-radius: 5px;
}
.post-item {
  margin-bottom: 2rem;
  border-bottom: 1px solid #eee;
  padding-bottom: 1rem;
}
.post-item h2 a {
  text-decoration: none;
  color: #333;
}
.post-detail .post-content {
  margin-top: 1rem;
}
.new-post-btn {
  background: #5cb85c;
  padding: 0.5rem 1rem;
  border-radius: 5px;
}
.post-form .form-group {
  margin-bottom: 1rem;
}
.post-form label {
  display: block;
  margin-bottom: 0.5rem;
}
.post-form input,
.post-form textarea {
  width: 100%;
  padding: 0.5rem;
}
.post-form button {
  background: #337ab7;
  color: #fff;
  padding: 0.7rem 1.5rem;
  border: none;
  cursor: pointer;
}
footer p {
  text-align: center;
}

バックエンドとフロントエンドページの接続

HTTP リクエストを処理し、EJS テンプレートをレンダリングするために、src/posts/posts.controller.tsを更新します。

// src/posts/posts.controller.ts
import { Controller, Get, Render, Param, Post, Body, Res } from '@nestjs/common';
import { PostsService } from './posts.service';
import { Response } from 'express';

@Controller('posts')
export class PostsController {
  constructor(private readonly postsService: PostsService) {}

  @Get()
  @Render('index')
  async root() {
    const posts = await this.postsService.findAll();
    return { posts };
  }

  @Get('new')
  @Render('new-post')
  newPostForm() {
    return;
  }

  @Post()
  async create(@Body() body: { title: string; content: string }, @Res() res: Response) {
    await this.postsService.create(body);
    res.redirect('/posts');
  }

  @Get(':id')
  @Render('post')
  async post(@Param('id') id: string) {
    const post = await this.postsService.findOne(id);
    return { post };
  }
}

次に、ルートパス/がブログホームページにリダイレクトされるようにsrc/app.controller.tsを更新します。

// src/app.controller.ts
import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
import { AppService } from './app.service';

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

  @Get()
  root(@Res() res: Response) {
    return res.redirect('/posts');
  }
}

ブログの実行

ブログを開始するには、ターミナルで次のコマンドを実行します。

npm run start:dev

ブラウザでhttp://localhost:3000を開いてブログページを表示します。新しい投稿を書いてみてください!

ImageP3

ImageP4

これで、ウェブサイトと API を自由にカスタマイズして、Nest.js の理解を深めることができます。

ブログのオンラインデプロイ

さて、自分で作ったウェブサイトを他の人に見せて、誰でもアクセスできるようにするにはどうすればよいか考えているかもしれません。

以前データベースを作成するために使用したLeapcellを覚えていますか?Leapcell はデータベースを作成するだけでなく、Nest.js を含むさまざまな言語やフレームワークのプロジェクトをホストできる Web アプリケーションホスティングプラットフォームでもあります。

Leapcell

以下の手順に従ってください。

  1. プロジェクトを GitHub にコミットします。GitHub の公式ドキュメントを参照して手順を確認してください。Leapcell は後で GitHub リポジトリからコードをプルします。
  2. Leapcell ページで「Create Service」をクリックします。
    ImageP5
  3. Nest.js リポジトリを選択すると、Leapcell が必要な構成を自動的に入力します。
    ImageP6
  4. 下部にある「Submit」をクリックしてデプロイします。デプロイはすぐに完了し、デプロイメントホームページに戻ります。ここで、Leapcell がドメインを提供していることがわかります。これがブログのオンラインアドレスです。
    ImageP7

これで、このリンクを友人と共有すれば、誰もがオンラインであなたのブログを見ることができます!


X でフォローする:@LeapcellJP


ブログでこの記事を読む

関連記事:

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?