슬랙봇 만들기: API를 통해 정보 얻기 및 표시하기

2019.01.28 07:50UI 가벼운 이야기
by Sungi Kim

안녕하세요. 1년 몇 개월 만에 슬랙봇 만들기 2편을 씁니다.

1편 : 슬랙봇을 만들어봅시다

오랜만에 1편을 다시 읽으니, 쉽게 쓴다고 썼는데 복잡해 보였습니다. 그래서 이번 글에서는 좀 더 쉽게 첫 세팅부터 활용까지 적어보려고 합니다. 그리고 제가 아는 범위 내에서 구조에 관해서도 설명을 하려고 합니다. 글의 순서는 아래와 같습니다.

1. 준비 : 슬랙봇 초간단 세팅
   1-1. 개발을 위한 에디터 설치
   1-2. 슬랙에서 봇 생성 및 Token 받기
   1-3. Slack bot library 설치
   1-4. 코드 작성 및 실행
2. 활용 : 슬랙봇이 현재 날씨 표시하게 하기
   2-1. 날씨 정보 제공 서비스 가입 및 API Key 받기
   2-2. 날씨를 알고 싶은 위치의 좌표 알아내기
   2-3. API 요청, 응답을 처리하기 위한 모듈 설치
3. 추가정보 : API와 JSON
   3-1. API를 통해 얻은 json 데이터 처리하기
   3-2. 다른 API 사용해보기


유의할 점

- 이 글은 Mac 환경에서 만드는 것을 설명합니다.
- 이 글을 따라서 만든 슬랙봇은 사용자의 컴퓨터가 켜져 있고, 슬랙봇이 실행되어있는 경우에만 동작합니다. 언제든 동작하게 하기 위해서는 1편의 호스팅 및 git을 통한 배포를 따라 해야 합니다.
- 저는 개발자가 아닙니다. 용어설명이나 표현이 정확하지 않을 수 있습니다.


1. 준비 : 슬랙봇 초간단 세팅

1-1. 개발을 위한 에디터 설치

먼저, 코딩을 쉽게 할 수 있도록 에디터를 설치합니다. 아래 사이트에서 OS X용을 다운받아서 설치하시면 됩니다. 에디터를 사용하는 일은 나중이니, 여기까지만 진행하고 다음 단계로 넘어갑니다. https://www.sublimetext.com

1-2. 슬랙에서 봇 생성 및 Token 받기

슬랙에서 봇을 만들기 위해서는 token을 발급받아야 합니다. 일단 따라 해보시죠. 아래 경로를 따라가시면 슬랙봇을 생성할 수 있습니다. 웹브라우저에 URL을 직접 입력하거나, 슬랙 앱에서 찾아갈 수도 있습니다.

a. Slack 어플리케이션에서의 경로 : 좌측상단 username 클릭 > Administration > Manage Apps > Custom Integrations > Bots > Add Configuration
b. 웹브라우저에서의 경로 주소 : https://슬랙이름.slack.com/apps/manage/custom-integrations

위에서 Add Configuration을 하면 새로운 봇이 생성됩니다. 표시되는 내용 중에 API token이 있는데, 이를 어딘가에 기록해둡니다. 'xoxb-....'로 시작되는 긴 내용이 token입니다.

1-3. Slack bot library 설치

이번에는 slack에서 제공하는 bot library를 설치합니다. Mac에서 Terminal을 실행합니다. Terminal은 파인더의 텍스트 버전이라고 생각하시면 됩니다.

Terminal 실행 경로 : Finder > Application > Utilities > Terminal

이제 Terminal을 통해 데스크탑에 example이라는 폴더를 만들고, 해당 폴더로 이동하는 명령어를 입력합니다. 아래의 내용에서 한 줄 적고 엔터, 한 줄 적고 엔터 하시면 됩니다.
mkdir ~/desktop/example
cd ~/desktop/example

그리고 Slack bot library를 설치하는 명령어를 입력합니다. 아래의 내용을 입력하고 엔터를 칩니다.
npm install @slack/client --save

* 혹시 npm이 설치되어있지 않다고 하면, https://www.npmjs.com/get-npm에서 다운받아 설치하세요.

1-4. 코드 작성 및 실행

이제 준비가 완료되었습니다. 코드를 작성하도록 하죠! 전 언제나 Copy&Paste로 시작하는 것을 좋아합니다. 1-1에서 설치한 에디터(sublimetext)를 실행하고, 빈 창에 아래의 내용을 붙여넣습니다. 그리고 아래의 빨간색 텍스트, 'xoxb...'로 시작되는 부분은 1-2 에서 생성한 봇의 token으로 대체해주세요.

