정보실

웹학교

정보실

Reactjs Nest.js, React, TypeScript 및 MongoDB를 사용한 최신 풀 스택 개발 : 1 부

본문

React, TypeScript 및 Nest.js를 사용하여 현대적이고 안전한 Full-Stack 애플리케이션을 구축하는 방법을 알아보십시오.


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



TL; DR :이 시리즈에서는 React 및 Nest.js를 사용하여 최신 웹 애플리케이션을 빌드 하는 방법을 학습합니다. 

결국, Auth0으로 애플리케이션을 보호하는 방법도 배우게 됩니다. 

JavaScript를 사용하여 React 애플리케이션을 빌드 하는 대신 약간 벗어나서 TypeScript를 사용합니다.


이러한 방식으로 응용 프로그램을 구성하면 유형 확인, 적용 및 응용 프로그램의 모든 변수를 데이터 유형과 관련이 있는 것과 같은 많은 이점이 있습니다. 

이 시리즈의 첫 번째 부분에서는 Nest.js로 백엔드 API를 작성하는 데 중점을 둘 것입니다.

두 번째 부분은 사용자 인터페이스를 구축하고 React를 사용하여 모든 프론트 엔드 로직을 처리하는 것입니다. 

두 번째 부분은 여기에서 찾을 수 있습니다. 

이 시리즈 전체에서 개발 된 완전한 소스 코드는 코드를 직접 살펴 보려는 경우 이 GitHub 리포지토리에서 찾을 수 있습니다.


전제 조건 


React를 사용하여 웹 애플리케이션을 빌드 하는 데 대한 기본 지식과 이전 경험을 통해 이 시리즈를 최대한 활용할 수 있습니다. 

필수는 아니지만 TypeScript에 대해 몇 가지 알아야 합니다. 

모든 사람들이 쉽게 따라 할 수 있도록 복잡한 구현을 세분화하려고 노력할 것입니다.


또한 개발 머신에 Node.js 및 Yarn 패키지 관리자가 설치되어 있는지 확인해야 합니다. 아직 설치하지 않은 경우 여기 지침에 따라 Yarn 패키지 관리자에 Node.js를 올바르게 설치하는 방법을 알아보십시오.


또한 컴퓨터에 MongoDB가 설치되어 있어야 합니다. 여기에 나오는 지침에 따라 원하는 운영 체제를 다운로드하여 설치하십시오.

MongoDB를 성공적으로 설치하려면 Mac에서 Homebrew를 사용하거나 MongoDB 웹 사이트에서 다운로드하여 설치할 수 있습니다.


이 학습서는 개발을 위해 macOS 시스템을 사용합니다. 다른 운영 체제를 사용하는 경우 첫 번째 단계에서 npm 명령에 sudo를 사용해야 할 수도 있습니다.


소개 


Nest.js는 효율적이고 안정적이며 확장 가능한 서버 측 애플리케이션을 빌드하기 위한 모듈 식 아키텍처를 갖춘 진보적인 Node.js 프레임 워크입니다. 

TypeScript로 완전히 구축되었지만 여전히 JavaScript와의 호환성을 유지하고 최신 JavaScript 기능을 활용합니다. 

Node.js 개발 환경에 디자인 패턴과 성숙한 솔루션을 제공합니다.


Angular 응용 프로그램의 구조에 정통한 경우 Nest.js를 사용하는 것이 더 편할 것입니다. Nest.js를 처음 사용하는 경우 Nest.js에서 Node.js 및 Express에 TypeScript를 가져 오는 이 기사를 확인하여 Nest.js의 주요 개념에 익숙해 지십시오.


React는 직관적 인 대화 형 사용자 인터페이스를 구축하기 위한 오픈 소스 JavaScript 프론트 엔드 프레임 워크입니다. 단일 페이지 응용 프로그램의 빠른 개발에서 뛰어난 성능과 단순성으로 인해 널리 채택되고 개발자들에게 최고의 선택입니다.

이 React 튜토리얼에서 React의 작동 방식과 주요 개념을 익히십시오. 첫 번째 앱 구축 및 보안 


