0%

前言

之前我在使用時都是直接在 Postman 上直接打 API,本來是打算自己刻 接 Richmenu API 的,但剛剛看到Python SDK 很佛心的也提供 Richmenu 相關的 SDK,如此一來就不用自己包一包了。

注意 Richmenu 圖片的方向是 由上到下、由左到右 哦!算位置記得別算錯XD

實作

設定座標

首先先使用 create_rich_menu(self, rich_menu, timeout=None)告訴 LINE 說你的 Richmenu 的基本設定是什麼,格式區域什麼個別要做什麼對應的事情,

Creates a rich menu. You must upload a rich menu image and link the rich menu to a user for the rich menu to be displayed. You can create up to 10 rich menus for one bot.

https://developers.line.biz/en/reference/messaging-api/#create-rich-menu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if usage == 'create':
rich_menu_to_create = RichMenu(
size=RichMenuSize(width=2500, height=843),
selected=False,
name="Nice richmenu", # display name
chat_bar_text="我是測試使用",
areas=[RichMenuArea( # 這邊是陣列的格式,可以動態設定自己要的區域想要有什麼功能
bounds=RichMenuBounds(x=0, y=0, width=2500, height=843),
action=URIAction(label='Go to line.me', uri='https://line.me'))]
)
rich_menu_id = self.line_bot_api.create_rich_menu(
rich_menu=rich_menu_to_create)
print(rich_menu_id)
return {'id': rich_menu_id}, 200

set_rich_menu_image(self, rich_menu_id, content_type, content, timeout=None)

上面設定完圖片裡每個座標區間要幹嘛了,接著就可以自己弄圖片或是下載官網提供的圖片

MAC 用戶的小技巧

這邊教大家一個小技巧,可以點選想使用的照片,在預覽程式裡的選擇工具->調整大小

接著看到這畫面,把依比例縮放的勾勾取消,然後把長寬調到對應的大小後就完成圖片大小的設定嚕!

https://developers.line.biz/en/reference/messaging-api/#upload-rich-menu-image

1
2
3
4
5
6
7
8
9
10
11
elif usage == 'upload':
file = request.files['the_file'].read()
rich_menu_id = request.form['richmenu_id']
content_type = "image/png"
try:
self.line_bot_api.set_rich_menu_image(
rich_menu_id, content_type, file)
except Exception as e:
print("===Upload Exception===")
raise BadRequest(e)
return {'result': 'upload ok'}, 200

set_default_rich_menu(self, rich_menu_id, timeout=None)

設定完了之後要幹嘛?就是要把他設定default啦!
不囉唆, show you the code.

Sets the default rich menu.
https://developers.line.biz/en/reference/messaging-api/#set-default-rich-menu

1
2
3
4
5
6
7
elif usage == 'set':
rich_menu_id = request.form['richmenu_id']
try:
self.line_bot_api.set_default_rich_menu(rich_menu_id)
except:
raise BadRequest("Maybe your richmenu id error.")
return {'result': 'set default ok!'}, 200

get_default_rich_menu(self, timeout=None)

糟糕,我好像瘋狂建立卻不知道有幾組?用這個就對了!

Gets the ID of the default rich menu set with the Messaging API.
https://developers.line.biz/en/reference/messaging-api/#get-default-rich-menu-id

1
2
3
4
5
6
elif usage == 'get':
rich_menu_list = self.line_bot_api.get_rich_menu_list()
total = []
for rich_menu in rich_menu_list:
total.append(rich_menu.rich_menu_id)
return {'result': total}, 200

delete_rich_menu(rich_menu_id)

不行,我弄的座標什麼全錯怎麼辦?有時候上傳的圖片可能不是自己想的那樣?,透過這個方法來刪掉它

Deletes a rich menu.
https://developers.line.biz/en/reference/messaging-api/#delete-rich-menu

1
2
3
4
5
6
7
elif usage == 'delete':
rich_menu_id = request.form['richmenu_id']
try:
self.line_bot_api.delete_rich_menu(rich_menu_id)
except:
raise BadRequest("Maybe your richmenu id error.")
return {'result': f'{rich_menu_id} is delete!'}, 200

結論

我都把 raise 打成 rails (大誤),LINE 幫忙做的 SDK 真的是好用,透過這次練習我也多學了好多不一樣的用法,順便把自己的腦袋也整理一下 😃,程式碼同步在這邊哦 URL