// 슬랙봇 초기화하기
const { RTMClient } = require('@slack/client');
const token = process.env.SLACK_TOKEN || 'xoxb-190626573414-500782710453-jVbhdun3GVdfcOJdW4z00000';
const rtm = new RTMClient(token);
rtm.start();

// 슬랙봇이 모든 메시지를 받도록 하기
rtm.on('message', (message) => {
    var text = message.text
    //슬랙봇이 받은 메시지에 '천재'가 포함되어있다면, '감사'라는 답글을 쓰도록 하기
    if (text.includes("천재") ) {rtm.sendMessage("감사", message.channel);} 
    else if(text.includes("바보")){rtm.sendMessage("반사", message.channel);} 
});

그 다음 저장하면 되는데요. Command + S를 눌러서 저장하기 팝업이 뜨면, 데스크탑의 example 폴더에, 파일명 app.js로 저장합니다. 저장하고 나면 텍스트들에 컬러가 붙었죠? sublimetext가 js라는 확장자를 보고 javascript syntax로 인식한 것입니다.

준비가 끝났습니다! Terminal에서 아래의 내용을 입력하고 엔터를 치면, 슬랙봇이 실행됩니다.
node ~/desktop/example/app.js

슬랙봇이 동작하는지 슬랙에서 확인해볼까요? 슬랙 앱의 Direct message에서 우리가 만든 봇을 선택합니다. 그리고 '천재'라고 입력하면, 슬랙봇이 '감사'라는 메시지를 보냅니다.


2. 활용 : 슬랙봇이 현재 날씨 표시하게 하기

이제 나만의 슬랙봇이 만들어졌습니다. 그리고 슬랙봇에게 특정 단어를 이야기하면, 코드에 작성된 내용으로 응답을 할 수 있게 되었습니다. 이제 슬랙봇에게 '날씨'라고 이야기하면, 현재의 날씨 정보를 어딘가에서 받아와 응답하도록 만들어 보겠습니다. 여기서 우리는 API를 사용할 겁니다. API는 application programming interface의 약자인데요. 이해를 돕기 위한 예로, 날씨 정보를 제공하는 서비스의 API를 통해 '신사동' 지역의 '현재 날씨'를 요청하면, 서비스에서는 요청한 정보를 나에게 보내줍니다. 


2-1. 날씨 정보 제공 서비스 가입 및 API Key 받기

먼저 '날씨 정보를 API로 제공하는 서비스'를 찾아야 합니다. 저는 Darksky를 사용하기로 했습니다. 웹브라우저를 통해 아래의 사이트에서 가입합니다.
https://darksky.net/dev

가입을 하면 Your Account라는 페이지가 뜨는데, 그 내용 중, Your Secret Key라는 부분에서 Key 값을 복사해 어딘가 저장해둡니다. 6280c9d740000000029d0957e1ff807e 처럼 생긴 값입니다.


2-2. 날씨를 알고 싶은 위치의 좌표 알아내기

위에서는 '신사동'이라는 지역을 언급했지만, darksky에서 특정 지역의 날씨를 알고 싶으면, 주소가 아닌 GPS 좌표 값으로 요청해야합니다. 이는 구글 맵이나 다른 웹서비스를 사용하여 확인할 수 있습니다. 제가 사용할 '가로수길 입구'의 GPS좌표는 '37.518252, 127.023549' 입니다. 


2-3. API 요청, 응답을 처리하기 위한 모듈 설치

nodejs에서 간편하게 API를 요청하고 응답을 처리하기 위해서는 request라는 모듈을 설치해야 합니다. Terminal로 돌아가 아래와 같이 입력하고 엔터를 칩니다. 혹시 명령 프롬프트가 표시된 상태가 아니라면(뭔가 입력해도 반응이 없고 왼쪽에 $와 같은 표시가 안 뜬다면) 슬랙봇 앱이 실행된 상태이니, Control + C로 종료시키고 입력하면 됩니다.
npm install request

2-4. 코드 작성 및 실행

이제 코드를 작성할 때가 되었습니다. 에디터를 열고 app.js의 내용을 모두 지우고, 아래의 내용을 Copy&Paste 합니다. 보라색 텍스트가 새롭게 추가된 내용이고, 빨간색 텍스트는 위에서 준비한 GPS 좌표, 날씨 서비스 API key, 슬랙봇 token 값들로, 여러분의 값을 입력하면 됩니다. 입력을 완료한 후 파일을 저장합니다.

// 위치값과 API key 정의하기
const lat = 37.518252;
const long = 127.023549;
const DARK_API_KEY = "6280c9d740000000029d0957e1ff807e";
const request = require('request');

