https://auth0.com/blog/modern-full-stack-development-with-nestjs-react-typescript-and-mongodb-part-1/

 

Modern Full-Stack Development with Nest.js, React, TypeScript, and MongoDB: Part 1

Learn how to build modern and secure Full-Stack applications with React, TypeScript, and Nest.js.

auth0.com

더보기

Nest.js로 생성한 프로젝트에 React.js를 적용하려고 했는데, 이 블로그를 보고 프론트 프로젝트랑 백엔드 프로젝트 나눠서 돌리면 엄청 편한 방법이라는 것을 깨달았다.

 

항상 생각을 유연하게 하려고 노력하지만 역시(사스가) 내가 익숙한 부분 때문에 이러한 생각을 못 하게 되어 아쉬운 경험을 한다.

익숙한 부분이 생기면 당연하지 않다고 생각해야겠다.

 

원본 게시물이 정말 좋아서 많은 사람들이 보았으면 합니다!

배우게 될 내용

  • React.js 및 Node.js를 사용하여 최신 웹 애플리케이션 빌드하는 방법 ( 2부 )
  • Auto0으로 애플리케이션을 보호하는 방법
  • Typescript를 사용하여 React 애플리케이션을 빌드
  • Nest.js 백엔드 API 작성 ( 1부의 주요내용 )
  • 사용자 인터페이스를 구축하고 React.js를 사용하여 모든 프론드 엔드 로직 처리 ( 2부 )

전제조건

  • React를 사용하여 웹 애플리케이션을 빌드하는 데 필요한 기본 지식과 이전 경험
  • 필수는 아니지만 TypeScript에 대한 몇 가지 지식
  • 개발 머신에 Node.js 및 Yarn 패키지 관리자 설치 확인
  • MongoDB 설치 확인
  • macOS 시스템 기반

소개

Nest.js

  • Nest.js는 효율적이고 안정적이며 확장 가능한 서버 측 애플리케이션을 구축하기위한 모듈 식 아키텍처를 갖춘 진보적인 Node.js 프레임워크 입니다.
  • TypeScript로 완전히 구축되었지만 여전히 JavaScript와의 호환성을 유지하고 최신 JavaScript 기능을 활용합니다.
  • Node.js 개발 세계에 디자인 패턴과 성숙한 솔루션을 제공합니다.
  • Angular 응용 프로그램의 구조에 정통한 경우 Nest.js를 사용하는 것이 더 편할 것입니다.
  • Nest.js를 처음 사용하는 경우 Nest.js에서 Node.js 및 Express에 TypeScript를 가져 오는이 기사를 확인하여 Nest.js의 주요 개념에 익숙해 지십시오.

React.js

  • React는 직관적인 상호작용 형 사용자 인터페이스를 구축하기위한 오픈 소스 JavaScript 프론트 엔드 프레임워크 입니다.
  • 단일 페이지 응용 프로그램의 빠른 개발에서 뛰어난 성능과 단순성으로 인해 널리 채택되고 개발자들에게 최고의 선택입니다.
  • 이 React 튜토리얼에서 React의 작동 방식과 주요 개념을 익히십시오.

MongoDB

  • MongoDB는 스키마가 없는 NoSQL 데이터베이스로 JSON과 유사한 문서로 데이터를 수신하고 저장할 수 있습니다.
  • 데이터베이스 테이블을 행과 열로 생각하고 시각화하는 아이디어를 제거합니다.
  • JSON 형식으로 JavaScript 응용 프로그램을 빌드하여 생산성을 높일 수 있으므로 JavaScript 개발자에게는 이상하지 않습니다.
  • 배열 및 중첩 객체 값을 지원하며 유연하고 동적인 스키마를 허용합니다.
  • 데이터 간의 관계를 관리하고 스키마 유효성 검사를 제공하는 ODM (Object Data Modeling) 라이브러리 인 Mongoose와 함께 자주 사용됩니다.