Rich menu 是一個 LINE 提供給 chatbot 的圖文選單,可以再上面設定很多各式各樣的功能,下圖為一個範例

優點

  • 擁有長板 & 短板的圖片支援,讓一張圖片不再是一張圖片,機器人看起來可以更有品牌風格,根據 User 喜好、訂閱功能或是下一頁 Menu(即時切換)等等不同創意巧思,且可以客製化圖片讓機器人看起來有更不一樣的特色,也讓對話是互動並不限於對話,而圖片來讓使用者可以更直觀地去使用機器人。
  • 一個 Chatbot 可以設定 1000 組的功能選單
  • 針對不同 user ID 顯示不同功能選單
    Rich menu 可以自己設計圖片並上傳,再透過 JSON 的樣式去設定圖片區間要進行各種用途,這邊使用 Youbike 小幫手為範例,設定很多相關的設計,並設計上下頁的選單提供像是 APP 的操作。

限制

  • 圖片格式: JPEG、PNG
  • 圖片尺寸: 2500x1686, 2500x843, 1200x810, 1200x405, 800x540, 800x270
  • 圖片大小: 1 MB

步驟

  1. 先準備一個圖片
  2. 對這個 API 下圖片每個位置要做什麼事 https://api.line.me/v2/bot/richmenu
  3. 接著上傳圖片給 LINE https://api.line.me/v2/bot/richmenu/richmenu-{id}/content
  4. 設定預設 https://api.line.me/v2/bot/user/all/richmenu/richmenu-{id}

結論

有很多的文章都有介紹過類似的功能,這邊簡介一下限制以及下篇要做的步驟~


前言

以前從花落落的文件中找到一個方法,像是使用 push message

我都會笨笨的 call API 的方法去執行功能,殊不知 SDK 早就包好了,然後邊做邊罵自己為什麼要解這些 JSON (拍桌)
到了現在比較會看文件,才知道原來以前是自己雷自己 (捶心肝)…接下來就試玩幾個我覺得常會用到的 method 好了不廢話了,來簡單介紹一下一些常用的方法 😎

get_profile

回傳使用者的個人狀態,可以透過每次的 reply 去拿到使用者的資訊,一般使用的話都話把它存下來,等之後有介接其他服務時方便使用 userId 去判斷使用者。

1
2
3
4
5
6
7
8
9
10
11
12
13
profile = line_bot_api.get_profile(event['events'][0]['source']['userId'])

try:
with Database() as db, db.connect() as conn, conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
cur.execute(
f"INSERT INTO users(id, name, picture) VALUES ('{id}', '{name}', '{picture}')")
except:
pass # 這邊簡單處理相同 id 的問題(id我有設 Private key 哦!)
state = f"Hello 👉 `{profile.display_name}` 👈"
line_bot_api.reply_message(token, [
TextSendMessage(text=state),
ImageSendMessage(original_content_url=profile.picture_url, preview_image_url=profile.picture_url)
])

這邊搭配 ImageSendMessage 來幫忙發送圖片,他主要是透過 original_content_url 以及 preview_image_url 這兩個參數來幫忙轉成圖片

  • original 就是讓使用者看到的圖片
  • preview 在還沒載入時的樣子

push_message

既然都取到使用者的 id 了,下一步就是推訊息給使用者啦!

建立一個 GET 的路由在 /webhook 上,收到 query string 的 msg 的值並找到所有使用者的 id 並逐一推送訊息。

1
2
3
4
5
6
7
8
9
10
11
12
line_bot_api = LineBotApi(os.getenv('LINE_CHANNEL_TOKEN'))
handler = WebhookHandler(os.getenv('LINE_CHANNEL_SECRET_KEY'))

def get(self):
msg = request.args.get('msg')
with Database() as db, db.connect() as conn, conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
cur.execute("SELECT * FROM users")
fetch = cur.fetchall()
for user in fetch:
self.line_bot_api.push_message(
user['id'], TextSendMessage(text=msg))
return {'message': msg}, 200


Reply Mode

LocationSendMessage

這邊直接拿 SDK 的範例來用,若是有在做商家功能的機器人可以使用這個方式讓使用者接收到商家訊息~

