Slack の Incoming Webhookで簡易なフィードバック管理機能を作る(Azure Functionsを利用)

# はじめに

本稿は、Slack の Incoming Webhook を用いて、アプリに対するユーザーからの要望や不具合報告などのフィードバック管理を簡易的に実現する方法の紹介です。

# ユーザーからのフィードバックを管理したい

Webサービスであっても、Android/iOSアプリであっても、ユーザーからの要望や不具合報告など、ユーザーからのフィードバックを管理したいことは多いです。
アクティブユーザー数の少ない個人開発のアプリやサービスなら、なおさらユーザーからのフィードバックを元に改善することが重要です。

しかし、DB(データベース)にデータを登録するのは、ちょっとだけ面倒です。
ユーザーからの要望や不具合報告登録をDBに登録する場合、登録したデータを検索したり表示したりするための管理機能が必要ですし、DBに登録されたことを通知する機能も欲しいです。
アプリの本質的でない部分に、あまり労力を使いたくないというのが心情です。

# そこで Slack の Incoming Webhook 
DBの代わりに、Slack の Incoming Webhook を使えば、指定したチャンネルに要望や不具合報告を投稿可能です。
Slackなので、検索もしやすいし、通知にもなります。
フリープランでも、直近10,000件まで投稿が記録できるので、アプリのユーザー数が多くなるまでは、簡易的な管理として十分活用できます。

# 実現手順の概要
Slack の Incoming Webhook を用いてフィードバック管理機能を作る手順は以下の通りです。