// API를 통해 날씨정보를 받아오는 기능 정의하기
function weatherFN(callback) { 
    request(`https://api.darksky.net/forecast/${DARK_API_KEY}/${lat},${long}?lang=ko&units=si`, { json: true }, (err, res, body) => {
    if (err) { return console.log(err); }
    var w1 = body.currently.summary
    var w2 = body.currently.temperature + "°"
    var w3 = body.currently.humidity * 100 + "%"
    var weatherValue = "날씨 : " + w1 + "\n기온 : " + w2 + "\n습도 : " + w3
    callback (weatherValue); 
    });
};

// 슬랙봇 초기화하기
const { RTMClient } = require('@slack/client');
const token = process.env.SLACK_TOKEN || 'xoxb-190626573414-500782710453-jVbhdun3GVdfcOJdW4z00000';
const rtm = new RTMClient(token);
rtm.start();

// 슬랙봇이 모든 메시지를 받도록 하기
rtm.on('message', (message) => {
    var text = message.text
    //슬랙봇이 받은 메시지에 '천재'가 포함되어있다면, '감사'라는 답글을 쓰도록 하기
    if (text.includes("천재") ) {rtm.sendMessage("감사", message.channel);} 
    else if(text.includes("바보")){rtm.sendMessage("반사", message.channel);} 
    else if(text.includes("날씨")){ 
        weatherFN(function(body) {rtm.sendMessage(body, message.channel);}) 
    }
});

대략 설명드리면, 슬랙봇이 '날씨'라는 메시지를 받으면 weatherFN이라는 기능을 실행하고, 해당 기능이 실행된 결과값을 응답 메시지로 보냅니다. weatherFN에서는 darksky API로 GPS 좌표와 인증을 위한 API key를 요청하고, darksky가 준 결과를 받아 원하는 정보만 정제합니다(여기서는 현재 날씨, 현재 기온, 현재 습도). 그리고 정제한 정보를 실행의 결과값으로 돌려줍니다.

이제 완성되었습니다! 다시 Terminal로 돌아가, 작성한 코드를 실행시킵니다.
node app.js

그런 다음, 슬랙 앱을 열고 슬랙봇에게 '날씨'라고 말해보세요. 아래와 같은 응답을 할 겁니다.

날씨 : 약간 흐림
기온 : -2.02°
습도 : 0.63


3. 추가정보 : API와 JSON

3-1. API를 통해 얻은 json 데이터 처리하기

다른 부분은 그대로 두고, weatherFN과 같은 API 처리 부분만 살짝 수정하면, 여러분은 다양한 open API를 통해 원하는 정보를 얻을 수 있습니다. 입력된 내용을 다른 언어로 번역한다거나, 현재의 대기질 수치와 같은 정보들 말이죠. 그리고 많은 경우 open API를 통한 결과는 json이나 xml 형태로 받게 됩니다. 이는 데이터를 저장하는 형식이라고 보시면 됩니다. 요즘에는 json이 더 많이 쓰이고, 대부분의 open API들도 json을 지원합니다. weatherFN에서 Darksky API를 통해 받은 날씨 데이터는 어떤 형태로 되어있을까요?

{
"latitude":37.518252,
"longitude":127.023549,
"timezone":"Asia/Seoul",
"currently":{
      "time":1544604165,
      "summary":"맑음",
      "icon":"clear-night",
      "precipIntensity":0,
      "precipProbability":0,
      "temperature":-0.23,
      "apparentTemperature":-3.55,
      "dewPoint":-18.04,
      "humidity":0.25,
      "pressure":1029.45,
      "windSpeed":2.75,
      "windGust":5.26,
      "windBearing":319,
      "cloudCover":0,
      "uvIndex":0,
      "visibility":15.71,
      "ozone":313.26
      },
"hourly":{...}
...

}

위의 내용은 weatherFN에서 요청한 내용의 결과 값 첫 부분만 적은 것입니다. '...'으로 생략된 부분에 훨씬 더 많은 내용이 있습니다. 궁금하다면 아래 url에서 변수로 처리된 부분에 실제 값을 입력하고 웹브라우저 주소창에 넣어 확인할 수 있습니다. ${lat} 부분을 37.518252로 대체하는 식으로 말이죠.

https://api.darksky.net/forecast/${DARK_API_KEY}/${lat},${long}?lang=ko&units=si

위의 내용을 보면 결과값은 온도, 날씨, 습도 외에도 다양한 수치들을 제공합니다. 슬랙봇에 추가하고 싶은 내용이 있다면 weatherFN에 추가하면 되죠. 예를 들어, 바람세기를 추가하고 싶으면 아래의 빨간색 텍스트 부분을 추가하면 됩니다.

