Nest.js、MongoDB、Vue.jsでブログを構築する方法

著者は、Write for DOnationsプログラムの一部として寄付を受け取るためにSoftware in the Public Interest Incを選択しました。

前書き

Nest.jsは、TypeScriptで構築されたスケーラブルなサーバーサイドJavaScriptフレームワークであり、JavaScriptとの互換性を維持しているため、効率的で信頼性の高いバックエンドアプリケーションを構築するための効果的なツールになります。 Node.js開発の世界に成熟した構造設計パターンを提供するモジュラーアーキテクチャを備えています。

Vue.jsは、ユーザーインターフェイスを構築するためのフロントエンドJavaScriptフレームワークです。 シンプルでありながら非常に強力なAPIと優れたパフォーマンスを備えています。 Vue.js is capable of powering the front-end layer and logic of any web application irrespective of the size. 他のライブラリまたは既存のプロジェクトと簡単に統合できるため、ほとんどの最新のWebアプリケーションに最適です。

このチュートリアルでは、Nest.jsアプリケーションを構築して、そのビルディングブロックと最新のWebアプリケーションを構築するための基本原則を理解します。 このプロジェクトにアプローチするには、アプリケーションを2つの異なるセクション(フロントエンドとバックエンド)に分けます。 まず、Nest.jsで構築されたRESTfulバックエンドAPIに集中します。 次に、Vue.jsで構築するフロントエンドに焦点を当てます。 両方のアプリケーションは異なるポートで実行され、個別のドメインとして機能します。

ユーザーが新しい投稿を作成して保存し、ホームページで保存した投稿を表示し、投稿の編集や削除などの他のプロセスを実行できるブログアプリケーションを構築します。 さらに、アプリケーションを接続し、そのデータをMongoDBで永続化します。これは、JSONドキュメントを受信して​​保存できるスキーマのないNoSQLデータベースです。 このチュートリアルは、開発環境でのアプリケーションの構築に焦点を当てています。 実稼働環境では、アプリケーションのユーザー認証も考慮する必要があります。

前提条件

このチュートリアルを完了するには、次のものが必要です。

  • Node.js(少なくともv6)およびnpm(少なくともv5.2)のローカルインストール。 Node.js is a JavaScript run-time environment that allows you to run your code outside of the browser. npmと呼ばれるパッケージマネージャーがプリインストールされており、パッケージをインストールおよび更新できます。 これらをmacOSまたはUbuntu18.04にインストールするには、How to Install Node.js and Create a Local Development Environment on macOSの手順またはHow To Install Node.js on Ubuntu 18.04の「PPAを使用したインストール」セクションに従います。

  • マシンにインストールされたMongoDB。 指示hereに従って、選択したオペレーティングシステム用にダウンロードしてインストールします。 MongoDBを正常にインストールするには、MacHomebrewを使用するか、MongoDB website.からダウンロードしてインストールします。

  • TypeScriptとJavaScriptの基本的な理解。

  • Visual Studio CodeAtomSublime Textなどのテキストエディタがインストールされています。

[.note]#Note:このチュートリアルでは、開発にmacOSマシンを使用します。 別のオペレーティングシステムを使用している場合は、チュートリアル全体でnpmコマンドにsudoを使用する必要がある場合があります。

[[step-1 -—- installing-nest-js-and-other-dependencies]] ==ステップ1—Nest.jsとその他の依存関係のインストール

このセクションでは、アプリケーションと必要な依存関係をローカルマシンにインストールすることで、Nest.jsを使い始めます。 Nest.jsが提供するCLIを使用するか、GitHubからスタータープロジェクトをインストールすることで、Nest.jsを簡単にインストールできます。 このチュートリアルでは、CLIを使用してアプリケーションをセットアップします。 開始するには、ターミナルから次のコマンドを実行して、マシンにグローバルにインストールします。

npm i -g @nestjs/cli

次のような出力が表示されます。

Output@nestjs/[email protected]
added 220 packages from 163 contributors in 49.104s

Nest CLIのインストールを確認するには、ターミナルから次のコマンドを実行します。

nest --version

マシンにインストールされている現在のバージョンを示す出力が表示されます。

Output5.8.0

nestコマンドを使用してプロジェクトを管理し、それを使用して、コントローラー、モジュール、プロバイダーなどの関連ファイルを生成します。

このチュートリアルのプロジェクトを開始するには、nestコマンドを使用して、ターミナルから次のコマンドを実行し、blog-backendという名前の新しいNest.jsプロジェクトを作成します。

nest new blog-backend

コマンドを実行した直後に、nestは、descriptionversionauthorなどの基本情報を提供するように要求します。 先に進み、適切な詳細を提供します。 各プロンプトに応答した後、続行するには、コンピューターでENTERを押します。

次に、パッケージマネージャーを選択します。 このチュートリアルでは、npmを選択し、ENTERを押してNest.jsのインストールを開始します。

Alt Creating a Nest project

これにより、ローカル開発フォルダー内のblog-backendフォルダーに新しいNest.jsプロジェクトが生成されます。

次に、ターミナルから新しいプロジェクトフォルダーに移動します。

cd blog-backend

次のコマンドを実行して、他のサーバーの依存関係をインストールします。

