Vue.js + Laravelを使って英和辞書APIを使おう #1

#英語版wikiを気軽に読みたい！
　Vue.js＋Laravelで
・Mediawikiを用いてwikiの記事をHTMLで引っ張ってくる
・ハイライトとか単語検索機能をつける
・単語の登録機能（単語帳みたいなの）をつけて後で復習しやすいようにする
みたいなアプリが出来たらなーと思って現在実装しています。
　今回は単語検索機能について必死にググりながら実装していったものを記事にまとめます。

実際に作ったもの（開発中）
http://wiki-learns.herokuapp.com
GitHub
https://github.com/customaddone/wikiLearns

#開発環境
|使用ツール名   |バージョン              |
|----------|--------------------------|
|Laravel| 6.1.0   |
|Vue|6.4.1|
Laravelのバージョンごとにresources/jsのディレクトリの構造が異なったりするようです。
#実装するもの
###Vue（単一コンポーネント）
- template
    - 検索結果を表示するカード（ボタンで表示/非表示の切り替え可）
    - カードの表示/非表示を切り替えるボタン
- script
    - デ辞蔵（辞書API）で単語の検索、内容取得する機能

###Laravel
- Controller
    - デ辞蔵（辞書API）で単語の検索、内容取得する機能(Guzzleを用いる）

#同一オリジンポリシー
　ブラウザには、同一オリジンポリシーというものが適用されていて、異なるドメイン（例localhost -> en.wikipedia...(wikiAPIのドメイン)）にアクセスしようとすると、「access-control-allow-origin ヘッダーに見つかりません。」とのエラーが出て弾かれます。

　外部APIを使うということは、異なるドメイン(localhost -> 外部APIのドメイン）にアクセスしようとすることなので、何かしら対策をしないとアクセスを弾かれてAPIで外部APIからレスポンスを受け取れません。

　対策としては
１　Chromeの拡張機能を使う
２　サーバーサイド(Laravel側)でページを取得
３　Jsonpを利用する

などの方法があるらしく、今回は「２　サーバーサイド(Laravel側)でページを取得」で対応しようと思います。

#Guzzle
PHPにはGuzzleというライブラリがあり、これを用いるとPHPでHTTPリクエストを行うことができます。これでクロスドメイン通信が可能になります。

###インストール
Composerでインストールしましょう。
$ composer require guzzlehttp/guzzle

###Vue側
単一コンポーネントのscriptの部分に書いていきましょう

```resources/js/components/WikiShow.Vue
    /* デ辞蔵を使って単語検索->ヒットすればIDを取得して単語のページを検索
       Guzzleを使ってクロスオリジン通信を行う */
    researchAxios: function (word) {
      return new Promise((resolve, reject) => {
        axios.get("/api/data/" + word)
             .then((response) => {

               /* 戻ってきたデータからIDを取得 */
               var searchId = response.data.match(/(\d{6})/);
               this.searchWordId = searchId[0]

               /* IDを用いて単語のページを検索 */
               axios.get("/api/datashow/" + this.searchWordId)
                    .then((response) => {

                      var means = response.data.match(/<div>(.*?)<\/div>/);
                      this.translated = means[1];
                      resolve();
                    })
                    .catch(response => console.log(response));
              })
              .catch((response) => {

                console.log(response);
                reject();

              });
          });
    },
```
（Vueファイルはシンタックスハイライト効かなくて寂しい..）

この部分に注目してください。

```
axios.get("/api/data/" + word)
             .then((response) => {
```
axisのgetメソッドで(localhost~)/api/data/(word(検索したい語))のurlでLaravelにリクエストをしています。routes/api.phpにAPIのルーティングを設定しましょう。

```routes/api.php
Route::get("/data/{pass}", "ArticlesController@dict"
);
```
先ほどのリクエストでArticlesControllerのdictメソッドを呼べるようにルーティングしました。dictメソッドを実装していきましょう。

###Laravel側
ここでGuzzleを使います。

```app/Http/Controllers/ArticlesController.php
<?php

namespace App\Http\Controllers;

use App\Article;
use Illuminate\Http\Request;
use GuzzleHttp\Client;

class ArticlesController extends Controller
{

    public function dict($pass)
    {
        $client = new \GuzzleHttp\Client();

        $response = $client->request(
            'GET',
            // レスポンスを返すurl(デ辞蔵のurl)
            $url = "http://public.dejizo.jp/NetDicV09.asmx/SearchDicItemLite",
            [ 'query' => [
                'Dic' => 'EJdict',
                'Word' => $pass,
                'Scope' => 'HEADWORD',
                'Match' => 'STARTWITH',
                'Merge' => 'AND',
                'Prof' => 'JSON',
                'PageSize' => 1,
                'PageIndex' => 0
            ]],
            // パラメーターがあれば設定
        );
        // レスポンスボディを取得
        $responseBody = $response->getBody()->getContents();
        return $responseBody;
    }
}
```
```
use GuzzleHttp\Client;
```
Clientインスタンスを使用できるようにして

```
$client = new \GuzzleHttp\Client();
```
インスタンスを生成

```
$response = $client->request(
    'GET',
    $url = "http://public.dejizo.jp/NetDicV09.asmx/SearchDicItemLite",
    [ 'query' => [
      'Dic' => 'EJdict',
      'Word' => $pass,
      'Scope' => 'HEADWORD',
      'Match' => 'STARTWITH',
      'Merge' => 'AND',
      'Prof' => 'JSON',
      'PageSize' => 1,
      'PageIndex' => 0
    ]],
// パラメーターがあれば設定
);
```
Vue側からパスの形で投げられたword + 各種検索条件をつけて$client->requestで指定のurlにリクエスト

```
// レスポンスボディを取得
$responseBody = $response->getBody()->getContents();
return $responseBody;
```
返ってきたレスポンスの内容を$responseBodyに収納してVue側にreturnする。

これでVue + Laravelで辞書APIを用いて入力した単語を検索する機能を
一通り実装できました。

次回はビューと検索機能をより使いやすくするための細かい実装について書いて行こうと思います。