// API를 통해 날씨정보를 받아오는 기능 정의하기
function weatherFN(callback) { 
    request(`https://api.darksky.net/forecast/${DARK_API_KEY}/${lat},${long}?lang=ko&units=si`, { json: true }, (err, res, body) => {
    if (err) { return console.log(err); }
    var w1 = body.currently.summary
    var w2 = body.currently.temperature + "°"
    var w3 = body.currently.humidity * 100 + "%"
    var w4 = body.currently.windSpeed
    var weatherValue = "날씨 : " + w1 + "\n기온 : " + w2 + "\n습도 : " + w3 + "\n바람 : " + w4
    callback (weatherValue); 
    });
};

json의 구조와 weatherFN 부분의 코드를 보면 전체 데이터에서 특정 값을 어떻게 읽어들이는지 이해하기 쉽습니다. 예를 들어 'temperature' 값은 json 전체 데이터에서 'currently' 내에 'temperature'라는 부분의 값으로 되어있습니다. 그리고 코드에서는 w2 = body. currently.temperature로 되어있는데, body는 API로 요청한 결과값이 들어있는 데이터입니다. 그래서 해석을 해보면 'w2라는 변수는 json 전체 데이터에서 currently 데이터 하위의 temperature의 값을 가진다' 이고, json 구조 내에서 하위 데이터는 '.'으로 표시한다는 것을 알 수 있습니다. 그럼 앞으로 다른 json 데이터에서 특정 값을 가져오려고 할 때 어떻게 해야할 지 아시겠죠?

3-2. 다른 API 사용해보기

이번에는 대기질 정보를 제공하는 API를 통해 데이터를 받아와보도록 하겠습니다. AQICN.org라는 곳에서 전세계 대기질 정보를 모아서 제공하는데요, 아래의 사이트에 가서 이메일과 정보를 입력합니다.
https://aqicn.org/data-platform/token/#/

이메일 인증을 하고 나면, 발급된 data token을 확인할 수 있습니다. 이 값을 어딘가 기록해둡니다. 아래의 페이지에 가시면 api를 어떻게 사용해야 하는지, 어떤 데이터를 얻을 수 있는지 확인할 수 있습니다.
http://aqicn.org/json-api/doc/

내용을 보다 보니, 아래와 같이 lat, lng와 token을 입력하여 요청하면 값을 받을 수 있다고 하네요.
https://api.waqi.info/feed/geo::lat;:lng/?token=:token

그렇다면 소스에 AirQualityFN을 만들어서 슬랙봇에 추가해보도록 하겠습니다. 아래의 내용을 작성한 코드 맨 끝에 추가합니다. 빨간색 텍스트 부분에는 아까 받은 data token을 입력합니다.

// API를 통해 대기질정보를 받아오는 기능 정의하기
const AQICN_API_KEY = "d3ef6b001bf986c68fc4b79770f2809d94ea0000"

function airQualityFN(callback) { 
    request(`https://api.waqi.info/feed/geo:${lat};${long}/?token=${AQICN_API_KEY}`, { json: true }, (err, res, body) => {
    if (err) { return console.log(err); }
    var a1 = body.data.aqi
    var a2 = body.data.iaqi.pm10.v
    var a3 = body.data.iaqi.pm25.v
    var airQualityValue = "AQI : " + a1 + "\npm10 : " + a2 + "\npm2.5 : " + a3
    callback (airQualityValue); 
    });
};

슬랙봇이 특정 단어를 인식하고 그에 맞는 응답을 하는 부분, '날씨'를 추가한 부분 아래에 '대기질' 부분을 추가합니다.

else if(text.includes("날씨")){ 
    weatherFN(function(body) {
        rtm.sendMessage(body, message.channel);
    }) 
}
else if (text.includes("대기질")) {
    airQualityFN(function(body) {
        rtm.sendMessage(body, message.channel);
    }) 
}

그리고 저장, 이렇게만 하면 끝입니다!
이제 다시 Terminal로 돌아가서, Control + C를 하여 기존에 동작하던 슬랙봇을 중지시키고, 업데이트한 내용을 슬랙봇을 실행합니다.
node app.js

슬랙에서 슬랙봇에게 "대기질" 이라고 해보세요. 아래와 같은 응답을 할 겁니다.

AQI : 85
pm10 : 50
pm2.5 : 85

이렇게 open API를 사용하면 다양한 정보들을 얻을 수 있고, 슬랙을 통해 쉽게 표시할 수 있습니다. 수많은 정보와 서비스들이 open API를 통해 제공되니, 관심이 있으시면 여러 가지를 시도해보시기 바랍니다!

선물 : json을 가독성 좋게 변환해서 표시해주는 사이트 - http://json.parser.online.fr 


[참고##CUI##]