npm install --save @nestjs/mongoose mongoose

MongoDBのオブジェクトモデリングツール用のNest.js専用パッケージである@nestjs/mongooseと、Mongoose用のパッケージであるmongooseをインストールしました。

次に、次のコマンドを使用してアプリケーションを起動します。

npm run start

これで、お気に入りのブラウザーからhttp://localhost:3000に移動すると、アプリケーションが実行されていることがわかります。

Alt Welcome page of the fresh installation of Nest.js application

Nest CLIコマンドの可用性を活用して、プロジェクトを正常に生成しました。 その後、アプリケーションの実行に進み、ローカルマシンのデフォルトポート3000でアクセスしました。 次のセクションでは、データベース接続の構成を設定して、アプリケーションをさらに詳しく説明します。

[[step-2 -—- configuring-and-connecting-with-the-database]] ==ステップ2—構成とデータベースへの接続

このステップでは、MongoDBを構成してNest.jsアプリケーションに統合します。 MongoDBを使用して、アプリケーションのデータを保存します。 MongoDBは、データをdocumentsfield : valueペアとして格納します。 このデータ構造にアクセスするには、Mongooseを使用します。これは、MongoDBデータベースが格納するデータのタイプを表すスキーマを定義できるオブジェクトドキュメントモデリング(ODM)です。

MongoDBを起動するには、アプリケーションが実行を継続できるように別のターミナルウィンドウを開き、次のコマンドを実行します。

sudo mongod

これにより、MongoDBサービスが開始され、マシンのバックグラウンドでデータベースが実行されます。

テキストエディタでプロジェクトblog-backendを開き、./src/app.module.tsに移動します。 インストールされたMongooseModuleをルートApplicationModuleに含めることにより、データベースへの接続を設定できます。 これを実現するには、app.module.tsのコンテンツを次の強調表示された行で更新します。

~/blog-backend/src/app.module.ts

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

