GCP Cloud Functions 사용법 [초보자]

18190 단어 5gcpcloudfunctions
AWS Lambda + API Gateway <GET> 사용법 [초보자]
AWS Lambda + API Gateway <POST> 사용법 [초보자]
GCP Cloud Function 버전입니다.

Cloud Functions 만들기



AWS의 경우 API Gateway와 Lambda에서 WEB API를 만들었습니다.
GCP의 경우 트리거에 HTTP를 선택하면 Cloud Functions에서만 사용할 수 있습니다.

런타임은 "Go 1.11"을 선택합니다.
포인트는 패키지에 "main"을 지정하지 않고 "main"함수도 지정하지 않습니다.

다음 소스를 "인라인 편집기"로 작성합니다.
실행할 함수는 "HelloWorld"입니다.

function.go
package p

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "strconv"
)

type Calc struct {
    Value1 int `json:"Value1"`
    Value2 int `json:"Value2"`
}

type ReturnCalc struct {
    Calc     // 埋め込み(embedded) 継承的な意味合い
    Ans  int `json:"Ans"`
}

// メソッド定義
func (c Calc) Add() int {
    return c.Value1 + c.Value2
}
func (c *ReturnCalc) Add() {
    c.Ans = c.Value1 + c.Value2
}

func HelloWorld(w http.ResponseWriter, r *http.Request) {
    // クエリパラメータ取得してみる
    var err_flg = 0
    var data Calc

    if r.Method == http.MethodGet {
        for key, values := range r.URL.Query() {
            for _, v := range values {
                switch key {
                case "Value1":
                    i, err := strconv.Atoi(v)
                    if err != nil {
                        fmt.Fprintln(w, "Value1が数値じゃない")
                        err_flg = 1
                        break
                    }
                    data.Value1 = i
                case "Value2":
                    i, err := strconv.Atoi(v)
                    if err != nil {
                        fmt.Fprintln(w, "Value2が数値じゃない")
                        err_flg = 1
                        break
                    }
                    data.Value2 = i
                default:
                    fmt.Fprintln(w, "パラメータエラー")
                    err_flg = 1
                    break
                }
            }
        }
        if err_flg == 0 {
            fmt.Fprintf(w, "%d + %d = %d \n", data.Value1, data.Value2, data.Add())
        } else {
            w.WriteHeader(http.StatusInternalServerError)
        }

    } else if r.Method == http.MethodPost {
        // CORS対策
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

        // Bodyデータを扱う場合には、事前にパースを行う(POSTの場合、必ず実施する)
        r.ParseForm()

        if r.Header.Get("Content-Type") != "application/json" {
            w.WriteHeader(http.StatusInternalServerError)
            fmt.Fprintln(w, "json形式じゃない")
            return
        }

        //parse json
        var data Calc
        jsondata, err := ioutil.ReadAll(r.Body)
        // 構造体に格納しているが、 data をmap[string]int や map[string]interfase{}にしても格納可能
        err = json.Unmarshal(jsondata, &data)
        if err != nil {
            fmt.Fprintf(w, "json変換できない %v \n", err)
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
        //返信用データ作成
        var rdata ReturnCalc
        rdata.Value1 = data.Value1
        rdata.Value2 = data.Value2
        rdata.Add()
        v, _ := json.Marshal(rdata)
        fmt.Fprint(w, string(v))

    } else if r.Method == http.MethodOptions {
        // CORS対策
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
    }
}

GET 만들기


r.Method == http.MethodGet 내가 GET 처리입니다.

다음 페이지를 참고하여 URL 매개변수를 가져옵니다.
golang에서 URL을 구문 분석

POST 만들기



OPTIONS 지정 및 CORS 대책



POST의 경우 AWS Lambda + API Gateway <POST> 사용법 [초보자]에서와 같이OPTIONS 의 지정과 CORS対策 가 필요합니다.

POST하면 r.Method == http.MethodOptions가 먼저 실행됩니다.r.Method == http.MethodPost 가 실행됩니다.

CORS 대책은, 이하의 헤더 정보를 부가하는 것으로 대응할 수 있습니다.
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

r.ParseForm()



POST 처리의 경우, ParseForm() 로 퍼스 처리가 필요합니다.

json 데이터 읽기 / 쓰기


ioutil.ReadAll(r.Body) 에서 요청 본문을 읽을 수 있습니다.Unmarshal 에서 json 데이터를 Go 언어의 구조체 등에 저장할 수 있습니다.Marshal 는 구조체와 같은 데이터를 json 데이터로 변환합니다.

방법


func (c *ReturnCalc) Add() {
    c.Ans = c.Value1 + c.Value2
}

위의 방법으로 추가 한 결과를 Ans에 저장합니다.
아래와 같이 포인터 리시버를 값 리시버의 메소드로 했을 경우, 올바른 결과가 되지 않습니다.
func (c ReturnCalc) Add() {
    c.Ans = c.Value1 + c.Value2
}

포인터 리시버와 값 리시버의 차이는, 구조체의 값의 변경이, 메소드 호출 후에도 반영되는지 어떤지입니다.
함수 내에서 구조체의 값을 변경하려면 포인터 메서드에서 정의해야 합니다.

다음이 도움이 되었습니다.
[Go] 구조체에서 값 및 포인터 메서드를 구분

테스트



Cloud Functions에도 테스트가 있지만 POST로 실행되는 것 같습니다.



참고



golang에서 URL을 구문 분석
[Go] 구조체에서 값 및 포인터 메서드를 구분

좋은 웹페이지 즐겨찾기