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.ts 및 blog.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, CreatePostDTO 및 ValidateObjectId의 세 가지 새 모듈을 가져 왔습니다.
- 다음 섹션에서 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 |