今天要寫下這個系列的第一支「真正會動」的資料串接程式碼。
目標檔案:src/api/tdx.js。
TDX 使用 OAuth 2.0,每次呼叫資料 API 前,都要先拿到一組 Access Token:
// src/api/tdx.js
const TDX_AUTH_URL = 'https://tdx.transportdata.tw/auth/realms/TDXConnect/protocol/openid-connect/token';
const TDX_API_BASE = 'https://tdx.transportdata.tw/api/basic/v2';
async function getAccessToken() {
const body = new URLSearchParams({
grant_type: 'client_credentials',
client_id: import.meta.env.VITE_TDX_CLIENT_ID,
client_secret: import.meta.env.VITE_TDX_CLIENT_SECRET,
});
const res = await fetch(TDX_AUTH_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body,
});
const data = await res.json();
return data.access_token;
}
// src/api/tdx.js(接續上方)
export async function fetchBusArrivals(city, routeName) {
const token = await getAccessToken();
const url = `${TDX_API_BASE}/Bus/EstimatedTimeOfArrival/City/${city}/${routeName}?%24format=JSON`;
const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) {
throw new Error(`TDX API 錯誤:${res.status}`);
}
return res.json();
}
這裡要提醒一件事:因為 syncetalite-pwa 是純前端 PWA,.env 裡的變數其實在打包後還是會出現在瀏覽器可讀取的程式碼中,這在正式的產品環境是不安全的做法。
對於這個教學系列,我們先用最簡單的方式讓功能跑起來;如果你要正式上線,建議做法是加一層自己的後端(例如簡單的 Node.js 伺服器),由後端保管金鑰、代為呼叫 TDX,前端只跟自己的後端溝通。
這個議題我會在 Day 27 效能與架構優化時再回頭討論。
在 src/main.js 暫時加入測試呼叫:
import { fetchBusArrivals } from './api/tdx.js';
fetchBusArrivals('Taipei', '0100000A00').then((data) => {
console.log('公車到站資料:', data);
});
打開瀏覽器 Console,如果有看到一串包含站牌與到站時間的 JSON 資料,就代表串接成功了!明天我們要處理這些原始資料,把它整理成好用的格式。