MongoDB는 스키마가 없는 NoSQL 데이터베이스로 JSON과 같은 문서로 데이터를 수신하고 저장할 수 있습니다. 

데이터베이스 테이블을 행과 열로 생각하고 시각화 하는 아이디어를 제거합니다. 

JSON 형식으로 JavaScript 응용 프로그램을 빌드 하여 생산성을 높일 수 있으므로 JavaScript 개발자에게는 이상하지 않습니다. 

배열 및 중첩 객체 값을 지원하며 유연하고 동적 인 스키마를 허용합니다. 

데이터 간의 관계를 관리하고 스키마 유효성 검사를 제공하는 ODM (Object Data Modeling) 라이브러리 인 Mongoose와 함께 자주 사용됩니다.


"MongoDB를 사용하면 JSON 형식으로 JavaScript 애플리케이션을 빌드 하여 생산성을 높일 수 있습니다."


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


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


TypeScript를 사용하여 반응 형 응용 프로그램을 구축해야 하는 이유 


아시다시피, React는 컴포넌트 기반 프론트 엔드 프레임 워크이며 여기 저기에서 props 및 state 객체를 사용합니다. TypeScript를 사용하여 React 애플리케이션을 빌드 하면 잘 정의되고 식별 가능한 prop 및 state 객체가 있는 강력한 유형의 컴포넌트를 가질 수 있습니다. 

이렇게 하면 컴파일러에서 구성 요소의 사용을 유형 확인하고 시간에 오류를 발견 할 수 있습니다.


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


"React는 컴포넌트 기반 프론트 엔드 프레임 워크입니다."


무엇을 만들 것인가 


사용자가 다음을 수행 할 수 있는 블로그 애플리케이션을 빌드 하려고 합니다.

  • 새 게시물을 작성하고 저장하십시오.
  • 홈페이지에서 새로 저장된 게시물 및 다른 모든 생성 된 게시물을 봅니다.
  • 게시물 편집 및 삭제와 같은 프로세스를 수행하십시오.

또한 데이터베이스에 데이터를 유지하기 위해 MongoDB를 사용하게 됩니다. 

다음은 이 학습서 끝에서 예상되는 내용의 미리보기입니다.


View of final blog that is built 

이 응용 프로그램을 통해 사용자는 인증 및 권한이 부여 된 경우에만 블로그 게시물을 작성할 수 있습니다. 

그렇지 않으면 인증 된 사용자 만 작성된 게시물을 볼 수 있습니다. 

사용자의 인증 및 권한 부여는 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를 사용하여 프로젝트를 작성합니다.


다음 명령을 실행하여 CLI를 설치하십시오.


npm install -g @nestjs/cli 


프로세스가 완료되면 다음 명령을 실행하여 Nest CLI가 설치되었는지 확인하십시오.


nest --version 


컴퓨터에 설치된 버전을 나타내는 다음과 유사한 출력이 표시됩니다.


6.6.4 


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


여기에 표시된 대로 nest 명령을 사용하여 이 학습서를 위한 새 프로젝트를 작성하십시오.


nest new blog-backend 


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


Terminal view of installing Nest.js 

로컬 개발 폴더 내의 블로그 백엔드 디렉토리에 새 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으로 이동하면 응용 프로그램이 실행되는 것을 볼 수 있습니다.


Hello World view of app 

이 섹션에서는 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 디렉토리를 작성하십시오. 

이제 처음 작성된 블로그 디렉토리 내에 schema라는 서브 디렉토리를 작성하십시오.


이 새 디렉토리에는 응용 프로그램에 필요한 모든 데이터베이스 스키마가 있습니다. 

이제 스키마 파일을 작성하고 이를 blog.schema.ts라고 하고 이를 schemas 폴더에 저장하십시오. 

이 파일을 열고 그 안에 다음 내용을 추가하십시오.


// 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 클래스의 각 개별 속성에 데이터 유형의 문자열이 있고 불필요한 돌연변이를 피하기 위해 읽기 전용으로 표시했습니다.


블로그 모듈 만들기 