Typescript

  • 공식 웹 사이트에 설명 된 TypeScript는 일반 JavaScript로 컴파일되는 JavaScript의 상위 집합입니다.
  • 버그가 적은 멋진 응용 프로그램을 성공적으로 개발할 수있는 기능을 추가하여 크고 복잡한 프로그램을 작성할 때 개발자의 생산성을 향상시킬 수 있도록 설계 및 개발되었습니다.
  • TypeScript를 사용하면 초기 단계에서 코드의 오류를 쉽게 발견 할 수 있으므로 프로덕션 환경에서 기존 응용 프로그램을 중단 할 염려없이 새로운 기능을 구현하는 데 쉽게 집중할 수 있습니다.

이 튜토리얼에서 앞서 지적한 바와 같이, 우리는이 멋진 현대적인 웹 도구를 결합하여 응용 프로그램을 구축 할 것입니다. 이 기사의 끝에는 새로운 프로젝트에서 React와 TypeScript를 결합하거나 기존 프로젝트를 향상시켜 응용 프로그램 구축의 이점을 탐색 할 수있는 충분한 지식을 모았습니다.

타입스크립트를 사용하여 리액트 애플리케이션을 구축해야하는 이유

  • React는 컴포넌트 기반 프론트 엔드 프레임 워크이며 여기 저기에서 props 및 state 객체를 사용합니다.
  • TypeScript를 사용하여 React 애플리케이션을 빌드하면 잘 정의되고 식별 가능한 prop 및 state 객체가 있는 강력한 유형(타입)의 컴포넌트를 가질 수 있습니다.
  • 이렇게하면 컴파일러에서 컴포넌트의 사용을 유형 확인하고 시간에 오류를 발견 할 수 있습니다.

간단히 말해 개발자로서 생산성을 높이고 코드를 보다 쉽게 ​​읽고 이해할 수 있습니다.

무엇을 만들 것인가

  • 사용자가 사용할 수있는 블로그 애플리케이션을 구축하려고합니다.
    • 새 게시물을 작성하고 저장합니다.
    • 홈페이지에서 새로 저장된 게시물 및 다른 모든 작성된 게시물을 봅니다.
    • 게시물 편집 및 삭제와 같은 프로세스를 수행합니다.
  • 데이터베이스에 데이터를 유지하기 위해 MongoDB를 사용하게됩니다.
  • 다음은 이 튜토리얼 끝에서 예상되는 내용의 미리보기 입니다.

  • 이 응용 프로그램을 통해 사용자는 인증 및 권한이 부여 된 경우에만 블로그 게시물을 작성할 수 있습니다.
  • 그렇지 않으면 인증 된 사용자 만 작성된 게시물을 볼 수 있습니다.
  • 사용자의 인증 및 권한 부여는 Auth0에 의해 처리됩니다.

 

  • 완전한 백엔드 API를 구축하는 것부터 시작하여 점진적으로 시작하고 한 번에 한 단계 씩 수행하며 모든 사용자가 데이터베이스에서 데이터를 작성, 검색 및 편집하기 위해 API 호출에 액세스하고 성공할 수 있도록합니다.
  • 그런 다음 Auth0을 통해 사용자 인증을 관리하여 API 보안을 진행합니다.
  • 시리즈의 이 부분에서 모든 구현을 테스트하려면 Postman을 사용합니다.

Nest.js를 사용하여 백엔드 API 빌드

  • 언급했듯이 백엔드 API는 Nest.js를 사용하여 빌드됩니다.
  • 여기에서 Nest.js를 설치 및 구성한 다음 API에 필요한 구조를 구현합니다.