@Module({
  imports: [
    MongooseModule.forRoot('mongodb://localhost/nest-blog', { useNewUrlParser: true }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }

このファイルでは、forRoot()メソッドを使用してデータベースへの接続を提供します。 編集が終了したら、ファイルを保存して閉じます。

これで、MongoDB用のMongooseモジュールを使用してデータベース接続をセットアップしました。 次のセクションでは、Mongooseライブラリ、TypeScriptインターフェイス、およびデータ転送オブジェクト(DTO)スキーマを使用してデータベーススキーマを作成します。

[[step-3 -—- creating-a-database-schema-interfaces-and-dto]] ==ステップ3—データベーススキーマ、インターフェイス、およびDTOの作成

このステップでは、Mongooseを使用して、データベース用にschemainterface、およびdata transfer objectを作成します。 Mongooseは、データ間の関係の管理に役立ち、データ型のスキーマ検証を提供します。 アプリケーションのデータベース内のデータの構造とデータ型を定義しやすくするために、以下を決定するファイルを作成します。

  • database schema:これは、データベースに格納する必要のあるデータの構造とタイプを定義するための青写真としてのデータの編成です。

  • interfaces:TypeScriptインターフェイスはタイプチェックに使用されます。 アプリケーションに渡す必要のあるデータのタイプを定義するために使用できます。

  • data transfer object:これは、データがネットワークを介して送信される方法を定義し、プロセス間でデータを伝送するオブジェクトです。

開始するには、アプリケーションが現在実行されているターミナルに戻り、CTRL + Cでプロセスを停止してから、./src/フォルダーに移動します。

cd ./src/

次に、blogという名前のディレクトリと、その中にschemasフォルダを作成します。

mkdir -p blog/schemas

schemasフォルダーに、blog.schema.tsという名前の新しいファイルを作成し、テキストエディターを使用して開きます。 次に、次のコンテンツを追加します。

~/blog-backend/src/blog/schemas/blog.schema.ts

import * as mongoose from 'mongoose';

export const BlogSchema = new mongoose.Schema({
    title: String,
    description: String,
    body: String,
    author: String,
    date_posted: String
})

ここでは、Mongooseを使用して、データベースに保存するデータのタイプを定義しました。 すべてのフィールドに文字列値のみが格納され、受け入れられるように指定しました。 編集が終了したら、ファイルを保存して閉じます。

これで、データベーススキーマが決定されたので、インターフェイスの作成に進むことができます。

開始するには、blogフォルダーに戻ります。

cd ~/blog-backend/src/blog/

interfacesという名前の新しいフォルダーを作成し、そのフォルダーに移動します。

mkdir interfaces

interfacesフォルダーに、post.interface.tsという名前の新しいファイルを作成し、テキストエディターを使用して開きます。 次のコンテンツを追加して、Postのデータのタイプを定義します。

~/blog-backend/src/blog/interfaces/post.interface.ts

import { Document } from 'mongoose';

export interface Post extends Document {
    readonly title: string;
    readonly description: string;
    readonly body: string;
    readonly author: string;
    readonly date_posted: string
}

このファイルでは、Post型のデータ型を文字列値として正常に定義しています。 ファイルを保存して終了します。

アプリケーションはデータベースにデータを送信する機能を実行するため、ネットワークを介してデータを送信する方法を定義するデータ転送オブジェクトを作成します。

これを実現するには、./src/blogフォルダー内にフォルダーdtoを作成します。 新しく作成したフォルダー内に、create-post.dto.tsという名前の別のファイルを作成します

blogフォルダーに戻ります。

cd ~/blog-backend/src/blog/

次に、dtoという名前のフォルダーを作成し、そのフォルダーに移動します。

mkdir dto

dtoフォルダーに、create-post.dto.tsという名前の新しいファイルを作成し、テキストエディターを使用して開いて、次のコンテンツを追加します。

~/blog-backend/src/blog/dto/create-post.dto.ts

export class CreatePostDTO {
    readonly title: string;
    readonly description: string;
    readonly body: string;
    readonly author: string;
    readonly date_posted: string
}

CreatePostDTOクラスの個々のプロパティのそれぞれに、データ型がstringであり、不必要な変更を避けるためにreadonlyとしてマークされています。 編集が終了したら、ファイルを保存して終了します。

この手順では、データベースのデータベーススキーマ、インターフェイス、およびデータベースに保存するデータのデータ転送オブジェクトを作成しました。 次に、ブログ用のモジュール、コントローラー、およびサービスを生成します。

[[step-4 -—- creating-the-module-controller-and-service-for-the-blog]] ==ステップ4—ブログのモジュール、コントローラー、およびサービスの作成

このステップでは、ブログ用のモジュールを作成して、アプリケーションの既存の構造を改善します。 このモジュールは、アプリケーションのファイル構造を整理します。 次に、ルートを処理し、クライアントからのHTTPリクエストを処理するコントローラーを作成します。 最後に、アプリケーションのコントローラーが処理するには複雑すぎるビジネスロジックをすべて処理するサービスを設定します。

モジュールの生成

AngularフロントエンドWebフレームワークと同様に、Nest.jsはモジュラー構文を使用します。 Nest.js applications have a modular design; it comes installed with a single root module, which is often sufficient for a small application. しかし、アプリケーションが成長し始めると、Nest.jsはコードを関連機能に分割する複数モジュールの組織を推奨します。

Nest.jsのmoduleは、@Module()デコレータによって識別され、controllersprovidersなどのプロパティを持つオブジェクトを取り込みます。 これらの各プロパティは、それぞれcontrollersprovidersの配列を取ります。

構造をより整理するために、このブログアプリケーション用の新しいモジュールを生成します。 開始するには、まだ~/blog-backendフォルダーで、次のコマンドを実行します。

nest generate module blog

次のような出力が表示されます。

OutputCREATE /src/blog/blog.module.ts

UPDATE /src/app.module.ts

このコマンドは、アプリケーション用にblog.module.tsという名前の新しいモジュールを生成し、新しく作成されたモジュールをアプリケーションのルートモジュールにインポートしました。 これにより、Nest.jsはルートモジュール以外の別のモジュールを認識することができます。

このファイルには、次のコードが表示されます。

~/blog-backend/src/blog/blog.module.ts

import { Module } from '@nestjs/common';

@Module({})
export class BlogModule {}

このBlogModuleは、チュートリアルの後半で必要なプロパティで更新します。 ファイルを保存して終了します。

サービスの生成

serviceは、Nest.jsではプロバイダーとも呼ばれ、コントローラーからロジックを削除するように設計されています。これは、HTTPリクエストのみを処理し、より複雑なタスクをサービスにリダイレクトすることを目的としています。 サービスはプレーンなJavaScriptクラスであり、その上に@Injectable()デコレータがあります。 新しいサービスを生成するには、プロジェクトディレクトリ内にいる間にターミナルから次のコマンドを実行します。

nest generate service blog

次のような出力が表示されます。

Output  CREATE /src/blog/blog.service.spec.ts (445 bytes)

CREATE /src/blog/blog.service.ts (88 bytes)

UPDATE /src/blog/blog.module.ts (529 bytes)

ここで使用されるnestコマンドは、テストに使用できるblog.service.spec.tsファイルを作成しました。 また、新しいblog.service.tsファイルを作成しました。このファイルは、このアプリケーションのすべてのロジックを保持し、MongoDBデータベースへのドキュメントの追加と取得を処理します。 また、新しく作成されたサービスを自動的にインポートし、blog.module.tsに追加しました。

サービスは、アプリケーション内のすべてのロジックを処理し、データベースとのやり取りを行い、適切な応答をコントローラーに返します。 これを行うには、テキストエディタでblog.service.tsファイルを開き、内容を次のように置き換えます。

~/blog-backend/src/blog/blog.service.ts

import { Injectable } from '@nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { Post } from './interfaces/post.interface';
import { CreatePostDTO } from './dto/create-post.dto';

@Injectable()
export class BlogService {

    constructor(@InjectModel('Post') private readonly postModel: Model) { }

    async getPosts(): Promise {
        const posts = await this.postModel.find().exec();
        return posts;
    }

    async getPost(postID): Promise {
        const post = await this.postModel
            .findById(postID)
            .exec();
        return post;
    }

    async addPost(createPostDTO: CreatePostDTO): Promise {
        const newPost = await this.postModel(createPostDTO);
        return newPost.save();
    }

    async editPost(postID, createPostDTO: CreatePostDTO): Promise {
        const editedPost = await this.postModel
            .findByIdAndUpdate(postID, createPostDTO, { new: true });
        return editedPost;
    }

    async deletePost(postID): Promise {
        const deletedPost = await this.postModel
            .findByIdAndRemove(postID);
        return deletedPost;
    }

}

このファイルでは、最初に必要なモジュールを@nestjs/commonmongoose、および@nestjs/mongooseからインポートしました。 また、Postという名前のインターフェイスとデータ転送オブジェクトCreatePostDTOをインポートしました。

constructorに、@InjectModel('Post')を追加しました。これにより、PostモデルがこのBlogServiceクラスに挿入されます。 これで、この注入されたモデルを使用して、すべての投稿を取得し、単一の投稿を取得し、他のデータベース関連のアクティビティを実行できます。

次に、次のメソッドを作成しました。

  • getPosts():データベースからすべての投稿をフェッチします。

  • getPost():データベースから単一の投稿を取得します。

  • addPost():新しい投稿を追加します。

  • editPost():単一の投稿を更新します。

  • deletePost():特定の投稿を削除します。

完了したら、ファイルを保存して終了します。

バックエンドAPIからMongoDBデータベースとの適切な対話を処理するいくつかのメソッドのセットアップと作成が完了しました。 次に、フロントエンドクライアントからのHTTP呼び出しを処理する必要なルートを作成します。

コントローラーの生成

巣の中。 js、controllersは、アプリケーションのクライアント側からの着信要求を処理し、適切な応答を返す責任があります。 他のほとんどのWebフレームワークと同様に、アプリケーションがリクエストをリッスンし、それに応答することが重要です。

ブログアプリケーションのすべてのHTTPリクエストに対応するには、nestコマンドを利用して新しいコントローラーファイルを生成します。 プロジェクトディレクトリblog-backendにいることを確認し、次のコマンドを実行します。

nest generate controller blog

次のような出力が表示されます。

OutputCREATE /src/blog/blog.controller.spec.ts (474 bytes)

CREATE /src/blog/blog.controller.ts (97 bytes)

UPDATE /src/blog/blog.module.ts (483 bytes)

出力は、このコマンドがsrc/blogディレクトリ内に2つの新しいファイルを作成したことを示しています。 それらはblog.controller.spec.tsblog.controller.tsです。 前者は、新しく作成されたコントローラーの自動テストを作成するために使用できるファイルです。 後者はコントローラーファイル自体です。 Nest.jsのコントローラーは、@Controllerメタデータで装飾されたTypeScriptファイルです。 このコマンドは、新しく作成されたコントローラーもインポートし、ブログモジュールに追加しました。

次に、テキストエディタでblog.controller.tsファイルを開き、次の内容で更新します。

~/blog-backend/src/blog/blog.controller.ts

import { Controller, Get, Res, HttpStatus, Param, NotFoundException, Post, Body, Query, Put, Delete } from '@nestjs/common';
import { BlogService } from './blog.service';
import { CreatePostDTO } from './dto/create-post.dto';
import { ValidateObjectId } from '../shared/pipes/validate-object-id.pipes';


@Controller('blog')
export class BlogController {

    constructor(private blogService: BlogService) { }

    @Get('posts')
    async getPosts(@Res() res) {
        const posts = await this.blogService.getPosts();
        return res.status(HttpStatus.OK).json(posts);
    }

    @Get('post/:postID')
    async getPost(@Res() res, @Param('postID', new ValidateObjectId()) postID) {
        const post = await this.blogService.getPost(postID);
        if (!post) throw new NotFoundException('Post does not exist!');
        return res.status(HttpStatus.OK).json(post);

    }

    @Post('/post')
    async addPost(@Res() res, @Body() createPostDTO: CreatePostDTO) {
        const newPost = await this.blogService.addPost(createPostDTO);
        return res.status(HttpStatus.OK).json({
            message: "Post has been submitted successfully!",
            post: newPost
        })
    }
}

このファイルでは、最初に、@nestjs/commonモジュールからのHTTP要求を処理するために必要なモジュールをインポートしました。 次に、BlogServiceCreatePostDTO、およびValidateObjectIdの3つの新しいモジュールをインポートしました。 その後、アクセスを取得し、BlogServiceファイル内ですでに定義されている関数を利用するために、コンストラクターを介してBlogServiceをコントローラーに挿入しました。 これは、効率を高め、アプリケーションのモジュール性を高めるためにNest.jsで使用されるdependency injectionと見なされるパターンです。

最後に、次の非同期メソッドを作成しました。

  • getPosts():このメソッドは、クライアントからHTTP GET要求を受信して​​データベースからすべての投稿をフェッチし、適切な応答を返す機能を実行します。 @Get('posts')で装飾されています。

  • getPost():これはパラメーターとしてpostIDを取り、データベースから単一の投稿をフェッチします。 このメソッドに渡されるpostIDパラメータに加えて、ValidateObjectId()という名前の追加のメソッドが追加されていることに気づきました。 このメソッドは、Nest.jsのPipeTransformインターフェースを実装します。 その目的は、postIDパラメーターがデータベースで見つかることを検証および確認することです。 このメソッドは次のセクションで定義します。

  • addPost():このメソッドは、データベースに新しい投稿を追加するためのPOSTHTTPリクエストを処理します。

特定の投稿を編集および削除できるようにするには、blog.controller.tsファイルにさらに2つのメソッドを追加する必要があります。 これを行うには、以前にblog.controller.tsに追加したaddPost()メソッドの直後に次のeditPost()およびdeletePost()メソッドを含めます。

~/blog-backend/src/blog/blog.controller.ts

...
@Controller('blog')
export class BlogController {
    ...
    @Put('/edit')
    async editPost(
        @Res() res,
        @Query('postID', new ValidateObjectId()) postID,
        @Body() createPostDTO: CreatePostDTO
    ) {
        const editedPost = await this.blogService.editPost(postID, createPostDTO);
        if (!editedPost) throw new NotFoundException('Post does not exist!');
        return res.status(HttpStatus.OK).json({
            message: 'Post has been successfully updated',
            post: editedPost
        })
    }


    @Delete('/delete')
    async deletePost(@Res() res, @Query('postID', new ValidateObjectId()) postID) {
        const deletedPost = await this.blogService.deletePost(postID);
        if (!deletedPost) throw new NotFoundException('Post does not exist!');
        return res.status(HttpStatus.OK).json({
            message: 'Post has been deleted!',
            post: deletedPost
        })
    }
}

ここに追加しました:

  • editPost():このメソッドはpostIDのクエリパラメータを受け入れ、単一の投稿を更新する機能を実行します。 また、ValidateObjectIdメソッドを使用して、編集する必要のある投稿を適切に検証しました。

  • deletePost():このメソッドはpostIDのクエリパラメータを受け入れ、データベースから特定の投稿を削除します。

BlogControllerと同様に、ここで定義した各非同期メソッドにはメタデータデコレータがあり、Nest.jsがルーティングメカニズムとして使用するプレフィックスを受け取ります。 どのコントローラーがどのリクエストを受信するかを制御し、リクエストを処理してレスポンスを返すメソッドをそれぞれポイントします。

たとえば、このセクションで作成したBlogControllerには、プレフィックスblogと、プレフィックスpostsを受け取るgetPosts()という名前のメソッドがあります。 これは、blog/postshttp:localhost:3000/blog/posts)のエンドポイントに送信されたGET要求は、 `getPosts()`メソッドによって処理されることを意味します。 この例は、他のメソッドがHTTP要求を処理する方法に似ています。

ファイルを保存して終了します。

完全なblog.controller.tsファイルについては、このアプリケーションのDO Community repositoryにアクセスしてください。

このセクションでは、アプリケーションをより整理した状態に保つためのモジュールを作成しました。 また、データベースと対話して適切な応答を返すことにより、アプリケーションのビジネスロジックを処理するサービスを作成しました。 最後に、コントローラーを生成し、クライアント側からGETPOSTPUTDELETEなどのHTTP要求を処理するために必要なメソッドを作成しました。 次のステップでは、バックエンドのセットアップを完了します。

[[step-5 -—- creating-an-extra-validation-for-mongoose]] ==ステップ5—Mongooseの追加の検証を作成する

ブログアプリケーションの各投稿は、PostIDとも呼ばれる一意のIDで識別できます。 つまり、投稿を取得するには、このIDをクエリパラメータとして渡す必要があります。 このpostIDパラメータを検証し、投稿がデータベースで利用可能であることを確認するには、BlogController内の任意のメソッドから初期化できる再利用可能な関数を作成する必要があります。

これを構成するには、./src/blogフォルダーに移動します。

cd ./src/blog/

次に、sharedという名前の新しいフォルダーを作成します。

mkdir -p shared/pipes

pipesフォルダーで、テキストエディターを使用して、validate-object-id.pipes.tsという名前の新しいファイルを作成して開きます。 次のコンテンツを追加して、受け入れられるpostIDデータを定義します。

~/blog-backend/src/blog/shared/pipes/validate-object-id.pipes.ts

import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import * as mongoose from 'mongoose';

@Injectable()
export class ValidateObjectId implements PipeTransform {
    async transform(value: string, metadata: ArgumentMetadata) {
        const isValid = mongoose.Types.ObjectId.isValid(value);
        if (!isValid) throw new BadRequestException('Invalid ID!');
        return value;
    }
}

ValidateObjectId()クラスは、@nestjs/commonモジュールのPipeTransformメソッドを実装します。 これには、パラメーターとして値を受け取るtransform()という名前の単一のメソッドがあります。この場合はpostIDです。 上記の方法では、データベースで見つからないpostIDを含むこのアプリケーションのフロントエンドからのHTTPリクエストは、無効と見なされます。 ファイルを保存して閉じます。

サービスとコントローラーの両方を作成した後、BlogSchemaに基づくPostモデルをセットアップする必要があります。 この構成はルートApplicationModule内でセットアップできますが、この場合、BlogModuleでモデルを構築すると、アプリケーションの組織が維持されます。 ./src/blog/blog.module.tsを開き、次の強調表示された行で更新します。

~/blog-backend/src/blog/blog.module.ts

import { Module } from '@nestjs/common';
import { BlogController } from './blog.controller';
import { BlogService } from './blog.service';
import { MongooseModule } from '@nestjs/mongoose';
import { BlogSchema } from './schemas/blog.schema';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: 'Post', schema: BlogSchema }])
 ],
  controllers: [BlogController],
  providers: [BlogService]
})
export class BlogModule { }

