6 min read

애저 펑션으로 MS 팀즈 커스텀 커넥터 만들기

Justin Yoo

지난 포스트에서는 애저 로직 앱으로 마이크로소프트 팀즈에 메시지를 보낼 수 있는 커스텀 커넥터를 만드는 방법에 대해 소개했었다. 많은 경우에는 로직 앱을 사용해도 크게 문제가 되진 않지만, 만약 메시지 구조가 복잡해진다거나 하면 애저 펑션을 쓰면 좀 더 효과적일 수도 있다. 이 포스트에서는 애저 펑션을 통해 MS 팀즈에 메시지를 보낼 수 있는 커스텀 커넥터를 만드는 방법에 대해 알아본다.

커스텀 커넥터 등록

우선 원하는 MS 팀즈 채널에 커스텀 커넥터를 등록한다. 지난 포스트와 마찬가지로 이번에도 Incoming Webhook 커넥터를 사용하기로 한다. 이 커넥터를 생성하는 방법은 지난 포스트를 참고하고, 여기서는 더 설명하지는 않기로 한다. 커넥터를 만들고 나면 웹훅 URL이 생기므로 이를 복사해 둔다.

실행형 메시지 카드 (Actionable Message Card) 작성

지난 포스트에서 언급한 바와 같이 현재 MS 팀즈의 커넥터는 적응형 카드(Adaptive Card) 포맷 대신 여전히 레거시 포맷인 실행형 메시지 카드(Actionable Message Card)를 사용한다. 어느 쪽이든 기본적으로 커다란 JSON 객체 형태인데, 이를 코드로 짜기에는 상당히 손이 많이 가는 편이다. 다행히도 이미 누군가 NuGet 패키지를 만들어서 제공하므로 그냥 가져다 쓰면 된다. 메시지 카드를 만드는 부분의 코드는 대략 아래와 비슷할 것이다.

private async Task ProcessAsync(string webhookUri, string summary, string title = null, string text = null, string themeColor = null, string sections = null, string actions = null)
{
var card = new MessageCard()
{
Title = title,
Summary = summary,
Text = text,
ThemeColor = themeColor,
Sections = ParseCollection<Section>(sections),
Actions = ParseCollection<BaseAction>(actions)
};
var converted = JsonConvert.SerializeObject(card, settings);
var message = (string)null;
var requestUri = webhookUri;
using (var client = new HttpClient())
using (var content = new StringContent(converted, Encoding.UTF8, "application/json"))
using (var response = await client.PostAsync(requestUri, content).ConfigureAwait(false))
{
response.EnsureSuccessStatusCode();
}
}
private List<T> ParseCollection<T>(string value)
{
var parsed = string.IsNullOrWhiteSpace(value)
? null
: JsonConvert.DeserializeObject<List<T>>(value, settings);
return parsed;
}

위 코드에서 볼 수 있다시피, webhookUrisummary를 제외하고 나머지는 모두 선택적 파라미터이다. sections, actions 파라미터는 JSON 배열 형태의 문자열을 직접 받아서 비직렬화를 시키게끔 했다. 이 부분은 사용자 케이스마다 워낙 천차만별이어서 각자의 상황에 맞게 적용하면 될 것이다.

보통은 이 sectionsactions 부분의 구조는 조직마다 어느 정도는 정형화 되어 있는 편일테니, 실제로 상황에 따라 변하는 값을 제외하고 나머지는 템플릿 형태로 미리 만들어서 제공하는 것이 일반적이다.

애저 펑션을 통해 메시지 보내기

위 코드는 상당히 일반론적인 것이어서, 사실 애저 펑션이 아니더라도 어디든 적용시킬 수 있다. 다만, 애저 펑션을 통해서 진행한다면 대략 아래와 같은 모양이 된다.

[FunctionName("SendMessageHttpTrigger")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "teams/send")] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var body = await new StreamReader(req.Body).ReadToEndAsync().ConfigureAwait(false);
dynamic payload = JsonConvert.DeserializeObject<object>(body);
await ProcessAsync(
payload.webhookUri,
payload.summary,
payload.title,
payload.text,
payload.themeColor,
payload.sections,
payload.actions).ConfigureAwait(false);
return new OkResult();
}
view raw function-app.cs hosted with ❤ by GitHub

콘솔 앱을 통해 메시지 보내기

그렇다면 만약 콘솔 앱과 같은 형태로 메시지를 보낸다면 어떤 식이 될까? 만약 CommandLineParser와 같은 라이브러리를 사용한다면 좀 더 직관적으로 멋지게 콘솔 앱을 작성할 수도 있겠지만, 여기서는 대략의 아이디어만 공유하자면 아래와 같은 모양과 비슷해진다.

public static void Main(string[] args)
{
var webhookUri = args[0];
var summary = args[1];
var title = args[2];
var text = args[3];
var themeColor = args[4];
var sections = args[5];
var actions = args[6];
ProcessAsync(
webhookUri,
summary,
title,
text,
themeColor,
sections,
actions).Result;
}
view raw console-app.cs hosted with ❤ by GitHub

지금까지 애저 펑션을 이용해서 MS 팀즈 채널로 메시지를 보내는 방법에 대해 논의해 보았다. 이렇게 만든 애저 펑션 앱은 결국 메시지를 쉽게 보내기 위한 웹훅 껍데기에 불과한 것이므로, 어딘가에서 이벤트가 발생했을 때 이를 빠르게 캡쳐해서 채널로 보내는 상황이라면 어디든 적용시킬 수 있을 것이다.