Azure Functions と Go 言語で Web API 開発

# はじめに
この記事では、Go言語を使って、与えた二つの数値の和の結果を返すような Web API を作成します。

GETリクエストを想定していて、二つの数値はクエリ文字列（URLパラメータ）で渡します。
デプロイ先としてはAzureのリソースを使います。

よろしくお願いします。

【イベント】Go強化月間～開発する上で知っておくべき知見を共有しよう～

https://qiita.com/official-events/ae80b010f51f7018891a

# 環境
- Windows 11
- [Go 1.17.7](https://go.dev/dl/)


# 必要なもの
- [Visual Studio Code](https://code.visualstudio.com/download)
- [Azure Functions用のVisual Studio Code 拡張機能](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions)
- [Azureサブスクリプション](https://azure.microsoft.com/ja-jp/free/)

# 全体の流れ
1. 各種必要なものをインストール & 作成する。
2. ローカル上にAzure Functionsプロジェクトを作成する。
3. Go言語で二つの数値の和を返すような関数を作成する。
4. ローカルで作成したAzure FuncitonsプロジェクトをAzure上にデプロイする。
5. 動作確認。

# 本文
## ① 各種必要なものをインストール & 作成する
上記で記載されている必要なものをインストール & 作成してください。

ローカル上で動作確認をしたい場合は下記を追加でインストールしてください。
この記事では使用していません。

- [Azure Functions Core Tools](https://github.com/Azure/azure-functions-core-tools)

## ② ローカル上にAzure Functionsプロジェクトを作成する
Azure Functions用のVisual Studio Code 拡張機能が無事にインストールされていれば、Azureの項目が追加されているので、下図のような画面を開いてください。またこのタイミングで自身のAzureサブスクリプションでサインインしてください。

赤線から [Create new project] をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/3ed39d64-4c17-667b-0aed-69d879b3bae8.png)

ここからは以下の手順で進めてください。

1. フォルダーの選択では、私の場合はデスクトップ上に「GoAppフォルダ」を作成し、そちらを選択しました。
2. 今回はGo言語を使用しますので、「Custom Handler」を選択してください。
3. 続いて、GETリクエストで呼ぶ想定なので「HTTP trigger」を選択してください。
4. 次にfunction名ですが、「sum」としておきましょう。
5. 承認レベルは「Anonymous」を選択してください。
6. 最後は「Open in current window」で大丈夫です。

Azure Functionsプロジェクトが作成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/891f09d5-4bf2-9873-3f9f-7769d8b804f9.png)



今回はGETリクエストで呼ぶので、function.jsonのmethodsのpostは削除しておきましょう。

```json
{
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}

```
以上で、「ローカル上にAzure Functionsプロジェクトを作成する」は完了です。

## ③ Go言語で二つの数値の和を返すような関数を作成する
それでは、Go言語のプログラムを書いていきます。

まずはGoAppフォルダに「server.go」ファイルを作成しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/5c73af8c-061f-a231-44c8-7e0722d531ec.png)



以下のようなコードを書いていきます。

```go
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
)

func sumHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	if r.Method == "GET" {
		a, _ := strconv.Atoi(r.URL.Query().Get("a"))
		b, _ := strconv.Atoi(r.URL.Query().Get("b"))
		w.Write([]byte(strconv.Itoa(a + b)))

	} else {
		body, _ := ioutil.ReadAll(r.Body)
		w.Write(body)
	}
}

func main() {
	customHandlerPort, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
	if !exists {
		customHandlerPort = "8080"
	}
	mux := http.NewServeMux()
	mux.HandleFunc("/api/sum", sumHandler)
	fmt.Println("Go server Listening on: ", customHandlerPort)
	log.Fatal(http.ListenAndServe(":"+customHandlerPort, mux))
}
```

続いて、ビルドしていきます。
コマンドプロンプトを開いて、作業フォルダ（私の場合はGoApp）がカレントディレクトリになるように移動してください。

```
go build server.go
```

上記コマンドを実行し、server.exeファイルを作成します。


最後にアプリケーションの実行PathとenableForwardingHttpRequestを設定します。
1. 先ほどビルドで作成されたserver.exeを指定します。host.jsonのdefaultExecutablePathに「sever.exe」と記載しましょう。
2.  customHandlerの中に、enableForwardingHttpRequestのkeyを追加し、valueはtrueに設定してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/6b8af27f-a4a3-8714-4f1a-bd5c7b721d85.png)



```json
{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[2.*, 3.0.0)"
  },
  "customHandler": {
    "description": {
      "defaultExecutablePath": "server.exe",
      "workingDirectory": "",
      "arguments": []
    },
    "enableForwardingHttpRequest" : true
  }
}
```


以上で、「Go言語で二つの数値の和を返すような関数を作成する」は完了です。

## ④ ローカルで作成したAzure FuncitonsプロジェクトをAzure上にデプロイする
それでは、Azure上にデプロイします。
[Deploy to Function App] をクリックしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/a438e9a2-aa7c-1914-2c43-6c96252d94c9.png)

ここからは以下の手順で進めてください。
Azureにリソースを作成する際に、命名をする必要があります。今回の記事では命名に関しては重要ではないです。ただし、function app名のみはユニークな名前にする必要がありますので注意してください。

1. 「Create new Function App in Azure... Advanced」を選択してください。
2. function app名ですが、ここはユニークな名前にする必要があります。私の場合は「michigoapp-fa」としました。※同じ名前にするとデプロイできません。
3. 「Custom Handler」を選択してください。
4. サーバーのOSですが、「Windows」にしておきましょう。
5. 次にリソースグループの作成になります。「Create new resource group」を選択してください。リソースグループ名は「michigoapp-rg」にしました。
6. リージョンは「japan East」を選択してください。
7. ホスティングプランは「App Service Plan」を選択してください。 
8. 「Create new App Service plan」を選択してください。App Service Plan名は「michigoapp-asp」にしました。
9. 「Free(F1)」を選択してください。
10. 「Create new storage account」を選択してください。ストレージアカウント名は「michigoappstorage」にしました。
11. Application Insightsは今回使用しないので、「Skip for now」を選択してください。

少し時間がかかりますが、completedが出れば、Azureのリソースが作成され、デプロイ完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/c0bc557c-1b67-5cf1-0ca7-6d19697484eb.png)

以上で、「ローカルで作成したAzure FuncitonsプロジェクトをAzure上にデプロイする」は完了です。


## ⑤ 動作確認
実際にAPIを叩いて、動作確認をします。

デプロイが成功すると、Azureサブスクリプションの下に先ほど作成したFunctions Appが表示されます。
赤線のsumを右クリックして、[Copy Function Url]をしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/e1d80d4a-572c-5993-5787-e03c72fa79f6.png)

以下のようなURLがコピーされます。

```
https://michigoapp-fa.azurewebsites.net/api/sum
```

二つの数値をクエリ文字列（URLパラメータ）で渡しますので、以下のようにURLの後ろ追記してください。

```
https://michigoapp-fa.azurewebsites.net/api/sum?a=5&b=10
```

任意のブラウザで追記したURLを叩き、 「15」 が表示されたら、成功です！

以上で、「動作確認」は完了です。

# おわりに
お疲れ様でした。

最後に、今回作成したAzureリソースを削除したいと思います。
[Azure Portal](https://portal.azure.com/)で作成したリソースグループを見ると、作成したリソースの存在が確認できます。
赤線のリソースグループの削除をクリックし、リソースグループ名の入力、削除ボタンクリックですべてのリソースを削除することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/6851f937-d198-3248-22fa-1091182149f2.png)

ここまで読んでいただきありがとうござました！