このモジュールは、MongooseModule.forFeature()メソッドを使用して、モジュールに登録するモデルを定義します。 これがないと、@injectModel()デコレータを使用してBlogService内にPostModelを挿入することはできません。 コンテンツの追加が終了したら、ファイルを保存して閉じます。

このステップでは、Nest.jsを使用して完全なバックエンドRESTful APIを作成し、MongoDBと統合しました。 次のセクションでは、フロントエンドアプリケーションが別のポートで実行されるため、別のサーバーからのHTTPリクエストを許可するようにサーバーを構成します。

[[step-6 -—- enableing-cors]] ==ステップ6—CORSを有効にする

1つのドメインから別のドメインへのHTTP要求は、サーバーによって許可されるように指定されている場合を除き、多くの場合デフォルトでブロックされます。 フロントエンドアプリケーションがバックエンドサーバーにリクエストを送信するには、Cross-origin resource sharing(CORS)を有効にする必要があります。これは、Webページ上の制限されたリソースのリクエストを許可する手法です。

Nest.jsでCORSを有効にするには、main.tsファイルに単一のメソッドを追加する必要があります。 ./src/main.tsにあるテキストエディタでこのファイルを開き、次の強調表示されたコンテンツで更新します。

~/blog-backend/src/main.ts

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

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