Nest.js의 모듈은 @Module () 데코레이터로 주석이 달린 클래스입니다. 

응용 프로그램 구조를 체계적으로 유지하는 데 도움이 됩니다. 

Nest.js는 각 애플리케이션에 적어도 하나의 모듈 (대부분 루트 모듈)이 있어야 합니다. 

이를 고려하여 nest 명령을 사용하여 응용 프로그램에 대한 모듈을 생성합니다. 

그렇게 하려면, 여전히 blog-backend 디렉토리 안에 있는지 확인하고 다음 명령을 실행하십시오 :


nest generate module blog 


위의 명령은 애플리케이션에 대해 blog.module.ts라는 새 모듈을 생성하고 새로 작성된 BlogModule을 자동으로 가져 와서 해당 모듈에 대한 루트 모듈을 업데이트합니다. 

이를 통해 Nest.js는 응용 프로그램 내에서 루트 모듈 외에 다른 모듈을 인식합니다. 

생성 된 블로그 모듈 파일은 다음과 같습니다.


// /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를 가져 왔습니다. 

생성자에서 @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 요청을 수신하고 적절한 응답을 리턴합니다. 

이를 통해 대부분의 비즈니스 로직이 서비스로 추상화 되어 컨트롤러가 확장되지 않습니다.


이전에 서비스를 작성 했으므로 여기서 블로그 백엔드 프로젝트 디렉토리에 있는 동안 다음 명령을 실행하여 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와 마찬가지로 여기에 정의한 각 비동기 메서드에는 메타 데이터 데코레이터가 있으며 Nest.js가 라우팅 메커니즘으로 사용하는 접두사를 사용합니다. 

어떤 컨트롤러가 어떤 요청을 받고 요청을 처리하고 응답을 반환해야 하는 메소드를 가리키는 지 제어합니다.


예를 들어,이 섹션에서 작성한 BlogController에는 접 두부 blog와 접 두부 post를 사용하는 getPosts ()라는 메소드가 있습니다. 

이는 블로그 / 포스트 엔드 포인트 (http : localhost : 3000 / blog / posts)로 전송 된 모든 GET 요청은 getPosts () 메소드에 의해 처리됨을 의미합니다. 

이 예제는 다른 메소드가 HTTP 요청을 처리하는 방법과 유사합니다.


파이프가 있는 몽구스 검증 


블로그 디렉토리로 이동하여 shared라는 새 폴더를 작성하십시오. 

이제 새로 작성된 폴더 내에 다른 폴더를 작성하고 파이프 이름을 지정하십시오. 

마지막으로, 새로 작성된 폴더 내에 새 파일을 작성하고 이름을 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 메소드를 구현합니다. 

여기에는 매개 변수로 postID를 사용하는 transform ()이라는 단일 메서드가 있습니다. 

위의 방법을 사용하면 데이터베이스에서 찾을 수없는 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은 프로덕션에 배포하기 전에 웹 서비스의 동작을 확인하고 확인하는 테스트 도구입니다.


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


Postman Post Test 

여기에 표시된 대로 블로그 게시물의 세부 사항과 함께 http : // localhost : 5000 / blog / post 엔드 포인트에 POST HTTP 호출이 작성되었습니다. 

성공적인 프로세스 후 작성된 작성된 게시물이 작성되었음을 나타내는 메시지와 함께 응답으로 리턴 되었습니다.


View post 


Postman Get Test 

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

응용 프로그램이 사용자의 신원을 관리하기에 충분히 똑똑해야 하므로 이는 허용되지 않습니다.


API를 보호하려면 먼저 Auth0 계정이 필요합니다 (아직 없는 경우 새 계정 생성).


Auth0으로 Nest.js 보안 및 사용자 ID 관리 


계정을 생성 한 후 계정에 로그인하여 Auth0 관리 대시 보드의 API 섹션으로 이동하여 사이드 메뉴에서 API를 선택하십시오. 

계정에 대한 API를 만든 경우 API 목록이 표시되지만 이 자습서에서는 API 생성 버튼을 클릭하고 새 API를 설정하십시오. 