Nest.js 설치 및 구성

  • Nest CLI라는 스캐 폴딩 Nest 애플리케이션을 위해 특별히 구축 된 명령 행 인터페이스를 사용하여 새 Nest.js 프로젝트를 쉽게 설치할 수 있습니다.

 

  • 새 Nest.js 응용 프로그램을 스캐폴딩하기 위해 특별히 작성된 명령 줄 인터페이스를 사용하여 시작합니다.
  • 또는 GitHub에서 Nest.js의 스타터 프로젝트를 복제 할 수 있습니다.
  • 이 방법으로 두 방법 모두 동일한 결과를 얻을 수 있지만 Nest.js 팀에서 처음 사용하는 사용자에게 권장 한대로 Nest CLI를 사용하여 프로젝트를 작성합니다.

 

  • Install the CLI by running the following command
npm install -g @nestjs/cli

 

  • Once the process is complete, confirm if Nest CLI has been installed by running the following command:
nest --version

 

  • You will see an output similar to the following indicating the version installed on your machine:
6.6.4

 

이 버전은 귀하의 버전과 다를 수 있습니다.

 

  • 여기에 표시된대로 nest 명령을 사용하여이 튜토리얼를 위한 새 프로젝트를 작성하십시오.
nest new blog-backend

 

  • 위의 명령을 실행 한 직후 nest는 사용할 패키지 관리자를 선택하라는 메시지를 표시합니다.
  • 컴퓨터에서 npm을 선택하고 Enter 키를 눌러 Nest.js 설치를 시작하십시오.

 

  • 로컬 개발 폴더 내의 blog-backend 디렉토리에 새 Nest.js 프로젝트가 생성됩니다.
  • 이제 새로 작성된 디렉토리로 이동하고 명령을 실행하여 다른 필수 서버 종속성을 설치하십시오.
// change directory
cd blog-backend

// install dependency
npm install --save @nestjs/mongoose mongoose

 

  • Nest.js는 Mongoose를 사용하여 MongoDB 데이터베이스와의 통합을 지원하므로 여기에서 수행 한 작업은 monnesose와 Nest.js 팀이 @nestjs/mongoose 통합을 위해 만든 전용 패키지를 설치하는 것입니다.

 

  • 설치 프로세스가 완료되면 MongooseModule을 애플리케이션으로 쉽게 가져올 수 있습니다.
  • 자세한 내용은 튜토리얼 뒷부분에서 설명합니다.

 

  • 다음으로 응용 프로그램을 시작하기 전에 코드 편집기를 사용하여 프로젝트를 열고 아래와 같이 기본 포트를 편집하십시오.
// /blog-backend/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(5000);// edit this
}
bootstrap();

 

  • 여기서 수행 한 작업은이 시리즈의 다음 부분에서 빌드 할 React 애플리케이션과의 포트 충돌을 피하기 위해 Nest.js의 기본 포트를 5000으로 변경하는 것입니다.
  • 기본적으로 포트 3000에서 실행됩니다.

 

  • 완료되면 다음 명령을 사용하여 응용 프로그램을 시작하십시오.
npm run start:dev

 

  • 로컬 컴퓨터의 포트 5000에서 응용 프로그램이 실행됩니다.
  • 선택한 브라우저에서 http://localhost:5000으로 이동하면 응용 프로그램이 실행되는 것을 볼 수 있습니다.

 

  • 이 섹션에서는 Nest CLI를 성공적으로 설치하고 이를 활용하여이 튜토리얼의 프로젝트를 생성했습니다.
  • 그런 다음 기본 포트 5000에서 응용 프로그램을 실행했습니다.
  • 다음으로, 앱과 생성 될 데이터베이스 간의 성공적인 연결을 보장하기 위해 노력할 것입니다.

데이터베이스 연결 구성

  • 이 섹션에서는 MongoDB를 애플리케이션에 구성 및 통합하는 것을 포함하여 데이터베이스 연결에 필요한 구성을 설정하는 것으로 시작합니다.
  • 이 튜토리얼의 전제 조건 섹션에 지시 된대로 지금까지 MongoDB를 설치해야합니다.
  • 처음 설치한다면 자동으로 실행하게 하게 합니다. 그러면 실행하는 작업이 필요하지 않습니다.
  • MongoDB가 현재 실행 중인지 확인하려면 다른 터미널 창을 열어서 백엔드 애플리케이션을 계속 실행하고 다음 명령을 실행하십시오.