ファイルを保存して終了します。

バックエンドのセットアップが完了したので、フロントエンドに焦点を移し、Vue.jsを使用して、これまでに構築されたAPIを使用します。

[[step-7 -—- creating-the-vue-js-frontend]] ==ステップ7—Vue.jsフロントエンドの作成

このセクションでは、Vue.jsを使用してフロントエンドアプリケーションを作成します。 Vue CLIは、手間をかけずに新しいVue.jsプロジェクトをすばやく生成してインストールできる標準ツールです。

まず、Vue CLIをマシンにグローバルにインストールする必要があります。 別のターミナルを開き、blog-backendフォルダーから作業する代わりに、ローカルプロジェクトの開発フォルダーに移動して次のコマンドを実行します。

npm install -g @vue/cli

インストールプロセスが完了したら、vueコマンドを使用して新しいVue.jsプロジェクトを作成します。

vue create blog-frontend

このコマンドを入力すると、短いプロンプトが表示されます。 manually select featuresオプションを選択し、コンピューターでSPACEを押して複数の機能を強調表示することにより、このプロジェクトに必要な機能を選択します。 BabelRouter、およびLinter / Formatterを選択します。

Alt Vue project CLI set up

次の手順では、yと入力して、ルーターの履歴モードを使用します。これにより、ルーターファイル内で履歴モードが有効になり、このプロジェクト用に自動的に生成されます。 さらに、ESLint with error prevention onlyを選択して、リンター/フォーマッター構成を選択します。 次に、追加のLint機能のLint on saveを選択します。 次に、将来のプロジェクトのために構成をdedicated config fileで保存することを選択します。 vueconfigのように、プリセットの名前を入力します。