1. フィードバック管理用のSlackのワークスペースを作成する([こちらのリンク先参照](https://slack.com/intl/ja-jp/help/articles/206845317-Slack-%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%BC%E3%82%B9%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B))
2. Incoming Webhook URLを取得する([こちらのリンク先参照](https://slack.com/intl/ja-jp/help/articles/115005265063-Slack-%E3%81%A7%E3%81%AE-Incoming-Webhook-%E3%81%AE%E5%88%A9%E7%94%A8))
3. Incoming Webhook URL を用いて Slack に投稿する Web API を作成する
4. 上記の Web API を Webサービスやアプリから実行する

この手順の中で、1, 2, 4 は簡単ですが、3 のWeb API を作成する部分は技術的要素があるので、その部分の詳細を以降で説明します。

# Microsoft Azure を用いた Web API の作成手順

ここからは、Web API を作成する1つの方法として、Visual Studio で Microsoft Azure の Azure Functions を用いる方法を説明します。

## Azure Functions のプロジェクトを作成する

まず最初は、以下の公式ページの通りに、Web APIの雛形を作ります。
[クイック スタート:Visual Studio を使用して Azure で初めての関数を作成する](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-create-your-first-function-visual-studio)

上記の手順でプロジェクトを作成すれば、以下のように Function1 というクラスが自動で作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403606/461edd4c-dd06-7d74-93c7-0a29e4370252.png)

Function1 の中身は、Web API を実現するための雛形が、下図のように最初から書いてあります。
そのため、やることは、このメソッドの中身を変更するだけです。
このメソッドの中身を変更して、上記公式ページにある Azure に発行する処理を行えば、Web APIの作成完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403606/5aa130b4-42d6-149f-73fa-37e08cdd3e80.png)

## Slackに投稿するメソッドを作成する

C# で Slack の Incoming Webhook を用いて投稿する実装はとても簡単です。
以下のようなメソッドを作れば、指定したSlackのワークスペースに投稿できます。
このメソッドを持つクラス(SlackNotificationServiceクラス)のソースコードは[こちら](https://github.com/kojimadev/SlackIncomingWebhook/blob/master/src/SlackFunctionApp/SlackFunctionApp/SlackNotificationService.cs)を参照ください。

```c#
/// <summary>
/// Slackにメッセージを通知する
/// </summary>
/// <param name="message">メッセージ</param>
/// <param name="webhookUrl">webhookUrl</param>
/// <param name="userName">ユーザー名</param>
/// <param name="channelName">チャンネル名</param>
/// <param name="mention">メンションを付けるか/param>
/// <returns>通知に成功したか</returns>
public async Task<bool> Notify(string message, string webhookUrl, string userName,
	string channelName, bool mention = true)
{
	// 先頭にChannelメンションを付ける
	if (mention)
	{
		message = $"{ChannelMention}{Environment.NewLine}{message}";
	}

	// 送信パラメータを作成
	var slackPayload = new SlackPayload()
	{
		// メッセージと投稿者名とチャンネル名を設定
		text = message,
		username = userName,
		channel = channelName,
	};

	// 送信パラメータオブジェクトをJSONに変換
	var jsonSlackPayload = JsonConvert.SerializeObject(slackPayload);

	// Jsonの送信パラメータ情報をHttpContentに変換
	var slackPayloadDictionary = new Dictionary<string, string>()
	{
		{PayloadKeyValue, jsonSlackPayload}
	};
	var urlParameter = new FormUrlEncodedContent(slackPayloadDictionary);

	try
	{
		// Skackに投稿
		var response = await _HttpClient.PostAsync(webhookUrl, urlParameter)
			.ConfigureAwait(false);
		return (response.StatusCode == HttpStatusCode.OK);
	}
	catch
	{
		return false;
	}
}
```

上記の実装は2021年11月時点でも正常に動作しますが、これは2020年以前に行ったものであり、2021年時点では Incoming WebHook URL の取得方法について、推奨する方法が変わっています。詳しくは以下の記事を参照ください。

https://7iro.net/slack-api-csharp-incoming-webhook/

上記の推奨する方法で Incoming WebHook URL を取得した場合、username というパラメータを用いて投稿者名を変更することはできません。
利用できるパラメータの詳細は、以下の公式ページを参照ください。

https://api.slack.com/messaging/webhooks#posting_with_webhooks


## Azure Functionsから上記メソッドを呼び出す

あとは、上記のSlackに投稿するメソッド(SlackNotificationService.Notifyメソッド)を、Azure Functions のメソッドから呼び出すだけです。
もともとメソッドの雛形があるので、そのメソッドの中身を以下のような感じに書き換えればOKです。
ここでは、投稿する本文(message)、チャンネル名(channelName)、メンションするか(mention)をWeb APIのリクエストボティのパラメータとして受け取っています。
以下のクラス全体のソースコードは[こちら](https://github.com/kojimadev/SlackIncomingWebhook/blob/master/src/SlackFunctionApp/SlackFunctionApp/SlackFunctions.cs)を参照ください。

```c#
public static async Task<IActionResult> Run(
	[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
	ILogger log)
{
	log.LogInformation("C# HTTP trigger function processed a request.");

	// リクエストボディからパラメータを取得
	string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
	dynamic data = JsonConvert.DeserializeObject(requestBody);
	string message = data?.message;
	string channelName = data?.channelName;
	bool mention = data?.mention;

	// Slackの指定のチャンネルに投稿する
	var service = new SlackNotificationService();
	var success = await service.Notify(message,
		"https://hooks.slack.com/services/XXXXXXX", 
		"BotName", channelName, mention);

	// Slackへの投稿が成功か失敗か返す
	string responseMessage = success ? "success" : "failed";
	return new OkObjectResult(responseMessage);
}
```

## 動作確認する

上記のWeb APIを呼び出す際に、リクエストボディに3つのパラメータを渡す必要があります。
そのパラメータをjson形式で記載する例は以下を参照ください。

```json
{
    "message": "ユーザーからの要望や不具合報告のメッセージ。",
    "channelName": "error_report",
    "mention": true
}
```
上記のリクエストボディのパラメータでWeb APIを実行すると、#error_reportチャンネルに下図のように投稿されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403606/ba98b582-679b-ae0b-25a3-897a5d8e1038.png)

# 活用例

ユーザーからのフィードバックの他にも、ユーザーがアプリでどんな操作をしたのかのログを取得する用途にも活用できます。
例えば、以下のように、用途ごとにチャンネルを分けることもできます。

- ユーザーからの不具合報告(#error_reportチャンネル)
- ユーザーからの要望報告(#user_reportチャンネル)
- アプリでの特定操作時のログ(#info_log)
- リワード広告の表示ログ(#reward_log)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403606/b65e6053-21d7-c2ce-53c4-6006a7c1409c.png" width="50%">

不具合報告チャンネルには、下図のように、アプリで例外が発生した原因を特定するための情報を投稿すると便利です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403606/dc50e4f1-18f4-b17c-6ad8-73cc03461881.png" width="50%">

# まとめ

Slack の Incoming Webhook と Azure Functions を用いることで、フィードバックの管理を簡単に実現できます。本稿で紹介したソースコードは以下のリポジトリで公開しています。

https://github.com/kojimadev/SlackIncomingWebhook

ちなみに私は、普段はエンジニアリングマネージャーとして、チームの皆で楽しく開発する施策を色々実施しています。詳しくは以下を参照ください。

https://qiita.com/kojimadev/items/4b28f801863cf4e8f0da

Twitterでも開発に役立つ情報を発信しています → [@kojimadev](https://twitter.com/kojimadev)