Post

API 계층별 역할

이번 글에서는 병원 문진(question) 목록을 조회하는 API를 수정하는 과정에서 공부한 것들을 기록한다. 라우터-컨트롤러-서비스-레포지토리-DB로 이어지는 구조를 기반으로, 각 계층이 어떤 역할을 했는지 살펴보겠다.


1. 라우터 (Router)

라우터는 클라이언트 요청을 받아서 적절한 컨트롤러로 전달하는 역할을 한다. 병원 문진 조회 API에서는 다음과 같은 경로로 설정했다.

1
router.GET("/admin/hospitalQuestion", adminHospitalController.GetHospitalQuestionList)

라우터는 HTTP GET 메서드를 통해 병원 ID를 쿼리 파라미터로 받아 컨트롤러로 전달한다.


2. 컨트롤러 (Controller)

컨트롤러에서는 라우터에서 받은 데이터를 서비스 계층으로 전달한다.

1
2
3
4
5
6
7
8
9
10
11
12
func (a adminHospitalController) GetHospitalQuestionList(c *gin.Context) {     
	appG := app.NewGin(c) // Gin 객체 생성    
	hospitalId := c.Query("hospitalId") // Query 파라미터에서 hospitalId 추출  
	// 서비스 계층 호출     
	questions, err := a.adminHospitalService.GetHospitalQuestionList(appG.Tx(), hospitalId)     
	if err != nil {         
		appG.Response(http.StatusInternalServerError, err.Error(), gin.H{})
		return     
	}      
	// 성공 응답     
	appG.Response(http.StatusOK, "success", questions) 
}

이 과정에서 데이터를 DTO(Data Transfer Object)로 바인딩해서 전달하기도 한다.

  • DTO: 데이터를 더 명확하고 가독성 좋은 구조로 전달하기 위해 사용하는 객체를 말한다. getter, setter를 가진다.

3. 서비스 (Service)

서비스 계층은 비즈니스 로직을 담당한다. 레포지토리 계층을 호출해 데이터베이스와 통신한다.

1
2
3
4
5
6
func (a adminHospitalService) GetHospitalQuestionList(tx *sql.Tx, hospitalId string) ([]multi.HospitalQuestionaire, error) {     
	if tx == nil {         
		return nil, fmt.Errorf("transaction connection is nil")     
	}     
	return a.adminHospitalRepository.GetHospitalQuestionList(tx, hospitalId) 
}

4. 레포지토리 (Repository)

레포지토리는 데이터베이스와의 직접적인 통신을 담당한다. 예시로 이 API에서는, SQL 쿼리를 통해 병원 ID에 해당하는 문진 데이터를 조회한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func (a adminHospitalRepository) GetHospitalQuestionList(tx *sql.Tx, hospitalId string) ([]multi.HospitalQuestionaire, error) {     
	query := 
	`     
	SELECT id, question_title, question_body, created_at     
FROM hospital_questionnaire     
WHERE hospital_id = ? AND deleted_at IS NULL;
	`     
	rows, err := tx.Query(query, hospitalId)     
	if err != nil {         
		return nil, err     
	}     defer rows.Close()      
	var questions []multi.HospitalQuestionaire     
	for rows.Next() {         
		var question multi.HospitalQuestionaire         
		if err := rows.Scan(&question.Id, &question.QuestionTitle, &question.QuestionBody, &question.CreatedAt); 
		err != nil {             
			return nil, err         
		}         
		questions = append(questions, question)     
	}     
	return questions, nil 
	}

정리

  • 컨트롤러: 요청과 응답을 처리한다.
  • 서비스: 비즈니스 로직을 담당한다.
  • 레포지토리: 데이터베이스와의 통신을 담당한다.
This post is licensed under CC BY 4.0 by the author.

Trending Tags