다음으로 API에 적합한 이름을 입력하십시오. 

식별자를 http : // localhost : 5000 / api로 설정하십시오. 

액세스 토큰을 구성 할 때 나중에 대상으로 사용됩니다. 

완료되면 서명 관점 알고리즘은 보안 관점에서 가장 좋은 옵션이므로 RS256으로 그대로 두고 CREATE 버튼을 클릭하여 계속하십시오.


Auth0 Create New API 


이 API를 생성하자마자 Auth0은 사용할 테스트 응용 프로그램을 자동으로 생성했습니다. 

이 자습서는 이 부분의 테스트 목적으로 만 사용할 기계 간 응용 프로그램입니다. 

학습서의 다음 부분에서 프론트 엔드 React 앱을 나타내는 새 단일 페이지 애플리케이션을 작성합니다.


그런 다음 사이드 메뉴에서 "응용 프로그램"을 클릭하여 계정의 응용 프로그램 목록을 보고 생성 된 테스트 응용 프로그램을 선택하십시오. 

그런 다음 "설정"탭을 클릭하십시오.


이제 허용 된 콜백 URL 필드를 찾아 http : // localhost : 3000을 값으로 추가하십시오. 

이것은 이 시리즈의 다음 부분에서 유용 할 것입니다. 이제 변경 사항을 저장하여 계속 진행할 수 있습니다. 

API를 구성하려면 곧 도메인, 클라이언트 ID 및 클라이언트 시크릿을 복사해야 합니다.


Nest.js 인증 미들웨어 정의 


API가 제공하는 일부 리소스에 액세스하기 전에 경로를 보호하고 모든 사용자가 인증되도록 하려면 Auth0을 사용합니다.


이것이 작동하는 방식은 Auth0에 의해 사용자가 인증되면 해당 사용자가 API 호출을 수행 할 수 있도록 액세스 토큰이 생성된다는 것입니다. 

Auth0에서 발행 한 생성 된 JWT 토큰을 확인하기 위해 express-jwt에서 제공 한 Express 미들웨어를 사용합니다.


실행 중인 경우 애플리케이션을 중지하고 다음 라이브러리를 설치하십시오.


npm install express-jwt jwks-rsa dotenv 



위의 라이브러리에는 .env 파일에서 변수를 로드 하는 dotenv 모듈이 포함되어 있습니다.


Auth0에서 응용 프로그램의 도메인과 같은 자격 증명을 쉽게 액세스하고 참조하려면 응용 프로그램 루트 내에 .env를 만들고 다음 내용을 붙여 넣습니다.


AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN AUTH0_AUDIENCE=http://localhost:5000/api 


Auth0 대시 보드에서 얻은 YOUR_AUTH0_DOMAIN을 적절한 자격 증명으로 바꾸십시오.


보호 된 엔드 포인트에 대한 모든 호출이 액세스 토큰으로 식별 되도록 인증 미들웨어를 구성하려면 src 디렉토리 내에 common이라는 폴더를 작성하십시오. 

그런 다음 authentication.middleware.ts라는 새 파일을 작성하십시오. 

새로 만든 파일에 다음을 붙여 넣습니다.


// blog-backend/src/common/authentication.middleware.ts import { Injectable, NestMiddleware } from '@nestjs/common'; import * as jwt from 'express-jwt'; import { expressJwtSecret } from 'jwks-rsa'; import { Request, Response } from 'express'; import * as dotenv from 'dotenv'; dotenv.config(); @Injectable() export class AuthenticationMiddleware implements NestMiddleware { use(req: Request, res: Response, next: Function) { jwt({ secret: expressJwtSecret({ cache: true, rateLimit: true, jwksRequestsPerMinute: 5, jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`, }), issuer: `https://${process.env.AUTH0_DOMAIN}/`, algorithm: ['RS256'], })(req, res, (err) => { if (err) { const status = err.status || 500; const message = err.message || 'Sorry we were unable to process your request.'; return res.status(status).send({ message, }); } next(); }); } } 


이 코드는 요청에 포함 된 액세스 토큰이 유효한지 확인합니다. 