1
2
3
4
5
6
self.line_bot_api.reply_message(token, LocationSendMessage(
title='my location',
address='Tokyo',
latitude=35.65910807942215,
longitude=139.70372892916203
))

StickerSendMessage

這個方法可以搭配使用,讓整個回應看起來跟真實吧!

不知道清單能用什麼可以參考

1
self.line_bot_api.reply_message(token, StickerSendMessage(package_id='1',sticker_id='1'))

Button Template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
buttons_template_message = TemplateSendMessage(
alt_text='Buttons template',
template=ButtonsTemplate(
thumbnail_image_url=f'{picture}.jpg',
title='Menu',
text='Please select',
actions=[
PostbackAction(
label='postback',
display_text='postback text',
data='action=buy&itemid=1'
),
MessageAction(
label='message',
text='message text'
),
URIAction(
label='uri',
uri='http://example.com/'
)
]
)
)
self.line_bot_api.reply_message(token, buttons_template_message)

結論

簡單玩了幾個 API,大概就這幾個比較常搭配著使用,用過之後才知道其實有好多 API 我都還不是很清楚用法 🤣
而 LINE 最近更新了他們文件的功能,多了一個Try的按鈕提供使用者可以線上直接測 API,只是像是 push messages 這個就剛好沒有 😓,但至少有很多 API 不用通靈去測試,直接拿著 Token 在網頁上測試嚕!
Doc Sample

Code is here

參考

LINE develop page

實作

新增兩個 LINE Channel key 至 .env

1
2
LINE_CHANNEL_TOKEN=
LINE_CHANNEL_SECRET_KEY=

接著加入 LINE 的 python SDK 至 requirements.txt

1
line-bot-sdk==1.12.1

透過 pip 安裝一下

1
pip install -r requirements.txt --user

在 controller/ 底下新增一個 message_api_controller.py 並輸入以下程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from flask import Flask, request, abort
from flask_restful import Resource
import json
import os
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)


class LineMessageApiWebhookController(Resource):
def post(self):
line_bot_api = LineBotApi(os.getenv('LINE_CHANNEL_TOKEN'))
handler = WebhookHandler(os.getenv('LINE_CHANNEL_SECRET_KEY'))

# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']

body = request.get_data(as_text=True)
event = json.loads(body)
print(event)
try:
handler.handle(body, signature)
except InvalidSignatureError:
print(
"Invalid signature. Please check your channel access token/channel secret.")
abort(400)

token = event['events'][0]['replyToken']
if token == "00000000000000000000000000000000":
pass
else:
line_bot_api.reply_message(token, TextSendMessage(
text=event['events'][0]['message']['text']))
return 'OK'

用任何語言都會看到回傳會有 200, ‘OK’…回傳的成功訊息,在內部系統的部分在處理時要考慮到回傳時間的問題,一般來說如果回傳的時間大於 1 秒的話就有可能失效,或許有些朋友有測試過大於 1 秒也可以,但最好還是於時間內回覆哦!

以下圖片來自 https://engineering.linecorp.com/zh-hant/blog/line-device-10/

https://engineering.linecorp.com/zh-hant/blog/line-device-10/

接著在 api.py 加入下面兩段 code,新增一個webhook的路由

1
2
from controller.message_api_controller import LineMessageApiWebhookController
api.add_resource(LineMessageApiWebhookController, '/webhook')

這邊可以使用sls wsgi serve + ngrok去搭配做測試

接著就部署啦

1
sls deploy

現在在接這種第三方的 API 時最好都使用 https,而使用 Serverless 的好處就是 AWS 在部署完之後會送你一個含有 SSL 的網址~

把網址貼到 webhook URL 上並在尾端加上 /webhook

測試結果如下

結論

這次整合了以前寫的 Repo,加入了.env讓我在抓下來使用時也更方便,也整合成 Restful 格式讓之後有需要的人在看 code 時可以更容易理解了~

專案也會持續更新,更多詳情可以 follow 我的專案 aws-python-line-api

前言

今天會帶大家如何一步一步的建立 Message api 以及需要注意設定的地方。

