Layered Architecture Pattern - Controller

윤태규·2024년 1월 16일

01. 컨트롤러 (Controller)

  • 1) 프레젠테이션 계층(Presentation Layer) 이란? 💡 **프레젠테이션 계층(Presentation Layer)**은 **3계층 아키텍처 패턴**에서 **가장 먼저 클라이언트의 요청(Request)**을 만나게 되는 계층이며, 대표적으로 **컨트롤러(Controller)**가 이 역할을 담당합니다. - **하위 계층(서비스 계층, 저장소 계층)**에서 발생하는 **예외(Exception)**를 처리 합니다. - 클라이언트가 전달한 데이터에 대해 **유효성을 검증**하는 기능을 수행합니다. → 이전에 **Joi** 라이브러리를 이용한 유효성 검사가 기억나시죠? 😉 - 클라이언트의 **요청**을 처리한 후 서버에서 처리된 결과를 **반환(Response)**합니다.
  • 2) 컨트롤러(Controller) 란? 💡 **컨트롤러(Controller)**란 클라이언트의 **요청(Request)**을 처리하고, 서버에서 처리된 **결과**를 **반환(Response)**하는 **역할**을 담당합니다. **컨트롤러(Controller)**는 추가적으로 아래의 역할을 담당합니다. - **클라이언트의 요청(Request)을 수신합니다.** - **요청(Request)에 들어온 데이터 및 내용을 검증합니다.** - **서버에서 수행된 결과를 클라이언트에게 반환(Response)합니다.**
  • 3) Express로 구현하는 컨트롤러 !https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9ab055dc-a05c-475b-9ca1-f7b986983024/Untitled.png 📌 저희는 이전 챕터에서 배운 내용을 바탕으로 **컨트롤러(Controller)**를 구현할 것입니다. 프로젝트를 시작하기에 앞서 **3계층 아키텍처** 프로젝트에서 어떤 **API**를 만들지 확인해보겠습니다. - **📚  [3계층 아키텍처] 게시글 API 명세서** [제목 없는 데이터베이스](https://www.notion.so/7c4fd196c43d4296aa17e44d7a4a0f93?pvs=21) **Express**에서는 **컨트롤러**와 **라우터(Router)**를 연결하기 위해서는 `express.Router`를 사용하여, 라우터가 클라이언트의 **요청(Request)**에서 특정 **URI**와 **HTTP Method**를 전달받았을 때 **컨트롤러의 특정 메서드**로 요청된 내용을 전달하도록 구현해야합니다. 그렇기 때문에 `routes` 폴더에서 `posts.router.js` 라는 파일을 만들어 `PostsConrtoller`와 연결하도록 구성해보겠습니다! 🙂 - **[코드 스니펫] 3계층 아키텍처 - `routes/posts.router.js`** ```jsx // src/routes/posts.router.js import express from 'express'; import { PostsController } from '../controllers/posts.controller.js'; const router = express.Router(); // PostsController의 인스턴스를 생성합니다. const postsController = new PostsController(); /** 게시글 조회 API **/ router.get('/', postsController.getPosts); /** 게시글 작성 API **/ router.post('/', postsController.createPost); export default router; ``` - **✅ `router.get('/', postsController.getPosts);` 코드 추가 설명** ✅ `router.get`은 저희가 **Express**를 이용하여 **API**를 만들때 매번 사용했던 코드에요! 이 메서드는 `/` URI에 대한 GET 메서드 요청이 들어올 경우, `postsController.getPosts`를 호출하라는 의미입니다. 즉, 클라이언트의 요청이 들어오면, `PostsController` 클래스에서 정의된 `getPosts` 메서드를 실행하도록 라우터를 설정한 것입니다. **그 결과, 저희는 Post에 해당하는 컨트롤러와 라우터를 연결하게 되었습니다! 😆** 저희는 `posts.router.js` 파일을 통해 **컨트롤러**와 **라우터**를 **연결**하였으니, 다음 단계로 `posts.controller.js` 파일을 작성하여 **Post**의 **컨트롤러**를 구현해보도록 하겠습니다! - **[코드 스니펫] 3계층 아키텍처 - `controllers/posts.controller.js`** ```jsx // src/controllers/posts.controller.js import { PostsService } from '../services/posts.service.js'; // Post의 컨트롤러(Controller)역할을 하는 클래스 export class PostsController { postsService = new PostsService(); // Post 서비스를 클래스를 컨트롤러 클래스의 멤버 변수로 할당합니다. getPosts = async (req, res, next) => { try { // 서비스 계층에 구현된 findAllPosts 로직을 실행합니다. const posts = await this.postsService.findAllPosts(); return res.status(200).json({ data: posts }); } catch (err) { next(err); } }; createPost = async (req, res, next) => { try { const { nickname, password, title, content } = req.body; // 서비스 계층에 구현된 createPost 로직을 실행합니다. const createdPost = await this.postsService.createPost( nickname, password, title, content, ); return res.status(201).json({ data: createdPost }); } catch (err) { next(err); } }; } ``` - **✅ `await this.postsService.findAllPosts();` 코드 추가 설명** `await this.postsService.findAllPosts();` 는 `PostsController` 클래스의 `postService` 인스턴스에서 `findAllPost` 메서드를 호출합니다. 컨트롤러는 **하위 계층**의 **내부 구조**에 대해신경쓰지 않습니다. 대신, **외부**에 공개된 **메서드**를 **호출**하기만 합니다. 이것이 가능한 이유는 **추상화(Absctraction)**의 특성 덕분입니다. `PostsController` 클래스는 전달된 **요청(Request)**을 처리하기 위해 `PostsService`를 호출하도록 구현하였습니다. 여기서 **컨트롤러**가 **비즈니스 로직**을 직접 수행하지 않고, **클라이언트**의 **요청**을 **서비스 계층**으로 바로 전달 하도록 구현한 것을 확인 할 수 있습니다. 😊 결국, `PostController` 클래스는 **클라이언트**의 **요청(Request)**을 **서비스 계층**으로 **전달**하는 역할을 수행하며, **서비스 계층**이 어떠한 내부 구조를 통해 **비즈니스 로직**을 수행하는지는 **상위 계층**인 **컨트롤러**에게는 중요하지 않습니다. 💪 이렇게 각 계층이 **자신의 역할에만 집중**할 수 있게 되며, **다른 계층의 세부사항**에 대해서는 알 필요가 없어지게 되는 것이죠.😉
profile
끝까지 가자

0개의 댓글