오늘은 Go 언어의 함수에 대해 살펴보겠습니다. 사실 언어를 공부하게 되면 제일 먼저 학습하게 되는 것이 변수 선언 같은 것일 텐데요, 여기서는 조금 다르게 함수를 먼저 살펴보겠습니다. 지난번에 만들었던 Hello Workd on API Gateway의 코드(https://fallwalker.tistory.com/4) 를 바탕으로 함수를 만들어서 여러 개의 Path를 처리할 수 있도록 해보겠습니다.
URI 별로 분기 하기
우리가 만든 Go 애플리케이션은 람다로 실행되고 앞단의 HTTP 요청은 API Gateway가 처리해 주기 때문에 Header와 Path와 같은 HTTP와 관련된 데이터들은 인자로 받을 수 있습니다. handler()
함수에서 인자로 받고 있는 events.APIGatewayProxyRequest
가 바로 그 주인공 입니다. 이 값을 통해 Path를 전달받고, 각각의 Path 별로 함수를 구현해서 서로 다른 응답을 할 수 있게 구현해 보겠습니다.
func handler(event events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error){
switch event.Path {
case "/hello":
// Do something about hello
case "/bye":
// Do something about bye
default:
// Do something about default
}
return events.APIGatewayProxyResponse{
StatusCode: http.StatusOK,
Body: "Hello World",
}, nil
}
handler()
함수가 기존보다 조금 더 풍성해 졌습니다. 먼저 event
라는 변수를 통해 API Gateway로부터 받은 인자를 넘겨받습니다. 그리고 event.Path
를 통해 어떤 URI로 들어왔는지를 확인 합니다.
event를 통해서 확인할 수 있는 건 Path 외에도 더 많습니다. 어떤 것들을 더 확인할 수 있는지는 https://github.com/aws/aws-lambda-go/blob/v1.24.0/events/apigw.go#L6 을 통해서 확인하시면 됩니다.
그럼 하나씩 함수를 만들어 보겠습니다.
DoHello()와 DoBye() 함수
각각의 Path를 처리하기 위한 DoHello()
함수와 DoBye()
함수를 만들어 보겠습니다. 함수를 정의할 때는 이미 앞의 예제를 통해서 보셨겠지만 func
라는 지시자를 통해서 정의해 줍니다. 그리고 다음으로 인자와 응답 값들을 정의해 줍니다.
func 함수이름 (인자) 응답 값
함수를 만들 때는 몇 가지 규칙이 있는데 어려운 것들은 우선은 빼고 가장 중요한 두 가지 규칙을 먼저 살펴보겠습니다.
- 함수의 이름을 소문자로 시작하게 만들면 패키지 내부에서만 호출 가능하며, 대문자로 시작하게 만들면 패키지 외부에서도 호출이 가능합니다. 우리는 이번 글에서 대문자로 시작하도록 함수 이름을 설정했는데 다음번 글에서 이에 대해 좀 더 자세히 살펴보겠습니다.
- 응답 값이 한개면 괄호를 생략할 수 있습니다. 응답값이 두 개 이상이면 괄호로 묶어 줘야 합니다.
ex) func DoHello() string {} - 가능, func DoHello() string, error - 불가능, func DoHello() (string, error) - 가능
그래서 우리가 만든 DoHello()
와 DoBye()
함수는 아래와 같은 모습이 됩니다.
func DoHello() string {
return "Hello"
}
func DoBye() string {
return "Bye"
}
각각 함수로 넘어오는 인자는 없으며, string
타입의 응답 값을 가지고 있는 함수가 됩니다. 그리고 이렇게 만들어 준 함수를 handler()
함수에 추가해 주겠습니다. responseBody
라는 변수를 만들고 각 함수의 호출 결과를 저장한 후에 이를 바탕으로 API 응답을 만들어 주도록 합니다.
func handler(event events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error){
switch event.Path {
case "/hello":
responseBody := DoHello()
case "/bye":
responseBody := DoBye()
default:
responseBody := "Default"
}
return events.APIGatewayProxyResponse{
StatusCode: http.StatusOK,
Body: responseBody,
}, nil
}
하지만 이대로 코드를 작성하면 GoLand에서는 아래와 같이 빨간 줄 천지가 됩니다.
왜 그럴까요? 바로 responseBody
라는 변수의 범위 때문에 발생하는 이슈입니다.
Go의 변수 선언
우리가 의도했던 것은 각 함수의 결과를 responseBody
에 저장한 후 사용하려고 했으나 의도대로 동작하지 않았습니다. 이는 Go 언어 변수의 범위 때문에 발생한 이슈입니다. switch, for 문과 같은 곳에서 선언한 변수들은 해당 로직이 종료되면 더 이상 존재하지 않습니다. Go 언어 변수의 지역성 때문인데요, 보통 다른 언어에서는 switch, for 문과 같은 곳에서 선언한 변수를 그 이후에도 사용할 수 있는 것과 달리 Go 언어에서는 로직 외부에서는 사용할 수 없습니다. 따라서 지금과 같은 경우에는 responseBody
를 switch 외부에서 정의해 줘야 합니다. Go 언어의 변수 선언은 아래와 같이 됩니다.
var 변수이름 변수타입
이것도 다른 언어들과 많이 다르죠.
다른 언어들은 타입이 먼저 나오지만 Go 언어는 변수 이름이 먼저 나옵니다.
그래서 위와 같은 responseBody
를 정의하기 위해서는 아래와 같이 정의해 줘야 합니다.
var responseBody string
하지만 위의 함수 예제를 보면 responseBody
를 처음 사용한 곳에서는 var 나 string 이라는 단어가 보이지 않는데 왜 그럴까요? Go 언어는 var 지시자를 통해 정의하지 않아도 변수 정의와 값 할당을 동시에 할 수 있습니다. 바로 :=
연산자를 통해 가능합니다. 그래서 위에서 본 responseBody := DoHello()
구문은 아래와 같은 구문입니다.
var responseBody string
responseBody = DoHello()
우리는 switch 문 밖에서도 responseBody
를 사용해야 하기 때문에 var 지시자를 통해서 선언해 주어야 합니다. 그래서 코드는 아래와 같이 됩니다.
func handler(event events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error){
var responseBody string
switch event.Path {
case "/hello":
responseBody = DoHello()
case "/bye":
responseBody = DoBye()
default:
responseBody = "Default"
}
return events.APIGatewayProxyResponse{
StatusCode: http.StatusOK,
Body: responseBody,
}, nil
}
이제 빨간 줄도 모두 없어졌을 겁니다. 빌드하고 serverless 를 통해 배포해 보겠습니다.
serverless 배포
serverless.yaml
파일도 아래와 같이 수정해 줍니다.
service: hello-world
provider:
name: aws
runtime: go1.x
memorySize: 256
region: ap-northeast-2
timeout: 30
package:
exclude:
- ./**
include:
- ./bin/**
functions:
helloWorld:
handler: bin/hello-world
events:
- http:
path: /
method: GET
- http:
path: /hello
method: GET
- http:
path: /bye
method: GET
첫 번째 글에서는 /
에 대한 Path만 정의해 줬지만 이번에 우리는 /hello
와 /bye
도 처리하기 위한 구현을 했기 때문에 두 개의 Path도 추가해 줍니다. 그리고 sls deploy
로 배포해 준 후 curl
로 테스트해 보겠습니다.
~/Desktop/Project/hello-world-go 28s
❯ curl https://o2slv6y2ac.execute-api.ap-northeast-2.amazonaws.com/dev/hello
Hello
~/Desktop/Project/hello-world-go
❯ curl https://o2slv6y2ac.execute-api.ap-northeast-2.amazonaws.com/dev/bye
Bye
우리가 의도했던 대로 잘 동작하는 것을 확인할 수 있습니다.
마치며
이번 글에서는 함수를 이용해서 우리가 처리하려는 것들을 더 늘려 봤습니다. 그리고 변수 선언 방법에 대해서도 가볍게 살펴봤습니다. 변수 선언과 함수 정의는 모든 언어에서 가장 중요한 부분이라고 생각합니다. 실질적인 로직을 만들어 내기 위해 필요한 것들이기 때문입니다. Go 언어의 더 다양한 변수 선언과 함수 정의 부분은 차차 살펴보기로 하고 오늘 배운 가장 기본적인 내용에 대해서 먼저 학습하고 익숙해 지시기 바랍니다. 다음 글에서는 패키지화를 통해서 Go 애플리케이션을 조금 더 잘 구조화해서 사용하는 방법에 대해서 살펴보겠습니다. 감사합니다.
'IT > GoLang' 카테고리의 다른 글
Go 언어에서 YAML 파일을 구조체로 표현하기 위한 일곱가지 패턴 (0) | 2022.01.17 |
---|---|
세번째 글 - 패키지 만들기 (0) | 2021.10.04 |
첫번째 글 - Hello World on API Gateway (0) | 2021.09.22 |