實作

  1. 首先先到 https://developers.line.biz/zh-hant/ ,點選右上角的大頭貼並選擇 Add new provider
  2. 接著在 Provider name 填上自己的想要的名稱
  3. 再次確認
  4. 選擇想要使用那種服務,這邊我們就選擇Message API並按下Create Channel
  5. 接著就開始填寫自己的機器人(channel)所需要的資訊嚕!
  6. 這邊我們需要填寫的內容為
    6.1. 大頭貼(option)
    6.2. 名稱 App name (required)
    6.3. 描述 app description (required)
    6.4. 類別與子類別 Catagory (required)
    6.5. 信箱 Email address (required)
    6.6. 政策網址 Policy URL (option)
    6.7. 服務條款網址 Term of use URL (option)



  1. 當填寫完之後的寫一步最後會需要勾兩個服務說明確認的選項並按下 Create
  2. 如此一來就看到自己百般折騰建立出來的 Message api 啦
  3. 滑到最下面,首先掃描 QR code 加入自己機器人的好友讓接下來好測試,接著按下圖篇右手邊的 Set message 進入調整頁面
  4. 進入之後到下面,將歡迎訊息 & 自動回應 停用,並將 Webhook 打開,讓之後的串接可以透過 Webhook 打到 Serverless 上,若是前兩個回應的選項沒有關的話即使 Webhook 有啟動也會因為優先權問題被擋下來哦!

簡介

LINE 在 2016 年 9 月底發表了 Messaging API 功能,用戶可以透過 Messaging API 將自家的服務內容串聯到 LINE@ 上。

接著在 2019/04/18 之後 LINE@ 2.0 正式上線,在 5/22 後有升級的選項並會陸續更新,升級完的官方帳號也可以申請專屬 ID、進行帳號認證。

我認為比前一版本的最大的好處是在好友無上限的這部分,以前只能有 50 位好友,若一般開發者的機器人好不容易上線了並開放測試時被限制住,除了再開一隻機器人或是其他方法就超麻煩,現在好友無上限了,就不會有上述的問題了。

若您以前有開發過的機器人到現在還沒升級的話,可以參考 -> URL

這邊需要注意 1 on 1 聊天與 Messaging API 是無法同時使用的,但可以在後台切換看要使用哪種模式與顧客互動。對話記錄也會保存在各自的模式下,若要查看完整的對話記錄的話會建議以固定模式與顧客進行互動哦!

主要的功能環繞在以下兩點

  1. Push mode: 主動推播訊息給用戶,2.0 每個機器人都有 500 則免費推播則數,超過則數的話可以參考以下的價目表:

  1. Reply mode: 這個模式是接受使用者的訊息並透過 webhook 打到伺服器上讓伺服器去做對應訊息的處理,重點是它是是免費、免費、免費的!所以若能引導使用者去輸入訊息的話用這個模式是不用錢的哦 🎉

Message API 支援以下格式

  • Text message
  • Sticker message
  • Image message
  • Video message
  • Audio message
  • Location message
  • Imagemap message
  • Template message
  • Flex message

詳細內容可以參考 LINE doc

line sample 1
line sample 2

回傳格式

Message API 回傳格式都是一個陣列的格式,一開始在接的時候都沒注意到一直瘋狂出錯,事實上這樣陣列對 Server 有個好處就是當一次需要送較多訊息時格式會比較統一,只是對於有潔癖的開發者來說每次都要多打[0]會覺得有點髒 🤣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
'events': [{
'replyToken': '00000000000000000000000000000000',
'type': 'message',
'timestamp': 1568983962754,
'source': {
'type': 'user',
'userId': 'Udeadbeefdaaaaefdeadbeefdeadbeef'
},
'message': {
'id': '100001',
'type': 'text',
'text': 'Hello, world'
}
}, {
'replyToken': 'ffffffffffffffffffffffffffffffff',
'type': 'message',
'timestamp': 1568983962754,
'source': {
'type': 'user',
'userId': 'Udeadbeeaaaaefdeadbeefdeadbeef'
},
'message': {
'id': '100002',
'type': 'sticker',
'packageId': '1',
'stickerId': '1'
}
}]
}

結論

以前剛開始接 LINE Message API 的時候都覺得他的文件不太人性,更新到現在文件內容也越來完整,讓開發者在開發的過程中不用再為了找不到文件而放棄了(我以前就是 🤣),下一篇將會帶來如何申請一隻機器人到如何建立一個 webhook API 到 AWS 上

參考

功能介紹】Messaging API
LINE message template