ps aux | grep -v grep | grep mongod

 

  • 터미널에 아래 출력과 유사한 출력이 표시되면 MongoDB가 실행되고있는 것 입니다.
root  4190   0.0  0.1  4349676   7476 s001  S+    9:58AM   0:00.04 sudo mongod
root  4191   0.0  0.5  5560120  43160 s001  S+    9:58AM   0:00.86 mongod

 

  • 그렇지 않으면 다음 명령을 실행하여 MongoDB를 시작하십시오.
sudo mongod

 

참고 : MongoDB는 일반적으로 컴퓨터 운영 체제의 루트 디렉토리 내에서 /data/db 에 데이터를 저장하지만 운영 체제가 macOS Catalina이거나 위 명령을 실행하는 동안 오류가 발생하면 루트 폴더에 쓸 수 없습니다. 이를 처리하려면 여기에 표시된대로 다른 위치에 다른 디렉토리를 작성하고 명령을 실행할 때 해당 경로를 참조해야합니다.

 

sudo mongod --dbpath=/Users/<user>/data/db

 

  • 응용 프로그램의 연결을 기다리는 동안 MongoDB 서비스가 시작되고 백그라운드에서 데이터베이스가 실행됩니다.
  • 다음으로 이 파일 ./src/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'; // add this