Alt Vue.js final CLI set up

Vue.js will then start creating the application and all its required dependencies in a directory named blog-frontend.

インストールプロセスが完了したら、Vue.jsアプリケーション内をナビゲートします。

cd blog-frontend

次に、次を使用して開発サーバーを起動します。

npm run serve

アプリケーションはhttp://localhost:8080で実行されます。

Alt Vue.js home view

このアプリケーション内でHTTPリクエストを実行するので、Axiosをインストールする必要があります。Axiosは、ブラウザ用の約束ベースのHTTPクライアントです。 ここでAxiosを使用して、アプリケーション内のさまざまなコンポーネントからHTTPリクエストを実行します。 コンピューターの端末からCTRL + Cを押してフロントエンドアプリケーションを停止し、次のコマンドを実行します。

npm install axios --save

フロントエンドアプリケーションは、アプリケーション内のさまざまなコンポーネントから特定のドメインのバックエンドAPIに対してAPI呼び出しを行います。 このアプリケーションの適切な構造を確保するために、helperファイルを作成し、サーバーbaseURLを定義できます。

まず、まだblog-frontend内にあるターミナルから、./src/フォルダーに移動します。

cd ./src/

utilsという名前の別のフォルダーを作成します。

mkdir utils

utilsフォルダーで、テキストエディターを使用して、helper.jsという名前の新しいファイルを作成して開きます。 次のコンテンツを追加して、バックエンドNest.jsプロジェクトのbaseURLを定義します。

~blog-frontend/src/utils/helper.js

export const server = {

baseURL: 'http://localhost:3000'

}

baseURLを定義することで、Vue.jsコンポーネントファイル内のどこからでも呼び出すことができます。 URLを変更する必要がある場合は、アプリケーション全体ではなく、このファイルのbaseURLを更新する方が簡単です。