首先先建立一個consumer/資料夾,新增__init__.py以及notify_handler.py

notify_handler.py輸入以下程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import json
import requests


def line_notify_handler(event, context):
print(event)
body = json.loads(event['Records'][0]['body'])
print(body)
headers = {
'Authorization': f"Bearer {body['token']}",
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('https://notify-api.line.me/api/notify',
headers=headers,
data={'message': body['message']})
print(r)

# AWS record sample
# {'Records': [{'messageId': 'fddc42ba-a122-4581-965e-d0144ac8a5ad', 'receiptHandle': 'AQEBjO32gY5pXOfOrmDR0hD4k1av9KyjbHFpc+rIBPV2Brif7Lo+jqnGevSjfFwlICyGf+BhWwKaxFw8XdB3QTzRbw0vnLURjnQeDSBrJHa/S57SRs9TOLRBq38maycAVg69iZbetg9VhLMBCcLtOtPHTzKkmo+/Sosm51WA5CzXK7A0rteikx6nxS1CUIpq6MAujodupP0Hgr5RjK5nH/nmxA4Db0leWEmLokalZbtlx4W14tp7PZxPOrQOLDaGrH//p4h32tY8IN3MkCqi+gyNT7kCU4KwCGOIrybb07ZWyKBTKw+KOMNr/Ykj4z2N1qxIvTM55UY9d8V29YsH32OjrZTei5P7Nke/51E2tWkmkqoFAlqzxDjQPvpP+Pvvr8aazeeZ6opkr59UefAiiyM71Q==', 'body': 'hi', 'attributes': {'ApproximateReceiveCount': '9', 'SentTimestamp': '1566621263072', 'SenderId': '901588721449', 'ApproximateFirstReceiveTimestamp': '1566621263072'}, 'messageAttributes': {}, 'md5OfBody': '49f68a5c8493ec2c0bf489821c21fc3b', 'eventSource': 'aws:sqs', 'eventSourceARN': 'arn:aws:sqs:us-east-1:901588721449:LINE_notify_consumer', 'awsRegion': 'us-east-1'}]}

接著在requirements.txt加入boto3,他是一個使用 python 介接 AWS 的套件

1
boto3==1.9.189

加入SQS_URL以及SQS_ARN.env裡面

1
2
SQS_URL=sqs url
SQS_ARN=your sqs arn

add controller/notify_sqs_controller.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from flask_restful import Resource, reqparse
import json
from lib.db import Database
import psycopg2.extras
import os
import boto3


def send_message(url, attr, body, delay=0):
cli.send_message(
QueueUrl=url,
DelaySeconds=0,
MessageAttributes=attr,
MessageBody=body,
)


class SendNotifyBySQSController(Resource):
cli = boto3.client("sqs", region_name=os.environ("region"))

def post(self):
parser = reqparse.RequestParser()
parser.add_argument(
'message', required=True, help='message can not be blank!')
args = parser.parse_args()
msg = args['message']
with Database() as db, db.connect() as conn:
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
cur.execute(
f"SELECT token FROM notify")
fetch = cur.fetchall()
for f in fetch:
body = {
'token': f"Bearer {f['token']}",
'message': f"Hello everyone, {msg}"
}
cli.send_message(
QueueUrl=os.environ("SQS_URL"),
DelaySeconds=0,
MessageAttributes={},
MessageBody=json.dumps(body),
)
return {'result': 'ok'}, 200

程式寫完了就是要加一條路由/notify/sqs

1
2
from controller.notify_sqs_controller import SendNotifyBySQSController
api.add_resource(SendNotifyBySQSController, '/notify/sqs')

接著透過wsgi在本地起一個 server

1
sls wsgi serve

再搭配 postman 來做測試,測試內容如下

1
2
3
{
"message": "test Content"
}

接著透過sls deploy部署上會遇到一個問題,會有 Access Denied,所以要在serverless.yml加入 IAM role 的設定

add iam in provider

1
2
3
4
5
6
iamRoleStatements:
- Effect: Allow
Action:
- sqs:SendMessage
Resource:
- ${env:SQS_ARN}

測試


結論

使用 SQS 這類服務都會需要透過boto3來幫忙串接,最需要注意的就是 IAM role,因為在本地端的 key 通常權限都是最大的,但上到 AWS 上就會有權限的問題,所以要記得加入 IAM 哦!

Code is here

專案也會持續更新,更多詳情可以 follow 我的專案 aws-python-line-api

詳細介紹

以前自己在架伺服器的時候,提到訊息佇列不外乎都是 RabbitMQ 或是 Kafka,只是現在 AWS、GCP 這類的雲端平台都越來越火紅了,手動按一下服務就建好了(信用卡也在哭泣),省去很多建立服務的時間,只是說一般時候根本找不到項目練習 😓,剛好最近在複習 LINE Notfiy,就趁這個機會順便練習並記錄一下 ✌️

你需要先了解…

當 Http requests 非常大量到一定程度,database 已經跟不上處理的速度,尤其是 relational database,這時就需要 queue 來緩衝;所以社群網站像 Facebook or LinkedIn 都使用大量的 message queue and cache.
By -> Leonard Lee

SQS 就是 managed queue service,主要就是 async, central messaging (對相對應的程式來說,通常處理 api 的會有多個 instances 同時存在,像是 auto-scaling),像是 fb 通知、寄送 email 認證信這種不用即時處理的情況,只要給訊息給 queue 讓其他服務或程式去處理,可以把原本的邏輯簡化(以及責任區分),甚至些事件是預期同時會有多個 listener 會需要處理的情況,在一個 api 裡面去處理這些會讓邏輯變很複雜/不好維護。
By -> Bill Chung

還有就是如果負責處理 request 的 host 有問題,message queue 可以用來短暫儲存還未被處理的 requests 使他們不至於丟失,直到 host 回復正常或是換了一個好的 host 後,message queue 裡面的的 requests 就可以繼續被處理
By -> 盧元駿

以上來自我之前寫過的文章 使用 Serverless 讓 AWS SQS 幫你發送 LINE Notify

今天在需要發個請求去呼叫 LINE API(或是其他服務的 API),都可能會碰到圖片,圖片不管他怎麼壓縮,終究還是比文字肥,在數量多的情況下可能就會發現 API 罷工(就會像被斷詠唱一樣)。雖然平常使用可能不會這麼平凡呼叫,但若在商業用途上使用者多的時候一次呼叫就會有一大筆,這時候用 Queue 讓他們排隊一個一個來就在適合不過了 🎉。

為什麼選擇 AWS SQS

Amazon Simple Queue Service (SQS) 是全受管訊息佇列服務,可讓您分離和擴展微型服務、分散式系統及無伺服器應用程式。SQS 可免除與管理和操作訊息導向中介軟體相關的複雜性及開銷,也可讓開發人員專注在與眾不同的工作上。您可以使用 SQS 在軟體元件之間傳送、存放和接收不限數量的訊息,不會遺失訊息或需要其他服務可用。使用 AWS 主控台、命令列界面或自選的 SDK 以及三個簡單的命令,即可在幾分鐘內開始使用 SQS。(參考 AWS)

SQS 有在免費方案裡面,只要一個月別高於 100 萬個請求就不會被收錢啦 💪

AWS 的免費方案可以參考 -> LINK

建立 SQS

接著就要開始引入 SQS 嚕,首先到 AWS 上的 SQS 頁面,如下


接著選左邊的Standard Queue並填入 name 就好


建立完之後就可以看到下面有建立完的資訊

ARN 以及 URL 接下來都會用到哦

結論

接下來會帶各位使用 Notify 接在 SQS 上,這篇就先帶各位介紹並先手動建立一個 Queue,之後會在大家使用 python 的 boto3 的套件來搭配使用 AWS 服務使用 👏

前言

看著前幾天的文章,像我們 notify 驗證的 API 有使用到 REDIRECT_URICLIENT_ID 以及 CLIENT_SECRET,或是像 PostgreSQL 的帳號密碼,
只是說若今天當程式碼變多的時候,抑或是這個參數有給其他 API 使用,那在尋找的時候不僅費工又浪費時間
那接下來就帶著大家在 serverless.yml 一步步加入變數值,並更改 code。

動手吧!

用 npm 安裝 serverless 的 dotenv 套件

1
npm i -D serverless-dotenv-plugin

接著加入新的套件到serverless.yml

1
2
plugins:
- serverless-dotenv-plugin

新增dotenv到 requirements.txt

1
python-dotenv==0.10.3

到 api.py 加入下面內容

1
2
3
from dotenv import load_dotenv
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)

