[国交DPF] API紹介③：指定したキーワードと緯度経度で検索する方法

# 指定したキーワードと緯度経度で検索する方法

[国交DPFアドベントカレンダー2023](https://qiita.com/advent-calendar/2023/mlit-dpf)　9日目の記事となります。

こんにちは～すっかり世間はクリスマスシーズンですね！<br>
~~なんかさみしい気持ちになる~~外は寒すぎるので連日おうちに引きこもってDPFを触っている日々ですｗ

と、いうことで今日は国交DPFに掲載されているAPIのサンプルコードを試しに使ってみました！！(唐突)

# APIドキュメントって知ってる？
昨日までの記事（[API紹介①](https://qiita.com/dpf_hirometai/items/6a594e8dfe85da0bb499)&
[API紹介②](https://qiita.com/dpf_hirometai/items/03d3f9b55ad573c85c6c)）はご覧頂けましたでしょうか。<br>
これを読んで、
*API触ってみたい！！でもどうせやるなら本格的に環境構築から始めたい！！あとなんかちょっと凝った感じのクエリたたいてみたい！！*
という願望を抱いてしまいました。形から入るとやっぱやる気出ますよね！(笑)

### 実はそんな願望が叶っちゃうんです！！！


そう、国交DPFならね。
ということで国交DPFトップページの下にある「開発者向け情報」にアクセスしてみましょう。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/65d4bb29-ffb2-c54f-1a64-f5fefe673c42.gif" width="600px">  

こんなページが出てくると思います。そこから、「APIドキュメント」をクリック。<br>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/ff635470-441e-db1b-4a88-33fca97c9cd5.png" width="600px">  

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/49ddb4b7-8e48-13cb-ead1-b224f839be7d.png" width="600px">  

このページでは、APIドキュメントはもちろん、サンプルプログラムなどのお助け情報が沢山のっているんです！初心者にもやさし～い！<br>
ということで、APIをたたくための環境構築＆サンプルプログラムを触ってみよう大会の始まりです！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/5653ffa8-7935-4c63-7af7-b5f59ad99dd8.png" width="600px">  


 # 環境構築＆サンプルプログラムを触ってみよう大会～第１部：環境構築～
APIドキュメンテーションのトップページから[「APIサンプル」](https://www.mlit-data.jp/api_docs/examples/introduction.html)ページでは、サンプルプログラムだけでなく、実行環境の構築方法についても載っています！<br>
なるほど、これは[「Node.js」](https://nodejs.org/en)の実行環境で試せるんですね？<br>(ちなみにNode.jsとは、JavaScriptを使ってサーバーサイドでアプリケーションを開発するためのプラットフォームです。JavaScriptはwebブラウザ上で扱うプログラム言語なのですが、Node.jsをつかうとサーバー側でも実行ができるようになります！)

 <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/d702ece4-c3ab-0875-07b1-eae30b10b581.png" width="600px">  

ここから「実行環境の準備」にアクセスしてみましょう。<br>
...めっちゃ丁寧に書かれてる!!

 <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/1a219a04-8b88-4c9b-2bec-adb2d74d2826.png" width="600px">  

 と、いうことでここに書いてある手順にしたがって環境構築をしてみました！

>1.Node.jsをダウンロードし、インストールしてください。

リンクからインストーラをダウンロードしてインストール完了！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/7133adfc-09ac-f542-f32d-e4860793694d.png" width="600px">  

>2.コマンドライン以下のコマンドを実行しNode.jsが正しくインストールされているかを確認してください。
>>node --version 

コマンドプロンプトを開いてポチポチしたらバージョン情報が出てきましたね！OKそうです！<br>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/d27e4ea4-9459-966c-95b9-243f8f0d0756.png" width="600px">  

>3,フォルダを作成しダウンロードしたサンプルソースコードのファイルをコピーしてください。ここではprojectというフォルダを作成したと仮定します。

ダウンロードしたサンプルソースコード、、あった！！「サンプルプログラム」ページからダウンロードできますね！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/79a51e26-a8fe-08a6-c278-7a64c1ccc1b8.png" width="600px"> 


これを解凍してとりあえず任意のフォルダに置いて、、っと。

>5,コマンドラインで作成したprojectフォルダに移動し以下のコマンドでaxiosライブラリをプロジェクト内にインストールしてください。
>>npm i axios

できた！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/7d464d69-52fd-8795-951a-028daa9f30bd.png" width="600px">  

>6,API のキーを取得し、各サンプルソースコードにあるAPI_KEYの値を取得したキーに置き換えてください。

まずはAPIのキーを取得しましょう。
DPFのページ下部の人マーク、「アカウント」ページより「アカウントの管理」にアクセス。<br>
「アプリケーションの新規登録」よりAPIキーを発行しましょう。<br>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/60184fb2-26ee-ab55-08a6-28ad8f03e994.png" width="600px"> 

発行した「app_〇〇」のボタンを押すと、取得したAPIキーが出てくるので、これをソースコードにコピーします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/a791ad00-98c8-378f-65b5-e6d24f65fe5f.png" width="600px"> 

>7,各サンプルをnode ファイル名で実行できます。

これで実行できるんですね！やったー！

node ファイル名で実行っと、、、としたいところですが、折角ならプログラムの中身を見ていきたい！ということで、環境構築＆サンプルプログラムを触ってみよう大会（今更ですが名前イケてないな）第２部、プログラムを触ってみようにいきたいと思います！

# 環境構築＆サンプルプログラムを触ってみよう大会～第２部：プログラムを触ってみよう～

国交DPFのサンプルプログラムのページには３つのサンプルプログラムが用意されています。先ほど、環境構築でサンプルプログラムをダウンロードする際に出てきた↓のページです。[リンクはこちら！](https://www.mlit-data.jp/api_docs/examples/introduction.html)

 <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/52e95723-f7b2-2e26-7b34-b88c7115f8e3.png" width="600px">  

 今日はこの中で
 >指定したキーワードと緯度経度の付近で最初にヒットした 5 件のデータ名（タイトル）の検索を行います。

のプログラムを見ていきたいと思います。
国交DPFのページ上でも「この範囲で検索」ができますよね。それがAPIでもできちゃうんです！

プログラムの全貌が↓です。英語が多くて難しそうですね。
一つ一つ見ていきましょう！

```javascript
import axios from 'axios';
// エンドポイントとAPIキーを定義しておく
const END_POINT = 'https://www.mlit-data.jp/api/v1/';
const API_KEY = 'please use your own key';

// 指定したキーワードと緯度経度の付近で最初にヒットした5件のデータ名（タイトル）の検索を行う。
// keyword = 検索キーワード
// lat = 十進数での緯度
// lon = 十進数での経度
// range = 度単位で検索する範囲を指定する。
async function GetData(keyword, lat, lon, range) {
  //GraphQLクエリー内容を作成
  const top = lat + range;
  const bottom = lat - range;
  const left = lon - range;
  const right = lon + range;
  const GraphQLQuery = `  
    query {
      search(
        term:"${keyword}", 
        first:0, 
        size: 5,
        locationFilter: {
          rectangle: {
            topLeft: {
              lat: ${top},
              lon: ${left}
            },
            bottomRight: {
              lat: ${bottom},
              lon: ${right}
            }
          }
        }
      ) {
        totalNumber
        searchResults {
          title
        }
      }
    }`;

  // HTTPクエリー内容を作成
  const request = {
    url: END_POINT,
    method: 'post',
    headers: {
      'Content-type': 'application/json',
      apikey: API_KEY
    },
    data: { query: GraphQLQuery }
  };

  // APIを呼び出して結果を準備する。
  const result = [];
  await axios(request)
    .then((response) => {
      response.data.data.search.searchResults.forEach((data) => {
        result.push(data);
      });
    })
    .catch((error) => {
      console.error(error.message);
      if (error.response) console.debug('Error data:', error.response.data);
    });

  return result;
}

// 検索の関数を呼び出して、結果をコンソールに出力する。
const sampleresult = await GetData(
  '公園',
  35.68087491742086,
  139.767285405523,
  0.01
);
console.log(sampleresult);
```

## ①エンドポイントとAPIキーの定義

END_POINTはデータを取得するためのAPIのエンドポイント（ざっくり言うとAPIのリクエスト先）を指定しています。<br>
API_KEYは認証のためのAPIキーです。先ほども第1部：環境構築で述べた通り、有効なAPIキーを使用する必要があります。

```javascript
const END_POINT = 'https://www.mlit-data.jp/api/v1/';
const API_KEY = 'please use your own key';
```
## ②データ取得関数'GetData'
データを取得するためには３つの手順を踏む必要があります。<br>
まずは「GraphQL」というクエリの言語を作成し、サーバーに送信するためのデータ取得を行うための下準備を行います。<br>
つぎに、この「GraphQL」クエリをＡＰＩに送信するために必要なHTTPリクエストを作成します。<br>
最後に、作成したHTTPリクエストを「axios」と呼ばれるJavaScriptでHTTPリクエストを行うためのライブラリで送信し、APIからのレスポンスを受け取っています。<br>

↓のプログラムでは「GraphQL」を作成しています。
```javascript
async function GetData(keyword, lat, lon, range) {
  //GraphQLクエリー内容を作成
  const top = lat + range;
  const bottom = lat - range;
  const left = lon - range;
  const right = lon + range;
  const GraphQLQuery = `  
    query {
      search(
        term:"${keyword}", 
        first:0, 
        size: 5,
        locationFilter: {
          rectangle: {
            topLeft: {
              lat: ${top},
              lon: ${left}
            },
            bottomRight: {
              lat: ${bottom},
              lon: ${right}
            }
          }
        }
      ) {
        totalNumber
        searchResults {
          title
        }
      }
    }`;

```
'GraphQLQuery'変数にGraphQLのクエリーが文字列として格納されています。<br>
クエリー内では、searchフィールドに対して検索条件や結果の形式を指定しています。このクエリーは、指定されたキーワードと緯度経度の範囲内で検索を行い、最大5件の結果を取得するものです。<br><br>



次に↓のプログラムで「GraphQL」クエリをＡＰＩに送信するために必要なHTTPリクエストを作成しています。
```javascript
 // HTTPクエリー内容を作成
  const request = {
    url: END_POINT,
    method: "post",
    headers: {
      "Content-type": "application/json",
      apikey: API_KEY,
    },
    data: { query: GraphQLQuery },
  };
```

'request'変数にはHTTPクエリーのパラメータがオブジェクトとして格納されています。それぞれのオブジェクトの意味はこんな感じ。<br>
>'url'：APIのエンドポイントが指定<br>
'method'：HTTPメソッドとして'POST'が指定<br>
'headers'：リクエストヘッダーが指定。'Content-type'は'application/json'、'apikey'は指定されたAPIキーを指す。<br>
'data'：GraphQLのクエリーが含まれるオブジェクトが指定<br>



最後に作成したHTTPリクエストを「axios」と呼ばれるJavaScriptでHTTPリクエストを行うためのライブラリで送信し、APIからのレスポンスを受け取っています。
```javascript

 // APIを呼び出して結果を準備する。
  const result = [];
  await axios(request)
    .then((response) => {
      response.data.data.search.searchResults.forEach((data) => {
        result.push(data);
      });
    })
    .catch((error) => {
      console.error(error.message);
      if (error.response) console.debug("Error data:", error.response.data);
    });

  return result;
}
```
'then'のブロックでは、APIからのレスポンスを処理し、検索結果から必要なデータを取得してresult配列に追加しています。<br>
'catch'ブロックでは、エラーが発生した場合にエラーメッセージをコンソールに表示しています。


何となく流れがイメージできましたでしょうか？<br>
処理としてはこれがすべてなんですが、何か忘れているような・・・？<br>



・・・あ！<br>
###  キーワードと緯度経度どこで指定するねん！！！


ご安心ください。忘れたわけではないんです。

## ③検索の関数呼び出しと結果表示
ここでは②で指定したGetData関数を実際に呼び出しています。<br>
今回はキーワードを「公園」、緯度経度を東京駅が所在する「35.68087491742086」「139.767285405523」として指定しました。<br>
そして、その緯度経度（つまり中心点）からどれくらいの範囲で検索をするか？を示す範囲を「0.01」と指定しました。（これは中心点から東西南北にそれぞれ 0.01の範囲を指定している、という意味です）


```javascript
const sampleresult = await GetData(
  '公園',
  35.68087491742086,
  139.767285405523,
  0.01
);
console.log(sampleresult);
```

## 実際に結果を表示

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/640e3fad-3d43-5e7e-b53a-c5d874561bff.png" width="1000px">  

お～！ちゃんと東京駅付近の「公園」に関連する情報が出てきた～！<br>
実際に環境構築して結果が出てくると気持ちが良いですよね！！

 # さいごに

 いかがでしたでしょうか。
 本日は国交DPFのAPIを使って環境構築＆サンプルプログラムを試してみました！<br>
 国交DPFのAPIドキュメントにはまだまだサンプルプログラムがあり、明日以降もご紹介しちゃいますのでお楽しみに～！では！