Vueで日本全国ダーツの旅的なものを作ってみた


テックタッチアドベントカレンダー19日目を担当する@kosyです。
18日目は @92thunder による Vuex × TypeScriptにvuex-smart-moduleを選んだ理由 でした。
vuex-smart-moduleがどう良いのかわかる内容で理解が深まりました。型に苦しめられた過去があるからこそ今の成長があるわけですね。
vuex-smart-moduleに即決定したスピード感、さすがテックタッチ。

はじめに

日本全国ダーツの旅みたいな感じでランダムに市区町村出してくれるサイトを作りました。
場所だけじゃなく、おすすめ観光スポットも表示されます。
エンジニアに転職した今年4月当初に作ろうとしましたが、何をどうすれば良いのか全くわからず結局何も作れないまま終わりました。9ヶ月経った今なら作れる!ということで作ってみました。
ぜひ遊んでみてください。

成果物

https://random-travel.netlify.com/

作成手順

1. 市区町村コードを取得できるAPIの準備
2. Puppeteerで観光地の情報収集
3. Vueでページを作る
4. Netlifyでアップロード

1. 市区町村コードを取得できるAPIの準備

内閣府 地方創生推進室が提供するAPIで市区町村コードが取得できるため利用登録 → RESAS
↓こんな感じで都道府県コードを入力すると、その都道府県の市区町村一覧が取得できます。(市区町村一覧API)


{
    "message": null,
    "result": [{
        "prefCode": 1,
        "cityCode": "01100",
        "cityName": "札幌市",
        "bigCityFlag": "2"
    }, {
        "prefCode": 1,
        "cityCode": "01101",
        "cityName": "札幌市中央区",
        "bigCityFlag": "1"
    }, {
     
}

都道府県コードのAPIでは、パラメータが指定できないので全都道府県のコードと名前が一括で返ってきます。なので、都道府県一覧は初回だけ取得したら一覧を保持しておきました。
登録できたらAPIキーが発行されるので、これを使ってリクエストを送ります。

2. Puppeteerで観光地の情報収集

Puppeteerも業務で使用しているため勉強も兼ねて使用。
観光地情報はじゃらんから、地図画像はgoogleから取得しています。

じゃらんにした理由は、人気観光地TOP3をまとめてくれている&地域毎の観光情報のURLが市区町村コード変えればそのページに行けるものなので情報収集しやすかったからです。
地図はgoogleにあった良い感じの画像のURLを取得して表示させています。
Google maps API使えば周辺地図も見れてよかったのかもしれませんが、市区町村の緯度経度をどこかから取得する必要があり時間と気力の問題から断念。

Puppeteerは以前に書いた記事に操作方法をまとめています。基本的にはこの記事で書いた操作しかしていません。
Puppeteerで自動ブラウザ操作するときによく使う操作一覧

収集したデータは市区町村ごとに{市区町村コード}.jsonファイルで保存し、vueでランダムに算出した市区町村コードのjsonファイルを呼び出しています。

3. Vueでページを作る

開発時は発行したAPIキーは、Vueのプロジェクト直下にenv.developmentファイルを作成し、そこにVUE_APP_API_KEY=APIキーのように記載しておきます。
APIキーは悪用されると困るので直接コードに書き込むのではなく、環境変数で管理します。

APIを使ってランダムで市区町村を取得するコードは以下のとおりです。


 cityCodeList = { data: { message: null, result: [], statusCode: 0 }, status: 0 } // APIのレスポンスを格納する配列
 all: any[] = []
 prefCode: number = 0
 resultCity = {}  // 最終的に選ばれた市区町村を格納する変数
 error: string = ''

 apiKey:string = process.env.VUE_APP_API_KEY

 config = {
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': this.apiKey,
    },
  }

  mounted() {
    this.calculateDestination();
  }

  async calculateDestination() {
    this.prefCode = Math.floor((Math.random() * 47) + 1); // 都道府県を乱数で選定
    // APIを使う
    await axios
      .get(`https://opendata.resas-portal.go.jp/api/v1/cities?prefCode=${this.prefCode}`, this.config)
      .then((response) => { this.cityCodeList = response; })
      .catch((error) => { console.log(error); });

    // レスポンスエラーになっていないか確認
    if (this.checkNotError()) {
      // 市区町村を乱数で選定
      const randomCity = Math.floor(Math.random() * this.cityCodeList.data.result.length); 
      this.resultCity = this.cityCodeList.data.result[randomCity];
    }
  }

  checkNotError() {
    if (this.cityCodeList.data.statusCode) {
      if (this.cityCodeList.data.statusCode === 429) {
        this.error = 'しばらく時間をおいてから試してみてください';
      } else {
        this.error = '行き先を決められませんでした';
      }
      return false;
    }
    return true;
  }

観光情報を表示させる処理は以下の通りです。puppeteerで取得したJSONファイルを読み込むだけ。

  async fetchSpotData(cityCode: string) {
    this.draftSpotData = await fetch(`./data/${cityCode}.json`)
      .then(response => response.json());
  }

4. Netlifyでアップロード

GitHubにコードをあげたら、NetlifyとGitHubを連携させデプロイします。
APIキーはNetlifyのSettings > Build&deploy > Environment で設定すればOK。
以降の更新はgitHubにpushする度に行われます。

おわりに

アドベントカレンダーという機会がなければ、作成をずっと後回しにしてそうだったので今回は良い機会でした。
半年前は作れなかったものが作れるようになったのは嬉しい。

明日20日目の担当は@mosimosiの「型論ではなくKatalon」です!乞うご期待!