ใน Codelab นี้คุณจะได้เรียนรู้การสร้าง LINE Chatbot สำหรับแจ้งสถานะการส่งพัสดุแบบ Real Time ผ่าน REST API ของไปรษณีย์ไทย (ThailandPost)
จุดเริ่มต้นของการพัฒนา LINE Chatbot คือคุณจะต้องสร้าง LINE OA(LINE Official Account) และเปิดใช้งาน Messaging API
หลังจากที่เรามี LINE OA เรียบร้อยแล้ว ขั้นตอนนี้จะพาทุกคนไปเพิ่มความสามารถให้ LINE OA ของเรากลายเป็น LINE Chatbot ได้
ขั้นตอนนี้เราจะเข้าไปใช้งาน LINE Developers Console ซึ่งเป็นเว็บไซต์สำหรับการบริหารจัดการ LINE Chatbot(LINE OA ที่เปิดใช้งาน Messaging API แล้ว) ในส่วนของนักพัฒนา
เบื้องหลังของ Chatbot ตัวนี้ เราจะใช้บริการใน Firebase อย่าง Cloud Functions for Firebase และ Cloud Firestore ดังนั้นขั้นตอนนี้เราจะมาสร้างโปรเจค Firebase เพื่อใช้งานกัน
เนื่องจาก Cloud Functions for Firebase มีเงื่อนไขว่า หากต้องการไป request ตัว APIs ที่อยู่ภายนอก Google คุณจำเป็นจะต้องใช้ Blaze plan(เราจะต้องไปเรียก Messaging API ของ LINE)
Firebase CLI เป็นเครื่องมือที่จำเป็นสำหรับการ deploy ตัวฟังก์ชันที่เราพัฒนาขึ้น อีกทั้งยังสามารถจำลองการทำงานฟังก์ชัน(Emulate) ภายในเครื่องที่เราพัฒนาอยู่(Locally) ได้
npm install -g firebase-tools
Caution: หากคุณพบปัญหาในการติดตั้ง Firebase CLI แบบ globally คุณจำเป็นตัองตั้งค่า npm permission ซะก่อน
firebase --version
firebase login
mkdir bot
cd bot
firebase init functions
สำหรับใครที่มี account บนเว็บไปรษณีย์ไทยแล้วให้เข้าไปที่ หน้า Sign in แล้ว Sign in ได้เลย
สำหรับใครที่ยังไม่มี account สามารถไปสมัครสมาชิกได้ที่ หน้า Register ครับ
หลังจาก Login เข้าระบบของไปรษณีย์ไทยมาแล้ว ขั้นตอนนี้เราจะทำการ create API token เพื่อเอาไปใช้งานตอนเรียก API
Create token
ขั้นตอนนี้เราจะมาสร้าง Utility Class ที่ชื่อว่า thailandpost.js ที่จะคอยช่วยจัดการเชื่อมต่อกับ API ของ ThailandPost โดยจะจัดการสร้าง Token และ ดึงรายการสถานะการส่งของ
package.json
ขี้นมาaxios
ลงไปใน dependencies
"dependencies": {
"axios": "^0.21.1",
"firebase-admin": "^9.9.0",
"firebase-functions": "^3.14.1"
},
functions
จากนั้นสั่ง Install ตัว dependencies ที่เพิ่มเข้ามาใหม่ใน terminal ด้วยคำสั่งnpm install
thailandpost.js
ในโฟลเดอร์เดิมที่ชื่อ functions
และเขียนโค้ดตามตัวอย่างด้านล่างconst axios = require("axios");
class Thailandpost {
constructor() {
// Token ที่ได้จาก ThailandPost
this.token = 'xxxxxxxxx';
}
async getAuthToken() {
let result = null
await axios({
url: 'https://trackapi.thailandpost.co.th/post/api/v1/authenticate/token',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token ' + this.token
}
}).then((response) => {
result = response.data
}).catch((error) => {
result = null
})
console.log("Token is ready!");
return result
}
async getItemTrack(trackNo) {
const authToken = await this.getAuthToken()
const params = {
"status": "all",
"language": "TH",
"barcode": [trackNo]
}
let result = null
await axios({
url: 'https://trackapi.thailandpost.co.th/post/api/v1/track',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token ' + authToken.token
},
data: params
}).then((response) => {
result = response.data
}).catch((error) => {
result = null
})
return result
}
}
module.exports = new Thailandpost();
ขั้นตอนนี้เราจะมาสร้างไฟล์สำหรับเก็บข้อความตอบกลับหาผู้ใช้บนหน้า Chat
สร้างไฟล์ใหม่ชื่อ message.js
ในโฟลเดอร์เดิมที่ชื่อ functions
และเขียนโค้ดตามตัวอย่างด้านล่าง
exports.trackMainPayload = (postCode, trackItems) => (
{
"type": "flex",
"altText": "สถานะการส่งของ",
"contents": {
"type": "bubble",
"size": "giga",
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": `${postCode}`,
"decoration": "none",
"size": "xl",
"weight": "bold"
},
{
"type": "box",
"layout": "vertical",
"contents": trackItems,
"spacing": "sm",
"margin": "md"
}
]
}
}
})
exports.trackMainItem = (detail, bgcolor) => ({
"type": "box",
"layout": "horizontal",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "box",
"layout": "horizontal",
"contents": [
{
"type": "text",
"text": `${detail.status_date}`
}
]
},
{
"type": "box",
"layout": "horizontal",
"contents": [
{
"type": "text",
"text": `${detail.status_description}`,
"size": "sm"
}
],
"spacing": "none",
"margin": "md"
},
{
"type": "box",
"layout": "horizontal",
"contents": [
{
"type": "text",
"text": `${detail.location}`,
"size": "sm"
},
{
"type": "text",
"text": `${detail.postcode}`,
"size": "sm"
}
],
"spacing": "none",
"margin": "md"
}
]
}
],
"backgroundColor": `${bgcolor}`,
"cornerRadius": "md",
"paddingAll": "10px"
})
exports.trackNotFound = () => ({
type: 'text',
text: 'ไม่พบหมายเลขพัสดุที่ระบุ'
})
ขั้นตอนนี้เราจะมาสร้าง Utility Class ที่ช่วยจัดการส่วนที่เกี่ยวข้องกับ LINE ในการส่งข้อความกลับหาผู้ใช้
สร้างไฟล์ใหม่ชื่อ lineapp.js
ในโฟลเดอร์เดิมที่ชื่อ functions
และเขียนโค้ดตามตัวอย่างด้านล่าง
const axios = require("axios");
const LINE_HEADER = {
"Content-Type": "application/json",
Authorization: "Bearer xxxxxxxx"
}
class lineApp {
async replyMessage(replyToken, message) {
try {
const params = {
replyToken: replyToken,
messages: [message]
}
return await axios({
url: 'https://api.line.me/v2/bot/message/reply',
method: 'POST',
headers: LINE_HEADER,
data: params
}).then((response) => {
result = response.data
}).catch((error) => {
result = null
})
} catch (error) {
console.error(`Delivery to LINE failed (${error})`);
}
}
}
module.exports = new lineApp();
LineWebhook
ในไฟล์ index.js
ที่ทำหน้าที่จัดการรับ Webhook ของผู้ใช้ตามโค้ดด้านล่างconst functions = require("firebase-functions");
const thailandpost = require("./thailandpost");
const lineApp = require("./lineapp");
const msgTemplate = require("./message");
exports.LineWebhook = functions.https.onRequest(async(req, res) => {
let event = req.body.events[0];
if (event.type === 'message' && event.message.type === 'text') {
const postCode = event.message.text;
const result = await thailandpost.getItemTrack(postCode);
let { response } = result;
let { items } = response;
let key = Object.keys(result.response.items);
let payload;
if (items[key[0]].length > 0) {
let trackItems = [];
items[key[0]].forEach(function(detail) {
const bgcolor = (detail.delivery_status == 'S') ? '#ABEBC6' : '#EEEEEE';
const item_temp = msgTemplate.trackMainItem(detail, bgcolor);
trackItems.push(item_temp);
});
payload = msgTemplate.trackMainPayload(postCode, trackItems)
} else {
payload = msgTemplate.trackNotFound()
}
await lineApp.replyMessage(event.replyToken, payload);
return res.status(200).send(req.method);
} else {
return res.status(200).send(req.method);
}
});
firebase deploy --only functions
ยินดีด้วย! ถึงตรงนี้คุณก็มี LINE Chatbot ที่สามารถเช็คสถานะส่งของจากไปรษณีย์ไทย ของคุณเองแล้ว!!!