@Module({
  imports: [
    MongooseModule.forRoot('mongodb://localhost/nest-blog-project', { useNewUrlParser: true }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

 

  • 여기에서 MongooseModule을 루트 AppModule로 가져온 다음 forRoot() 메소드를 사용하여 데이터베이스에 대한 연결을 제공했습니다.
  • 위 파일의 편집으로 MongoDB 용 Mongoose 모듈을 사용하여 애플리케이션에 대한 데이터베이스 연결을 설정했습니다.

데이터베이스 스키마 및 인터페이스 설정

  • 여기에서는 TypeScript 인터페이스를 만들어 응용 프로그램에서 데이터의 구조와 데이터 유형을 정의합니다.
  • TypeScript 인터페이스는 유형 확인에 사용되며 응용 프로그램에 전달해야하는 데이터 유형을 정의합니다.
  • 또한 Mongoose가 특정 응용 프로그램 내에 정의 된 스키마에서 모든 것을 파생시키는 경향이 있으므로 데이터베이스 스키마를 작성하게됩니다.

 

  • 시작하려면 응용 프로그램이 현재 실행중인 터미널로 돌아가서 CTRL + C를 사용하여 프로세스를 중지 한 다음 ./src/ 디렉토리로 다시 이동하여 그 안에 blog라는 디렉토리를 만드십시오.
  • 이제 처음 작성된 blog 디렉토리 내에 schema라는 서브 디렉토리를 작성하십시오.
  • 이 파일을 열고 그 안에 다음 내용을 추가하십시오.
// 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,
});

 

  • 이 정의는 모든 필드가 문자열 값만 저장하고 수락하도록 지정합니다.
  • 이를 사용하면 데이터베이스에 저장 될 데이터의 데이터 유형이 올바르게 제어됩니다.

 

  • 다음으로 주로 유형 검사를 위한 인터페이스를 만듭니다.
  • 시작하려면 /blog-backend/src/blog 폴더 내에 interfaces라는 새 디렉토리를 만드십시오.
  • 그 안에 파일을 생성하고 이름을 post.interface.ts로 지정하고 다음 코드를 추가하십시오.
// /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 유형의 데이터 유형을 문자열 값으로 정의했습니다.

데이터 전송 객체 (DTO) 생성

  • 데이터 전송 개체는 네트워크를 통해 데이터를 전송하는 방법을 정의하고 응용 프로그램에서 데이터베이스로 데이터를 게시하는 방법을 제어합니다.
  • 이를 위해서는 ./src/blog 폴더 안에 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이 있고 불필요한 돌연변이를 피하기 위해 read-only으로 표시했습니다.

블로그 모듈 만들기

  • Nest.js의 모듈은 @Module() 데코레이터로 주석이 달린 클래스입니다.
  • 응용 프로그램 구조를 체계적으로 유지하는 데 도움이됩니다.
  • Nest.js는 각 애플리케이션에 적어도 하나의 모듈 (대부분 루트 모듈)이 있어야합니다.
  • 이를 고려하여 nest 명령을 사용하여 응용 프로그램에 대한 모듈을 생성합니다.
  • 그렇게하려면, 여전히 blog-backend 디렉토리 안에 있는지 확인하고 다음 명령을 실행하십시오.
nest generate module blog

 

  • 위의 명령은 애플리케이션에 대해 blog.module.ts라는 새 모듈을 생성하고 새로 작성된 BlogModule을 자동으로 가져 와서 루트 모듈을 업데이트 합니다.
  • 이를 통해 Nest.js는 응용 프로그램 내에서 루트 모듈 외에 다른 모듈을 인식합니다.
    • app.module.ts 파일을 보면 자동으로 모듈이 추가된 것을 볼 수 있습니다.
  • 생성 된 블로그 모듈 파일은 다음과 같습니다.
// /blog-backend/src/blog/blog.module.ts

import { Module } from '@nestjs/common';
@Module({})
export class BlogModule {}

 

  • 이 자습서의 뒷부분에서 필요한 내용으로 이 BlogModule을 업데이트합니다.

Nest.js 서비스 및 컨트롤러 생성

  • 여기에서는 공급자라고도 하는 서비스를 생성 한 후 응용 프로그램의 모든 HTTP 요청을 처리하는 컨트롤러를 만듭니다.
  • Nest.js의 서비스는 특정 목적을 위해 복잡한 비즈니스 로직을 처리하고 적절한 응답을 컨트롤러에 반환하기위한 것입니다.

서비스 생성

  • 프로젝트 디렉토리 내에있는 동안 다음 명령을 실행하여 새 서비스 파일을 생성하십시오.
nest generate service blog

 

  • 여기서 주목할 것은 위의 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<Post>) { }

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

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

  async getPosts(): Promise<Post[]> {
    const posts = await this.postModel.find().exec();
    return posts;
  }
} 

 

  • 이 파일에서는 먼저 @nestjs/common, mongoose 및 @nestjs/mongoose에서 필수 모듈을 가져 왔습니다.
  • 또한 Post라는 인터페이스와 데이터 전송 객체 CreatePostDTO를 가져 왔습니다.
  • constructor에서 @InjectModel( 'Post')을 추가하여 Post 모델을이 BlogService 클래스에 삽입합니다.
  • 이를 통해 이제 이 주입 된 모델을 사용하여 모든 게시물을 검색하고 단일 게시물을 가져 오며 다른 데이터베이스 관련 활동을 수행 할 수 있습니다.

 

  • 다음으로 addPost(), getPost()getPosts() 메소드를 작성하여 새 게시물을 추가하고 단일 게시물을 검색하고 데이터베이스에서 모든 게시물을 각각 가져옵니다.

 

  • 마지막으로 이 파일 내에서 작성된 게시물을 편집하고 삭제하려면 여기에 표시된대로 getPosts() 메소드 바로 다음에 다음을 추가해야합니다.

 

// /blog-backend/src/blog/blog.service.ts
...
@Injectable()
export class BlogService {
  ...
  async editPost(postID, createPostDTO: CreatePostDTO): Promise<Post> {
    const editedPost = await this.postModel
      .findByIdAndUpdate(postID, createPostDTO, { new: true });
    return editedPost;
  }
  async deletePost(postID): Promise<any> {
    const deletedPost = await this.postModel
      .findByIdAndRemove(postID);
    return deletedPost;
  }
} 

 

  • 위에서 생성 된 모든 방법은 백엔드 API에서 MongoDB 데이터베이스와의 적절한 상호 작용을 용이하게합니다.
  • 이제 프런트 엔드 클라이언트의 HTTP 호출을 처리 할 필수 경로를 만들 수 있습니다.

