TDX 運輸資料流通服務 API 介接 - VUE Cli 範例

前言

Vue Cli 需要搭配 qs 才能順利將 content-type 改為 application/x-www-form-urlencoded 格式。另外經測試後 qs 外掛似乎只適用於版本 0.27.2 以下的 axios 外掛,不然會一直出現 400 或 415 錯誤訊息。

範例程式碼

GitHub 程式碼

GitHub Pages

❒ 安裝 vue-axios

文件:vue-axios

1
npm install --save axios vue-axios
  • 上方指令會連同 axios 一起安裝,下圖 “devDependencies” 中的 11 與 15 行。

    截圖 2022-11-02 下午5.23.19.png

  • 執行 npm i vue-axios 指令只會安裝 vue-axios。

❒ 安裝 qs

文件:npm - qs

1
npm i qs

vue-axios、axios、qs 版本注意事項

❗ 筆者測試後「axios 版本不可高於 0.27.2 版本 」不然會無法取得 api 資料。

  • vue-axios 版本:3.5.1
  • axios 版本:0.27.2
  • qs 版本: 6.11.0

怎麼降 axios 版本

使用 npm install --save axios vue-axios 安裝後,於 package.json 檔案中會看見 axios 與 vue-axios 版本為最新,可執行 npm i [email protected] 指令即可。

❒ 步驟

  1. 使用 npm 安裝 axios 與 qs 套件,上方程式碼。

  2. 全域註冊 qs 套件 ( 路徑 : 專案 / main.js )

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import { createApp } from 'vue';
    // 匯入Axios
    import axios from 'axios';
    import VueAxios from 'vue-axios';
    // 匯入qs
    import qs from 'qs';

    import App from './App.vue';
    import router from './router';

    const app = createApp(App);
    // 註冊Axios
    app.use(VueAxios, axios);
    // 全域註冊 qs
    app.config.globalProperties.$qs = qs;

    app.use(router);
    app.mount('#app');
  3. 環境變數設定 : 使用 TDX API 會有專屬的 ID 與 KEY,不建議外流,所以可於分別設定「 正式環境與開發環境的環境 」的環境變數 .env。

    1. 正式環境:.env.production ( 檔案內的資料只在正式環境被載入 )

      1
      2
      VUE_APP_TDXAPI=https://tdx.transportdata.tw/
      VUE_APP_AUTHORIZATIONAPI=https://tdx.transportdata.tw/auth/realms/TDXConnect/protocol/openid-connect/token
    2. 機敏資料:.env.local ( 檔案內的資訊在所有環境中被載入,但會被 git 忽略 )

      1
      2
      3
      4
      VUE_APP_TDXAPI=https://tdx.transportdata.tw/
      VUE_APP_AUTHORIZATIONAPI=https://tdx.transportdata.tw/auth/realms/TDXConnect/protocol/openid-connect/token
      VUE_APP_TDXID=xxxxxx
      VUE_APP_TDXKEY=xxxxxx
  4. 取得 Access Token

    1. axios 文件: Using application/x-www-form-urlencoded format

    2. 參考此文章得知,需要搭配 qs 才能順利將 content-type 改為 application/x-www-form-urlencoded,成功 !!

      1. 查看開發者工具 Network / token 右方 Headers 中的「 Request Headers & Response Headers 的 Content-Type 」皆可正常呈現。

        Response Headers 的 Content-Type

        Request Headers 的 Content-Type

      • 程式碼

        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
        export default {
        methods: {
        getAuthorizationHeader() {
        const urlPath = `${process.env.VUE_APP_TDXAPI}auth/realms/TDXConnect/protocol/openid-connect/token`;
        const parameter = {
        grant_type: 'client_credentials',
        client_id: `${process.env.VUE_APP_TDXID}`,
        client_secret: `${process.env.VUE_APP_TDXKEY}`,
        };
        this.$http({
        method: 'POST',
        url: urlPath,
        dataType: 'JSON',
        headers: {
        'content-type': 'application/x-www-form-urlencoded',
        },
        data: this.$qs.stringify(parameter),
        })
        .then((res) => {
        // 取得Access Token
        console.log(res.data.access_token);
        })
        .catch((err) => {
        console.log(err);
        });
        },
        },
        mounted() {
        this.getAuthorizationHeader();
        },
        };
  5. 取得 Access Token,呼叫 TDX API

    • 方式一 ( 較麻煩,每個 API 都要帶入 headers )

      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
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      <script>
      export default {
      data() {
      return {
      tokenCode: '',
      };
      },
      methods: {
      getAuthorizationHeader() {
      const urlPath = `${process.env.VUE_APP_TDXAPI}auth/realms/TDXConnect/protocol/openid-connect/token`;
      const parameter = {
      grant_type: 'client_credentials',
      client_id: `${process.env.VUE_APP_TDXID}`,
      client_secret: `${process.env.VUE_APP_TDXKEY}`,
      };
      this.$http({
      method: 'POST',
      url: urlPath,
      dataType: 'JSON',
      headers: {
      'content-type': 'application/x-www-form-urlencoded',
      },
      data: this.$qs.stringify(parameter),
      })
      .then((res) => {
      console.log(res);
      this.tokenCode = res.data.access_token;
      this.getBus();
      })
      .catch((err) => {
      console.log(err);
      });
      },
      getBus() {
      const url = `${process.env.VUE_APP_TDXAPI}api/basic/v2/Bus/StopOfRoute/City/Taipei?%24top=12&%24format=JSON`;
      this.$http(url, {
      headers: {
      authorization: `Bearer ${this.tokenCode}`,
      },
      })
      .then((res) => {
      console.log(res);
      })
      .catch((err) => {
      console.log(err);
      });
      },
      },
      mounted() {
      this.getAuthorizationHeader();
      },
      };
      </script>
    • 方式二 ( 使用 Axios 全域預設配置,不須每個 API 都要帶入 headers )

      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
      <script>
      export default {
      methods: {
      getAuthorizationHeader() {
      const urlPath = `${process.env.VUE_APP_TDXAPI}auth/realms/TDXConnect/protocol/openid-connect/token`;
      const parameter = {
      grant_type: 'client_credentials',
      client_id: `${process.env.VUE_APP_TDXID}`,
      client_secret: `${process.env.VUE_APP_TDXKEY}`,
      };
      this.$http({
      method: 'POST',
      url: urlPath,
      dataType: 'JSON',
      headers: {
      'content-type': 'application/x-www-form-urlencoded',
      },
      data: this.$qs.stringify(parameter),
      })
      .then((res) => {
      this.$http.defaults.headers.common.Authorization = `Bearer ${res.data.access_token}`;
      this.getBus();
      })
      .catch((err) => {
      console.log(err);
      });
      },
      getBus() {
      const url = `${process.env.VUE_APP_TDXAPI}api/basic/v2/Bus/StopOfRoute/City/Taipei?%24top=15&%24format=JSON`;
      this.$http(url)
      .then((res) => {
      console.log(res);
      })
      .catch((err) => {
      console.log(err);
      });
      },
      },
      mounted() {
      this.getAuthorizationHeader();
      },
      };
      </script>

參考資訊