このセクションでは、新しいVue.jsアプリケーションを作成するためのツールであるVue CLIをインストールしました。 このツールを使用して、blog-frontendアプリケーションを作成しました。 さらに、アプリケーションを実行し、Axiosという名前のライブラリをインストールしました。これは、アプリケーション内でHTTP呼び出しが行われるたびに使用します。 次に、アプリケーションのコンポーネントを作成します。

[[step-8 -—- creating-reusable-components]] ==ステップ8—再利用可能なコンポーネントの作成

次に、アプリケーションの再利用可能なコンポーネントを作成します。これは、Vue.jsアプリケーションの標準構造です。 Vue.jsのコンポーネントシステムにより、開発者は独自の状態、マークアップ、スタイルを持つことができるインターフェイスの単一の独立したユニットを構築できます。 これにより、Vue.jsのコンポーネントが再利用可能になります。

すべてのVue.jsコンポーネントには、3つの異なるセクションが含まれています。

  • <template>:HTMLコンテンツが含まれています

  • <script>:すべての基本的なフロントエンドロジックを保持し、関数を定義します

  • <style>:個別のコンポーネントごとのスタイルシート

最初に、コンポーネントを作成して新しい投稿を作成します。 これを行うには、./src/componentsフォルダー内にpostという名前の新しいフォルダーを作成します。このフォルダーには、投稿に必要な再利用可能なコンポーネントが格納されます。 次に、テキストエディタを使用して、新しく作成したpostフォルダ内に別のファイルを作成し、Create.vueという名前を付けます。 新しいファイルを開き、次のコードを追加します。このコードには、投稿を送信するために必要な入力フィールドが含まれています。

~blog-frontend/src/components/post/Create.vue

これは、CreatePostコンポーネントの<template>セクションです。 新しい投稿を作成するために必要なHTML入力要素が含まれています。 各入力フィールドには、入力属性としてv-modelディレクティブがあります。 これは、Vue.jsがユーザーの入力を簡単に取得できるように、各フォーム入力で双方向のデータバインディングを確保するためです。

次に、前のコンテンツの直後にある同じファイルに<script>セクションを追加します。

~blog-frontend/src/components/post/Create.vue

...

ここでは、createPost()という名前のメソッドを追加して、新しい投稿を作成し、Axiosを使用してサーバーに送信します。 ユーザーが新しい投稿を作成すると、アプリケーションはホームページにリダイレクトされ、ユーザーは作成された投稿のリストを表示できます。

このチュートリアルの後半でリダイレクトを実装するようにvue-routerを構成します。

編集が終了したら、ファイルを保存して閉じます。 完全なCreate.vueファイルについては、このアプリケーションのDO Community repositoryにアクセスしてください。

次に、特定の投稿を編集するための別のコンポーネントを作成する必要があります。 ./src/components/postフォルダーに移動し、別のファイルを作成して、Edit.vueという名前を付けます。 <template>セクションを含む次のコードを追加します。

~blog-frontend/src/components/post/Edit.vue

このテンプレートセクションには、CreatePost()コンポーネントと同様のコンテンツが含まれています。唯一の違いは、編集が必要な特定の投稿の詳細が含まれていることです。

