본문 바로가기
프로그래밍/Go

고 (Golang) | 이것만 알면 나도 개발 전문가 | Gin 을 이용한 CRUD RESTful API 개발 Part-2

by K-인사이터 2023. 3. 1.
반응형

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

 

 

안녕하세요

K-IN 입니다.

 

서론 

"이것만 알면 나도 개발 전문가" 시리즈입니다.

"Gin 을 이용한 CRUD RESTful API 개발 Part-2" 를 진행하겠습니다. 

 

Part-2 에서는 dotenv 파일을 로드하여 환경변수 정보를 불러오는 과정을 학습해보겠습니다. 

 

2023.03.01 - [Go] - 고 (Golang) | 이것만 알면 나도 개발 전문가 | Gin 을 이용한 CRUD RESTful API 개발 Part-1

 

고 (Golang) | 이것만 알면 나도 개발 전문가 | Gin 을 이용한 CRUD RESTful API 개발 Part-1

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다. 안녕하세요 K-IN 입니다. 서론 "이것만 알면 나도 개발 전문가" 시리즈입니다. 이번 시간에는 Gin Web Frame

k-in.tistory.com

 

 

 

Part-1 코드 내려 받기 

코드는 이전 시간에 작성한 코드에 이어서 진행하도록 하겠습니다. 아래의 링크에 접근하여 clone 후 코드를 내려 받아 주세요. 

아래 웹사이트에 방문하셔서 Clone 버튼을 눌러주세요

 

 

https://bitbucket.org/kinstory/gin-tutorial/src/part1/

 

Bitbucket

 

bitbucket.org

 

Viper 를 이용한 환경 변수 로드  

배포 시에 테스트, 개발 등의 다양한 stage 환경 별로 환경변수를 관리해야 합니다. 

이는 웹 어플리케이션의 가장 기본입니다. 

 

이전 시간에 config 폴더에서 환경 변수를 로드하여 관리한다고 안내 드렸습니다.

config 폴더에서 default.go 파일을 생성해주세요.

 

$ touch config/default.go

프로젝트 폴더 구조에 default.go 파일이 추가되었습니다.

 

dotenv 파일을 효율적으로 로드하기 viper 패키지를 사용하도록 하겠습니다. 

아래의 명령어로 viper 를 설치해주세요. 

go get github.com/spf13/viper

 

 

Listen 할 TCP 포트 환경 변수 설정 

viper 는 환경 변수(configuration)을 불러오는 역할을 합니다.

그리고 환경 변수 파일은 JSON, TOML, YAML, HCL, envfile, Java properties 포맷들을 모두 지원합니다. 

 

우선, Gin 웹 어플리케이션이 Listen 할 포트를 app.env 에 정의해보도록 하겠습니다. 

프로젝트 루트 폴더에 app.env 파일을 생성해주세요.

$ touch app.env

파일의 생성 위치는 아래의 그림을 참고해주세요. 

 

app.env 파일의 위치

app.env 파일에 PORT 라는 변수를 생성하고 8000 을 입력합니다.

Gin 웹 어플리케이션이 8000번 TCP 포트로 Listen 할 것을 의미합니다. 

또한, 향후에 CI/CD 를 구성하면서 배포할 Stage 별로 PORT 정보를 교체하여 웹 어플리케이션을 제어할 수 있습니다. 

PORT=8000

 

다음 차례는 default.go 파일입니다. viper 의 자세한 사용법은 그리 중요하지 않습니다. 

