본문 바로가기
Study/Slack

Slack 이미지 업로드 API 사용하기 (Slack image upload API) - 2024년 5월 이후 기준

by Zeromk2 2024. 9. 18.
728x90

29CM QA팀에서는 테스트 자동화가 Fail이 될 경우 해당 장면의 스크린샷을 찍어서 슬랙 자동화 리포트에 업로드 하는 방식을 사용하고 있습니다. 

아마 테스트 자동화를 활용하시는 다수의 QA분들도 이미지 업로드 방식을 사용하실 것 같은데요 이번에 새로운 앱을 생성해야 하는 상황이 생겨서 Slack에 앱을 추가해서 해당 앱으로 테스트 리포트를 Slack에 발행하도록 변경했는데 이미지만 업로드가 되지 않는 상황이 발생했습니다. 

아 왜 또 뭐

 

일단 과거에 잘 사용했었던 API 페이지로 가봤습니다. 

 

files.upload API method

Uploads or creates a file.

api.slack.com

 

그랬더니 이런 내용이 있는 것을 발견했습니다.

 

2024년 5월 8일 이후에 생성한 앱은 위의 API를 사용할 수 없는 것이였습니다.

그래서 코드 수정이 필요했습니다.

결국 위에서 이야기 하고 있는 files.getUploadURLExternal과 files.completeUploadExternal를 사용하는 방법을 찾기 시작했습니다.

 

이 방식은 꽤나 까다로웠습니다.
(사실 제가 Slack SDK를 안쓰고 API로만 Slack에 리포트를 보내고 있기 때문에 더 까다로웠을 수 있습니다.)

일단 이런 일련의 단계가 필요합니다.

  1. files.getUploadURLExternal 로 응답을 보내서 "upload_url" 과 "file_id" 를 받습니다. 
  2. 응답으로 받은 upload_url로 이미지 업로드를 합니다.
  3. files.completeUploadExternal 로 요청을 보낼 때 "file_id" 를 payload에 포함하여 보냅니다.

 

다시 각 단계별로 자세히 보면 이렇습니다.

1. files.getUploadURLExternal 로 응답을 보내서 "upload_url" 과 "file_id" 를 받습니다. 

이미지가 동일 폴더에 error.png라는 파일로 있을때를 가정합니다.
해당 파일의 크기가 필수요소이기 때문에 len(content)로 크기를 체크합니다. 

img_src = os.path.abspath('error.png')

headers = {
    'Content-Type': 'application/json',
    'Authorization': f'Bearer {slack_token}'
}
# 이미지 업로드
try:
    with open(img_src, 'rb') as f:
        content = f.read()
except FileNotFoundError:
    content = None
if content is not None:
    data = {
        "filename": "error.png",
        "length": len(content),  # 파일 크기(바이트 단위)
    }
    headers['Content-Type'] = 'application/x-www-form-urlencoded'
    response = requests.post(url="https://slack.com/api/files.getUploadURLExternal", headers=headers, data=data)

 

2. 응답으로 받은 upload_url로 이미지 업로드를 합니다.

이부분이 최대의 삽질이였습니다. 일단 Slack API 페이지에 이 내용이 자세히 없었습니다.

1번에서 응답으로 받은 'upload_url'을 사용해서 POST 요청을 보냅니다. file로는 위에 있는 이미지 객체를 사용합니다.

upload_response = requests.post(url=file_id.get('upload_url'), files={'file': content})

200 응답으로 오면 성공입니다.

이제 실제 Slack에 보낼 차례입니다.

 

3. files.completeUploadExternal 로 요청을 보낼 때 "file_id" 를 payload에 포함하여 보냅니다.

attachment = {
    "files": [{
        "id": file_id.get('file_id'),
        "title": "error.png"
    }],
    "channel_id": channel_id, # 업로드할 채널 ID
    "thread_ts": thread_ts # 스레드에 보내고 싶다면 스레드 ts포함
}
headers['Content-Type'] = 'application/json; charset=utf-8'
upload_response = requests.post(url="https://slack.com/api/files.completeUploadExternal", headers=headers, json=attachment)

 

이러면 짠. 이미지가 업로드 됩니다. 

이전에 비해 단계가 많아지고 복잡도가 높아졌지만 다시 이미지 업로드가 가능해졌다는 것에 즐겁네요. 

내일 코드 정리해서 팀 자동화 프레임워크에 올려야겠습니다~

댓글