接著新增.env並輸入對應的內容

1
2
3
4
5
6
7
8
9
10
11
NOTIFY_REDIRECT_URI=
NOTIFY_CLIENT_ID=
NOTIFY_CLIENT_SECRET=
REGION=us-east-2
SQS_URL=
SQS_ARN=
PG_DB=
PG_HOST=
PG_NAME=
PG_PWD=
PG_PORT=

接著修改有使用到他們的地方,範例如下

1
2
import os
os.getenv("SQS_ARN")

既然有安裝 serverless 的套件了,那 yml 檔也可以使用哦!

1
2
3
4
provider:
name: aws
runtime: python3.7
region: ${env:REGION}

後記

有時候把專案抓下來的時候要找到這些輸入的地方很容易找不到(我有點癡呆),一般 open source 也都會有一個.env的,用serverless-dotenv-plugin來幫忙弄就方便許多了,後續有需要再繼續往裡面新增就好了~

最後在搭配 python 的 dot env 套件使用就讓整個好用多了 🤣,只是說 html 因為目前還不是透過 serverless 來幫忙部署,所以這邊的參數就沒辦法吃設定檔了 😓

參考

os.environ
env setting

繼上一篇我們已經可以讓使用者註冊 Notify 並將 token 放入資料庫,接著就帶各位使用 query string 的方式讓你的 Notify 可以送訊息給所有註冊過的 Notify。

