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.