토큰이 유효하지 않은 경우 사용자에게 권한 부여 토큰이 유효하지 않다는 메시지가 표시됩니다.


그런 다음 blog.module.ts 파일로 다시 이동하여 다음과 같이 파일을 업데이트하십시오.


import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common'; import { BlogService } from './blog.service'; import { BlogController } from './blog.controller'; import { MongooseModule } from '@nestjs/mongoose'; import { BlogSchema } from './schemas/blog.schema'; import { AuthenticationMiddleware } from 'src/common/authentication.middleware'; @Module({ imports: [ MongooseModule.forFeature([{ name: 'Post', schema: BlogSchema }]), ], // add this providers: [BlogService], controllers: [BlogController] }) export class BlogModule implements NestModule { configure(consumer: MiddlewareConsumer): MiddlewareConsumer | void { consumer.apply(AuthenticationMiddleware).forRoutes( { method: RequestMethod.POST, path: '/blog/post' }, { method: RequestMethod.PUT, path: '/blog/edit' }, { method: RequestMethod.DELETE, path: '/blog/delete' } ) } } 



이 구현을 사용하면 다음 경로에 대한 액세스 토큰이 없는 후속 요청은 응용 프로그램에서 허용되지 않습니다.

  • GET /blog/post
  • PUT /blog/edit
  • DELETE /blog/delete

이를 테스트하려면 npm run start : dev 및 sudo mongod를 각각 사용하여 애플리케이션 및 MongoDB 인스턴스를 다시 시작하십시오. 

그런 다음 Postman에서 http 요청을 http : // localhost : 5000 / blog / post로 보내십시오. 

아래 이미지에 표시된 대로 응답이 표시됩니다.


Postman Post with no authorization token found 


이 시리즈의 다음 부분에서는 Auth0에 의해 인증되면 즉시 액세스 토큰을 생성 할 수 있습니다. 

그러나 개념 증명으로 Auth0 계정 관리 대시 보드에서 API에 대한 테스트 액세스 토큰을 얻을 수 있습니다. 

Auth0 대시 보드에서 API 섹션에 액세스하고 이전에 작성된 API를 클릭하십시오.


Nest API View on Auth0 

이제 테스트 탭을 클릭하고 아래로 스크롤하여 응답 자막 아래에 표시된 액세스 토큰을 복사하십시오.


그런 다음 Postman을 열고 Authorization 탭에서 Bearer Token을 선택하고 액세스 토큰을 붙여 넣습니다.


Postman - Bearer Token being added 


Postman을 사용하여 모든 엔드 포인트 테스트 


이제 모든 보호 된 엔드 포인트에 액세스 할 수 있습니다.


Postman Success 

결론 


이 학습서에서는 Nest.js를 사용하여 API를 빌드 한 후 MongoDB를 사용하여 데이터베이스에 데이터를 보존 할 수 있었습니다. 

Auth0에서 발행 한 JWT (JSON Web Token)를 확인하고 확인하여 애플리케이션으로 일부 엔드 포인트를 보호하기 위해 추가로 진행했습니다.


이 시리즈의 첫 번째 부분이며 두 번째 부분에서 React 및 TypeScript를 사용하여 사용자 인터페이스를 설정하고 프런트 엔드 논리를 만듭니다.


Auth0 정보 


Auth0은 애플리케이션 빌더를 위한 최초의 ID 관리 플랫폼이며, 맞춤형 애플리케이션에 필요한 유일한 ID 솔루션입니다.

Auth0은 혁신자가 혁신 할 수 있도록 세계의 정체성을 확보하는 임무를 통해 모든 응용 프로그램에서 모든 대상을 위해 정체성을 확장 및 보호 할 수 있는 단순성, 확장 성 및 전문성을 제공합니다. 

Auth0은 매일 1 억 회 이상의 로그인을 보호하여 기업이 전 세계 고객에게 신뢰할 수 있고 우아한 디지털 경험을 제공 할 수 있는 자신감을 제공합니다.



페이지 정보

조회 94회 ]  작성일20-02-09 14:44

웹학교