首先我們進入我們已經建立過的 controller/notify_controller.py,會看到 class 下有我們之前建立的 post method,這時我們就在前面加入 get method,並加入以下的 code,讓這個 class 看起來比較有順序(潔癖)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import request

class NotifyController(Resource):

def get(self):
msg = request.args.get('msg')
with Database() as db, db.connect() as conn:
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
cur.execute(
f"SELECT token FROM notify")
fetch = cur.fetchall()
for f in fetch:
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': f"Bearer {f['token']}"
}
payload = {'message': msg}

r = requests.post(
'https://notify-api.line.me/api/notify', data=payload, headers=headers)
return {'result': 'ok'}, 200

def post(self):
...

這次使用的套件比上次多 import 一個 flask 底下的 request (注意沒有 s 哦),這個主要是讓我們可以抓到網址問號後面接的參數,這邊我設定打 API 的人會打一個 msg 的參數。

接著就是使用進 DB 撈我們的 token 們,並用一個迴圈來跑

再來是設定 headers 以及 payload

headers 的部分參考 Notify 的文件,如下圖

我們需要設定 Content-Type 以及 Authorization,需要注意的是 Authorization 是使用 Bearer 格式(參考),他中間是有加空白鍵的,這邊很多朋友都會錯在這裡,千萬要記得檢查這邊!

接著是要送出去的東西是要用什麼送出,本篇只用 message 做範例,若需要使用到其他的功能,像是圖片、貼圖等等的可參考以下的圖片

接著我們就可以使用sls deploy來部署我們的程式啦

等等!
這邊有個需要注意的地方是,照著這次的範例使用的話會需要用 docker 來幫忙跑編譯,因為 psycopg2-binary 這個套件如果不是在 Linux 的環境下會需要透過 docker 幫忙編譯完再丟過去
這部分需要在serverless.yml下填入參數

1
2
3
custom:
pythonRequirements:
dockerizePip: true

如此一來當前環境若不是 Linux 的話他就會使用 docker 來幫忙,記得 docker 要開哦 🙏

當然最簡單的方法就是把它直接抓下來放在專案中,只是這樣就會比較髒一點,可以從這邊抓 -> 參考

這邊可以先在環境變數上加上SLS_DEBUG=* 接著在加上 sls deploy 後面加上--verbose可以看到 serverless 到底都在背地裡做了什麼事情 🤣

接著我們就使用 Postman 來幫我們送字串出去,參考下圖,當回傳 ok 就成功了 🎉

你的 Notify 應該要回你了~

結論

這邊帶大家做一個簡單的應用,一般來說我覺得放在 query string 讓其他 API 來呼叫的時候帶參數來就可以直接用是很方便的,不用再特地自己寫方法去呼叫 LINE Notify 來幫我們送,反正 AWS Lambda 有一百萬次的請求不怕 🤣