새로운 컨트롤러 생성

  • Nest.js의 컨트롤러는 애플리케이션 프론트 엔드에서 들어오는 HTTP 요청을 수신하고 적절한 응답을 리턴합니다.
  • 이를 통해 대부분의 비즈니스 로직이 서비스로 추상화되어 컨트롤러가 확장되지 않습니다.

 

  • 이전에 서비스를 작성 했으므로 여기서 blog-backend 프로젝트 디렉토리에있는 동안 다음 명령을 실행하여 nest 명령을 사용하여 새 제어기 파일을 생성합니다.
nest generate controller blog

 

 

  • 앞의 명령은 src/blog 디렉토리 내에 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, Put, Query, 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) { }

  // Submit a 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,
    });
  }

  // Fetch a particular post using ID
  @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);
  }

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

 

  • 위의 코드 스니펫에서 @nestjs/common 모듈의 HTTP 요청을 처리하는 데 필요한 모든 모듈을 가져 왔습니다.
  • 그런 다음 BlogService, CreatePostDTOValidateObjectId의 세 가지 새 모듈을 가져 왔습니다.
  • 다음 섹션에서 ValidateObjectId 모듈을 작성합니다.

 

  • 앞서 BlogService에서 선언 된 모든 함수에 액세스하려면 생성자를 통해 컨트롤러에 삽입했습니다.
  • 이는 효율성을 높이고 애플리케이션의 모듈성을 향상시키기 위해 Nest.js에서 사용되는 종속성 주입으로 간주되는 패턴입니다.
  • 마지막으로 다음과 같은 비동기 메소드를 작성했습니다.
    • getPosts():  이 메소드는 클라이언트로부터 HTTP GET 요청을 수신하는 기능을 수행하여 데이터베이스에서 모든 게시물을 가져온 다음 적절한 응답을 리턴합니다. @Get ( 'posts')로 데코레이트 되어 있습니다.
    • getPost(): postID를 매개 변수로 사용하여 데이터베이스에서 단일 게시물을 가져옵니다.  이 메소드에 전달 된 postID 매개 변수 외에도 ValidateObjectId()라는 추가 메소드가 추가 된 것을 깨달았습니다. 이 메소드는 Nest.js에서 PipeTransform 인터페이스를 구현합니다. 이는 데이터베이스에서 postID 매개 변수를 찾을 수 있는지 확인하고 확인하는 것이 목적입니다. 다음 세션에서 이 메소드를 정의합니다.
    • addPost(): 이 메소드는 데이터베이스에 새 게시물을 추가하기 위해 POST HTTP 요청을 처리합니다.

 

  • 특정 게시물을 편집하고 삭제하려면 blog.controller.ts 파일에 두 가지 메소드을 추가하십시오.
  • 이를 위해 editPost()deletePost() 메소드를 이전에 동일한 파일에 추가 한 addPost() 메소드 바로 뒤에 붙여 넣으십시오.
// /blog-backend/src/blog/blog.controller.ts
...
@Controller('blog')
export class BlogController {
  ...
  // Edit a particular post using ID
  @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 a post using ID
  @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(클래스)와 마찬가지로 여기에 정의한 각 비동기(async) 메서드에는 메타 데이터 데코레이터가 있으며 Nest.js가 라우팅 메커니즘으로 사용하는 접두사를 사용합니다.
  • 어떤 컨트롤러가 어떤 요청을 받고 요청을 처리하고 응답을 반환해야하는 메소드를 가리키는 지 제어합니다.

 

