3. Backend/NestJS / / 2024. 3. 12. 17:35

[코드팩토리 NestJS 강의] Service (서비스)

프로바이더로 NestJS에서 전형적으로 사용하는 Service에 대해 알아보도록 함

처음 NestJS폴더를 생성했을때, controller가 있거, module이 있고 service가 있다
이 3종류는 셋트같은 개념이다.

controller에서 구현을 다 했는데, 왜 service가 필요한것인가? controller와 service의 차이는?

controller같은 경우에 아키텍처라는 개념이 생김 아키텍처란? 좋은방법으로 코드를 쓰면, 실패하거나 협업이 어려운 일을 최소할 수 있다.

controller파일이 담당하는것은 말 그대로 가장 맨 앞에서 요청을 받는 역할을 함 = 최전방에서 요청이 어디로 가야 될지를 함수로 라우팅 해주는 역할을 함 = 컨트롤러는 오직 그 역할만 하고 그 역할에 포커스가 되어있어야함

NestJS에서 정의하는 controller는 로직을 컨트롤러 단위안에서 정의하지 말라고 써둠 긴 로직은 service파일에 정의하라고 함 service에 정의하고 controller에서는 service파일을 불러와서 사용하라고 이야기함

constructor(private readonly postsService: PostsService) {}

controller가 생성되면 당연히 service가 같이 생성이 되어야하고, controller에서는 로직을 작성하지않고 service파일에 정의 한 후 불러와 사용

  • 재활용성이 높아짐

서비스 파일은 컨트롤러에서 했던것처럼 특정 라우트에 대한 태그들이 없다(annotation안씀)

 

앞서 한꺼번에 작성했던거를 두 파일에 나눠 작성한 결과

// posts.controller.ts
/* eslint-disable prettier/prettier */
import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Post,
  Put,
} from '@nestjs/common';
import { PostsService } from './posts.service';

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

  // 1) GET /posts
  //    모든 post를 다 가져온다
  @Get()
  getPosts() {
    return this.postsService.getAllPosts();
  }
  // 2) GET /posts/:id
  //    id에 해당되는 post를 가져온다 => path parameter를 만들어야 함!!
  //    예를들어서 id=1일 경우 id가 1인 포스트를 가져온다
  @Get(':id')
  // :은 Param 이라는 뜻이라 id만 정의해주면 됨
  getPost(@Param('id') id: string) {
    return this.postsService.getPostById(+id);
  }

  // 3) POST /posts
  //    POST를 생성한다
  @Post()
  postPost(
    @Body('author') author: string, // 데이터를 body에서 받을건데, body안에 author라는 키 안에 있는 값을 author라는 string파라미터에 저장한다.
    @Body('title') title: string,
    @Body('content') content: string,
  ) {
    return this.postsService.createPost(author, title, content);
  }

  // 4) PUT /posts
  //    id에 해당되는 POST를 변경한다
  @Put(':id')
  putPost(
    @Param('id') id: string,
    // 변경하고 싶은 요소만 따로 받아서 요청을 보내면 되는데, 어떤요소를 변경하고싶은지 모름
    // 그래서 물음표를 붙여줘야함
    @Body('author') author?: string,
    @Body('title') title?: string,
    @Body('content') content?: string,
  ) {
    return this.postsService.updatePost(+id, author, title, content);
  }

  // 5) DELETE /posts/:id
  //    id에 해당되는 post를 삭제한다
  @Delete(':id')
  deletePost(@Param('id') id: string) {
    return this.postsService.deletePost(+id);
  }
}
//posts.service.ts
/* eslint-disable prettier/prettier */
import { Injectable, NotFoundException } from '@nestjs/common';

/**
 * id : number
 * authour : string
 * title : string
 * content : string
 * likeCount : number
 * commentCount : number
 */

export interface PostModel {
  id: number;
  author: string;
  title: string;
  content: string;
  likeCount: number;
  commentCount: number;
}

// let으로 설정한 이유 : 데이터를 추가,삭제,변경 할것이기 때문
let posts: PostModel[] = [
  {
    id: 1,
    author: 'newjeans_official',
    title: '뉴진스 민지',
    content: '메이크업 고치고 있는 민지',
    likeCount: 1000000,
    commentCount: 99999,
  },
  {
    id: 2,
    author: 'newjeans_official',
    title: '뉴진스 해린',
    content: '노래연습하고있는 해린',
    likeCount: 1000000,
    commentCount: 99999,
  },
  {
    id: 3,
    author: 'blackpink_official',
    title: '블랙핑크 로제',
    content: '종합운동장에서 공연중인 로제',
    likeCount: 1000000,
    commentCount: 99999,
  },
];

@Injectable()
export class PostsService {
  getAllPosts() {
    return posts;
  }

  getPostById(id: number) {
    const post = posts.find((post) => {
      post.id === +id;
    });

    // post가 없을때, Not Found Exception 던지기 (404 Not Found 에러)
    // 에러 반환하는 이유 : 아무것도 없는 값을 반환해주는것이아닌 문제가 있다는 실질적인 메세지를 전달하기 위함
    if (!post) {
      throw new NotFoundException();
    }
    return post; // (200 OK)
  }

  createPost(author: string, title: string, content: string) {
    // 생성할 포스트 데이터에 맞게 post 만듦
    const post: PostModel = {
      id: posts[posts.length - 1].id + 1,
      author,
      title,
      content,
      likeCount: 0,
      commentCount: 0,
    };

    // posts는 기존의 posts와 새로 만든 post를 넣는다.
    posts = [...posts, post];

    // 응답은 새로 만든 post만 반환한다.
    // 허용되는 정보 안에서 최소한의 데이터를 반환해주는것이 가장 좋다.
    // 최소한의 정보를 주되, 꼭 필요한 정보는 모두 담아서 반환을 해줘야함.
    // 이유 : 서버를 클라우드에 올리면 데이터를 얼마나 보냈냐에 따라서 과금을 함.
    return post; // (201 Created)
  }

  updatePost(
    postId: number,
    author?: string,
    title?: string,
    content?: string,
  ) {
    const post = posts.find((post) => post.id === postId);

    if (!post) {
      throw new NotFoundException();
    }
    if (author) {
      post.author = author;
    }
    if (title) {
      post.title = title;
    }
    if (content) {
      post.content = content;
    }

    posts = posts.map((prevPost) =>
      prevPost.id === +postId ? post : prevPost,
    );
    return post;
  }

  deletePost(postId: number) {
    // id가 없다면 NotFoundException를 던지는 로직
    const post = posts.find((post) => post.id === postId);
    if (!post) {
      throw new NotFoundException();
    }
    // id가 있으면 posts에 필터해서 삭제함
    posts = posts.filter((post) => post.id !== postId);
    // 삭제한 포스트의 id를 반환함
    return postId;
  }
}
728x90
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유