次に、Edit.vue</template>セクションの直後に `

ここでは、特定の投稿を識別するためのルートパラメータidを取得しました。 次に、getPost()という名前のメソッドを作成して、データベースからこの投稿の詳細を取得し、それを使用してページを更新しました。 最後に、editPost()メソッドを作成して、編集した投稿をPUTHTTPリクエストでバックエンドサーバーに送信します。

ファイルを保存して終了します。 完全なEdit.vueファイルについては、このアプリケーションのDO Community repositoryにアクセスしてください。

次に、./src/components/postフォルダー内に新しいコンポーネントを作成し、Post.vueという名前を付けます。 これにより、ホームページから特定の投稿の詳細を表示できます。 次のコンテンツをPost.vueに追加します。

~blog-frontend/src/components/post/Post.vue

このコードは、titleauthor、および投稿bodyを含む投稿の詳細をレンダリングします。

ここで、</template>の直後に、次のコードをファイルに追加します。

~blog-frontend/src/components/post/Post.vue

...

投稿編集コンポーネントの<script>セクションと同様に、ルートパラメータidを取得し、それを使用して特定の投稿の詳細を取得しました。

コンテンツの追加が終了したら、ファイルを保存して閉じます。 完全なPost.vueファイルについては、このアプリケーションのDO Community repositoryにアクセスしてください。

次に、作成されたすべての投稿をユーザーに表示するには、新しいコンポーネントを作成します。 src/viewsviewsフォルダーに移動すると、Home.vueコンポーネントが表示されます。このファイルが存在しない場合は、テキストエディターを使用して作成し、次のコードを追加します。

~blog-frontend/src/views/Home.vue

ここでは、<template>セクション内で、<router-link>を使用して、post._idをクエリパラメーターとして渡して、編集および投稿の表示用のリンクを作成しました。 また、v-ifディレクティブを使用して、ユーザーの投稿を条件付きでレンダリングしました。 データベースからの投稿がない場合、ユーザーには次のテキストのみが表示されます:No post found at the moment

ファイルを保存して終了します。 完全なHome.vueファイルについては、このアプリケーションのDO Community repositoryにアクセスしてください。

ここで、Home.vue</template>セクションの直後に、次の</script>セクションを追加します。

~blog-frontend/src/views/Home.vue

...

このファイルの<script>セクション内で、データベースからすべての投稿をフェッチするfetchPosts()という名前のメソッドを作成し、サーバーから返されたデータでページを更新しました。

次に、フロントエンドアプリケーションのAppコンポーネントを更新して、HomeおよびCreateコンポーネントへのリンクを作成します。 src/App.vueを開き、次のように更新します。

~blog-frontend/src/App.vue



HomeコンポーネントとCreateコンポーネントの両方へのリンクを含めるほかに、このコンポーネントのスタイルシートであり、上のいくつかの要素のスタイルの定義を保持する<Style>セクションも含めました。ページ。 ファイルを保存して終了します。

このステップでは、アプリケーションに必要なすべてのコンポーネントを作成しました。 次に、ルーターファイルを構成します。

[[step-9 -—- setting-up-routing]] ==ステップ9—ルーティングの設定

必要なすべての再利用可能なコンポーネントを作成した後、作成したすべてのコンポーネントへのリンクでコンテンツを更新することにより、ルーターファイルを適切に構成できるようになりました。 これにより、フロントエンドアプリケーション内のすべてのエンドポイントが適切なアクションのために特定のコンポーネントにマップされます。 ./src/router.jsに移動し、その内容を次のように置き換えます。

~blog-frontend/src/router.js

import Vue from 'vue'
import Router from 'vue-router'
import HomeComponent from '@/views/Home';
import EditComponent from '@/components/post/Edit';
import CreateComponent from '@/components/post/Create';
import PostComponent from '@/components/post/Post';

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    { path: '/', redirect: { name: 'home' } },
    { path: '/home', name: 'home', component: HomeComponent },
    { path: '/create', name: 'Create', component: CreateComponent },
    { path: '/edit/:id', name: 'Edit', component: EditComponent },
    { path: '/post/:id', name: 'Post', component: PostComponent }
  ]
});

vue-routerモジュールからRouterをインポートし、modeおよびroutesパラメーターを渡してインスタンス化しました。 vue-routerのデフォルトモードはハッシュモードです。ハッシュモードでは、URLハッシュを使用して完全なURLをシミュレートし、URLが変更されたときにページが再読み込みされないようにします。 ハッシュを不要にするために、ここでは履歴モードを使用して、ページをリロードすることなくURLナビゲーションを実現しています。 最後に、routesオプション内で、エンドポイントのパスを指定しました。これは、ルートの名前と、アプリケーション内でルートが呼び出されたときにレンダリングされるコンポーネントです。 ファイルを保存して終了します。

アプリケーションへのルーティングを設定したので、Bootstrapファイルを含めて、アプリケーションのユーザーインターフェイスの事前に構築されたスタイル設定を支援する必要があります。 これを実現するには、テキストエディタで./public/index.htmlファイルを開き、ファイルに次のコンテンツを追加して、ブートストラップ用のCDNファイルを含めます。

~blog-frontend/public/index.html




  ...
  
  blog-frontend


   ...

ファイルを保存して終了し、アプリケーションが現在実行されていない場合は、blog-frontendに対してnpm run serveを使用してアプリケーションを再起動します。

[.note]#Note:バックエンドサーバーとMongoDBインスタンスの両方が実行されていることを確認します。 それ以外の場合は、別の端末からblog-backendに移動し、npm run startを実行します。 また、新しいターミナルからもsudo mongodを実行して、MongoDBサービスを開始します。

http://localhost:8080でアプリケーションに移動します。 これで、投稿を作成および編集してブログをテストできます。

Alt Create a new post

アプリケーションでCreateをクリックして、CreateComponentファイルに関連してレンダリングするCreate Post画面を表示します。 入力フィールドに値を入力し、Create Postボタンをクリックして投稿を送信します。 完了すると、アプリケーションはホームページにリダイレクトします。

アプリケーションのホームページはHomeComponentをレンダリングします。 このコンポーネントには、データベースからすべての投稿を取得してユーザーに表示するHTTP呼び出しを送信するメソッドがあります。

Alt View all posts from the database

特定の投稿のEdit Postボタンをクリックすると、編集ページに移動し、変更を組み込んで投稿を保存できます。

Alt Edit a new post

このセクションでは、アプリケーションのルーティングを構成および設定しました。 これで、ブログアプリケーションの準備が整いました。

結論

このチュートリアルでは、Nest.jsを使用してNode.jsアプリケーションを構築する新しい方法を検討しました。 Nest.jsを使用してバックエンドRESTful APIを構築するシンプルなブログアプリケーションを作成し、Vue.jsを使用してすべてのフロントエンドロジックを処理しました。 さらに、MongoDBをNest.jsアプリケーションのデータベースとして統合しました。

アプリケーションに認証を追加する方法の詳細については、人気のあるNode.js認証ライブラリであるPassport.jsを利用できます。 Passport.jsの統合については、Nest.js documentationで学ぶことができます。

このプロジェクトhere on GitHubの完全なソースコードを見つけることができます。 Nest.jsの詳細については、official documentationにアクセスしてください。

Related