어차피 우리는 환경 변수를 로드하는데 쓰이기 때문에 기본 코드 Snippet 만 알고 있다면 편리하게 응용할 수 있습니다. 

 

 

  1. Config 타입을 정의하고 app.env 파일 설정과 맵핑되는 Port 필드를 설정합니다. struct 타입은 field 의 모음(collection)을 의미합니다.
  2. Port 변수는 PORT 환경변수와 맵핑되도록 설정이 필요합니다. 이럴때 사용하는 것이 Go 언어에서 제공하는 Tag 입니다. Tag 는 backtick 문자로 둘러쌓인 문자열입니다. 우리는 viper 에게 PORT 환경변수를 Port 에 맵핑하라고 지시해야 하므로 `mapstructure:"PORT"` Tag 를 설정하여 viper 에게 정보를 전달합니다. viper 는 내부적으로 https://github.com/mitchellh/mapstructure 를 통해 mapstructure Tag 를 지원합니다. 
  3. LoadConfig 함수를 정의하여 환경 변수의 경로(path string)를 입력 받고 정의한 Config 타입과 error 정보를 리턴하도록 합니다. 
  4. viper.AddConfigPath 함수는 Viper 가 config 파일을 검색할 경로를 추가하는 역할을 합니다. 여러 번 호출이 가능하기 때문에 환경 변수 파일이 분리된 경우에도 사용할 수 있습니다. 
  5. viper.SetConfigType 함수는 환경 변수 파일의 유형을 설정하는 역할을 합니다. 앞서 json, toml, yml 등의 다양한 포맷에 대해 Viper 가 지원한다고 말씀드렸습니다. "env" 타입을 입력해줍니다. 
  6. viper.SetConfigName 함수는 "app.env" 파일의 이름 영역을 의미합니다. 확장자 정보를 빼고 "app" 이름을 입력해주세요. 
  7. viper.AutomaticEnv 함수는 Viper 로 하여금 환경 변수들과 Config 타입의 필드를 자동으로 맵핑하도록 설정합니다. 
  8. viper.ReadInConfig 함수는 실제로 환경 설정 파일을 탐색하고 로드하는 역할을 합니다. 
  9. 불러온 환경 설정 파일의 정보를 struct 타입에 맵핑합니다. config Named Return 변수가 사용된 점과 Unmarshal 함수에 전달될 때 변수의 주소(&) 연산자를 이용하는 부분에 주의를 기울여주세요. 함수의 실행의 결과는 config 변수에 저장됩니다. (만약 config 변수가 어디에 있는지 모르시는 분은 해당 링크를 참고해주세요. https://go.dev/tour/basics/7 )
package config

import "github.com/spf13/viper"

type Config struct { // (1)
	Port string `mapstructure:"PORT"` // (2)
}

func LoadConfig(path string) (config Config, err error) { // (3)

	viper.AddConfigPath(path) // (4)
	viper.SetConfigType("env") // (5)
	viper.SetConfigName("app") // (6)

	viper.AutomaticEnv() // (7)

	err = viper.ReadInConfig() // (8)
	if err != nil {
		return
	}
	err = viper.Unmarshal(&config) // (9)
	return // (10)
}

config 타입은 아래와 같이 viper.go 소스에서 지원하는 유형과 이를 가리키는 키워드를 손쉽게 확인할 수 있습니다. 

// FileName: github.com/spf13/viper@v1.15.0/viper.go

// (생략)
SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}

// (생략)

 

 

환경 변수 정보를 이용한 웹 어플리케이션 포트 정보 변경 

자 이제 main.go 파일을 조금 수정해봅시다. 

 

  1. LoadConfig 함수를 실행합니다. 여기서 주의할 점은 "." 입니다. 이는 현재 폴더라는 의미이고 터미널에서 go 명령어를 실행하는 현재 디렉터리 위치에 영향을 받습니다. 보통 프로그램 실행 시에는 폴더의 경로가 PROJECT_ROOT 입니다. 따라서, 보통 "." 으로 지정합니다. 절대 경로도 가능하므로 상황에 따라 유연하게 변경해주세요. 
  2. Go 언어에서 흔하게 사용하는 error 처리 로직입니다. log.Fatal 함수는 에러 로그를 출력하고 프로그램을 종료합니다. 
  3. 웹 어플리케이션이 Listen 할 TCP 포트를 환경 변수 파일에 의존하도록 설정하는게 목표이므로 Run 함수에 config.Port 정보를 전달합니다. 
// FileName: cmd/main.go

package main

import (
	"log"
	"net/http"

	"github.com/gin-gonic/gin"
	"k-in.com/gin-tutorial/config"
)

func main() {

	config, err := config.LoadConfig(".") // (1) 

	if err != nil { // (2) 
		log.Fatal("Could not load config", err)
	}

	server := gin.Default()
	server.GET("/health", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{"message": "ok"})
	})

	log.Fatal(server.Run(":" + config.Port)) // (3)
}

 

 

환경 변수 정보를 바꾸어가면서 실행해보기

환경 변수 정보를 변경해가면서 프로그램을 실행하여 로직이 우리 의도대로 흘러가는지 테스트해볼까요? 

 

$ cat app.env                                                              
PORT=8000%   

$ go run cmd/main.go

프로그램을 실행하면 8000 포트로 Listen 하는 것을 확인할 수 있습니다. 

 

이번엔 8001 포트로 변경해서 적용해볼까요? 

마찬가지로 8001 포트로 Listen 하고 있음을 확인하였습니다. 

$ cat app.env
PORT=8001%
$ go run cmd/main.go

 

 

맺음말 

 

오늘은 "Gin 을 이용한 CRUD RESTful API 개발" 시리즈의 Part-2 를 진행하였습니다. 

Part-1 의 소스코드를 수정해 Viper 를 이용해서 환경 변수를 불러오고

웹 어플리케이션의 Listen 포트를 수정하는 과정을 진행하였습니다. 

 

오늘 진행한 튜토리얼의 소스는 아래의 경로에서 다운받아서 살펴볼 수 있습니다. 

아래 웹 사이트에 방문하셔서 Clone 버튼을 꾹 눌러주세요. 

 

 

https://bitbucket.org/kinstory/gin-tutorial/src/part2/

 

Bitbucket

 

bitbucket.org

 

이상으로 K-IN 이었습니다.

즐거운 하루되세요 

 

반응형