  • 예를 들어, 이 섹션에서 작성한 BlogController에는 접두사 blog와 접두사 post를 사용하는 getPosts()라는 메소드가 있습니다.
  • 이는 blog/posts 엔드 포인트 (http:localhost:3000/blog/posts)로 전송 된 모든 GET 요청은 getPosts() 메소드에 의해 처리됨을 의미합니다.
  • 이 예제는 다른 메소드가 HTTP 요청을 처리하는 방법과 유사합니다.

Validation for Mongoose with Pipes

  • blog 디렉토리로 이동하여 shared라는 새 폴더를 작성하십시오.
  • 이제 새로 작성된 폴더 내에 다른 폴더를 작성하고 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<string> {
  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 메소드를 구현합니다.
  • 매개 변수로 value를 취하는 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 { BlogService } from './blog.service';
import { BlogController } from './blog.controller';
import { MongooseModule } from '@nestjs/mongoose'; // add this
import { BlogSchema } from './schemas/blog.schema'; // and this

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

 

  • 이 모듈은 MongooseModule.forFeature() 메소드를 사용하여 모듈에 등록 할 모델을 정의합니다.
  • 이것이 없으면 @injectModel() 데코레이터를 사용하여 BlogService 내에 PostModel을 주입해도 작동하지 않습니다.

인증 없이 테스트

  • 터미널로 돌아가서 프로젝트 디렉토리 내에 있는 동안 터미널에서 다음 명령을 실행하여 애플리케이션을 테스트하십시오.
npm run start:dev

 

  • 앞의 명령은 응용 프로그램이 계속 실행되는 동안 새로운 변경 사항을 추적하기 위해 응용 프로그램을 감시 모드로 실행합니다.

 

참고 : 앞에서 언급 한대로 다른 터미널에서 MongoDB 인스턴스가 계속 실행 중인지 확인하십시오. 그렇지 않으면 다른 터미널을 열고 sudo mongod를 실행하여 백그라운드에서 MongoDB 프로세스를 시작하십시오. Postman을 사용하여 API를 테스트 할 수 있습니다. Postman은 프로덕션에 배포하기 전에 웹 서비스의 동작을 확인하고 확인하는 테스트 도구입니다.

응용 프로그램을 사용하여 게시물 작성

  • 여기에 표시된대로 블로그 게시물의 세부 사항과 함께 http://localhost:5000/blog/post 엔드 포인트에 POST HTTP 호출이 작성되었습니다.
  • 성공적인 프로세스 후 작성된 작성된 게시물이 작성되었음을 나타내는 메시지와 함께 응답으로 리턴되었습니다.

View post

  • 위의 스크린 샷에서 백엔드 API에 대해 구현 된 모든 논리가 올바르게 작동하는 것이 분명하지만 다른 문제가 발생합니다.
  • 임의의 사용자는 API 호출을 쉽게 만들어 인증없이 새 게시물을 검색하거나 작성하여 성공할 수 있습니다.
  • 응용 프로그램이 사용자의 신원을 관리하기에 충분히 똑똑해야하므로 이는 허용되지 않습니다.

 

  • API를 보호하려면 먼저 Auth0 계정이 필요합니다 (아직없는 경우 새 계정 생성).
    • 하하하... 약을 팔기 시작하네요.
    • 지금부터 이하 내용는 정리하지 않겠습니다.
    • OAuth2.0 서버 정도는 어떻게든 직접 운영하는 게 좋다고 생각합니다.
    • 쭈욱 따라서 살펴보니, Nest js가 더욱 마음에 드네요. Node 계의 스프링 프레임워크라고 말해도 되겠네요.

'Node > Nest Js' 카테고리의 다른 글

Nest js 모델-뷰-컨트롤러  (0) 2020.01.31
Nest js Providers  (0) 2020.01.30
Nest Js 컨트롤러  (0) 2020.01.28
Nest Js 첫걸음  (0) 2020.01.28
Nest js 소개  (0) 2020.01.27
블로그 이미지

_김은찬

두번 다시는 꺾이지 않으리

,