npm
laravel
docker
vue.js
RestAPI

限りなく簡単に解説!LaravelでRestAPIとVueを連携させる!~アジャイルでDevOpsなシステム構築実践~

目的

LaravelPHPにおいてRestAPIとVueの連携をします。
※サンプルでRestAPI公開できたら…もっとよいのに…ごめんなさい

前提・環境

  • Windows10
  • Laradock(Docker)で開発環境を構築
  • RestAPIは作成済み
  • welcome.blade.phpを利用
  • /{プロジェクト}/src/ をルートとする
  • vue-router, asiosを使う

準備

vue-routerをインストール

下記のpackage.json状態で、npm installを実行します。

/package.json
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.17",
        "bootstrap-sass": "^3.3.7",
        "cross-env": "^5.1",
        "jquery": "^3.2",
        "laravel-mix": "^1.0",
        "lodash": "^4.17.4",
        "vue": "^2.5.7",
        "vue-router": "^2.3.0"
    }
}

devDependencies の詳細

こちらに詳しく説明があります。

asios

Laravel5.5でプロジェクトを作成時にインストールされます。

表示される画面

想定画面

下記のような画面を表示します。
コンポーネントはナビゲーションと本体(試験区分)です。

1 画面.PNG

APIが取得するJSON

想定されるJSON
[{"id":1,"name":"IT\u30d1\u30b9\u30dd\u30fc\u30c8\u8a66\u9a13","created_at":"2017-12-12 00:00:00","updated_at":"2017-12-12 00:00:00"},{"id":2,"name":"\u57fa\u672c\u60c5\u5831\u6280\u8853\u8005\u8a66\u9a13","created_at":"2017-12-12 00:00:00","updated_at":"2017-12-12 00:00:00"},{"id":3,"name":"\u5fdc\u7528\u60c5\u5831\u6280\u8853\u8005\u8a66\u9a13","created_at":"2017-12-12 00:00:00","updated_at":"2017-12-12 00:00:00"},{"id":4,"name":"\u60c5\u5831\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30de\u30cd\u30b8\u30e1\u30f3\u30c8\u8a66\u9a13","created_at":"2017-12-12 00:00:00","updated_at":"2017-12-12 00:00:00"}]

構成図

ファイル間は次の図のような連携をしています。

各ファイル間連携

2 構成図.png

フォルダ構成

フォルダ構成は下記のようになっています。

3 フォルダ構成.PNG

ファイル

今回使うファイルは次の5つです。

  • welcome.blade.php
  • app.js
  • bootstrap.js
  • Navigation.vue
  • Examination.vue

この5つを作成し、"npm run dev"を実行し、
http://192.168.99.100/
にアクセスすると、想定のような画面が表示されます。
※RestAPIがある前提

welcome.blade.php / ビュー

http://192.168.99.100
にアクセスしたときに表示されるビューです。
このビューが表示されるときに、app.jsが呼ばれます。

/resources/view/welcome.blade.php
<!DOCTYPE html>
<html lang="jp">
    <head>
        <meta charset="UTF-8">
        <title>Hello Vue</title>
        <link rel="stylesheet" href="css/app.css"/>
        <meta name="csrf-token" content="{{ csrf_token() }}">
    </head>
    <body>
        <div id="app">
            <!-- /resources/assets/js/components/Layouts/Navigation.vueを呼ぶ -->
            <navigation></navigation>
            <div class="container">
                <!-- vue-routerによって動的に変わる -->
                <router-view></router-view>
            </div>
        </div>
    </body>
    <script src="{{ mix('js/app.js') }}"></script>
</html>

app.js

本体となるjsファイル(という認識)です。
正直、bootstrap.jsとの役割分担がわからない…

/resources/js/app.js
/**
 * vue本体などをインポート
 */
import Vue from 'vue'
import VueRouter from 'vue-router'



/**
 * First we will load all of this project's JavaScript dependencies which
 * includes Vue and other libraries. It is a great starting point when
 * building robust, powerful web applications using Vue and Laravel.
 */
require('./bootstrap')


/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

/*
 * vue-routerを利用して、vueファイルと関連付け
 */
Vue.use(VueRouter)

/*
 * ナビゲーションコンポーネント
 * サンプルではwelcome.blade.phpの<navigation></navigation>と関連付け
 */
Vue.component('navigation', require('./components/Layouts/Navigation.vue'))

/*
 * 試験区分一覧コンポーネント
 * サンプルではwelcome.blade.phpの<router-view></router-view>と関連付け
 * ※vue-routerによって動的に変わる
 */
const router = new VueRouter({
    mode: 'history',
    routes: [
        { path: '/',
          component: require('./components/Articles/Examination.vue')
        }
    ]
})

/*
 * welcome.blade.phpの<div id="app"></div>にマウント
 */
const app = new Vue({ router }).$mount('#app')

bootstrap.js

app.jsがrequireします。

/resources/js/bootstrap.js
/**
 * 下記をここに書かないと
 * window.axios = require('axios');
 * でエラーが起こる
 * 正直、bootstrap.jsとapp.jsの役割を理解していない
 *
 */
window.Vue = require('vue')


window._ = require('lodash');

/**
 * We'll load jQuery and the Bootstrap jQuery plugin which provides support
 * for JavaScript based Bootstrap features such as modals and tabs. This
 * code may be modified to fit the specific needs of your application.
 */

/**
 * We'll load jQuery and the Bootstrap jQuery plugin which provides support
 * for JavaScript based Bootstrap features such as modals and tabs. This
 * code may be modified to fit the specific needs of your application.
 */

try {
    window.$ = window.jQuery = require('jquery');

    require('bootstrap-sass');
} catch (e) {}

/**
 * We'll load the axios HTTP library which allows us to easily issue requests
 * to our Laravel back-end. This library automatically handles sending the
 * CSRF token as a header based on the value of the "XSRF" token cookie.
 */

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

/**
 * Next we will register the CSRF Token as a common header with Axios so that
 * all outgoing HTTP requests automatically have it attached. This is just
 * a simple convenience so we don't have to attach every token manually.
 */

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

/*
 * axiosを使う際に追記
 */
Vue.prototype.$http = axios

/**
 * Echo exposes an expressive API for subscribing to channels and listening
 * for events that are broadcast by Laravel. Echo and event broadcasting
 * allows your team to easily build robust real-time web applications.
 */

// import Echo from 'laravel-echo'

// window.Pusher = require('pusher-js');

// window.Echo = new Echo({
//     broadcaster: 'pusher',
//     key: 'your-pusher-key'
// });

Navigation.vue

ナビゲーションのコンポーネントです。
テンプレート(HTML)とスタイル(css)とスクリプト(JavaScript)で構成されます。
ここでは、テンプレートだけ記述しています。

/resources/js/components/Layouts/Navigation.vue
<template>
    <nav class="navbar navbar-default">
        ナビゲーション
    </nav>
</template>

Examination.vue

本体部分のコンポーネントです。
テンプレート(HTML)とスタイル(css)とスクリプト(JavaScript)で構成されます。
テンプレートとスクリプトを記述しています。スタイルは省略しています。
コメントはそれぞれの文法通りです。

API連携部分
fetchArticles() {
    this.$http({
        url: '/api/getAllExamination',
            method: 'GET'
    }).then(res =>  {
        this.articles =  res.data
    })
}

上記がAPI連携です。
本当はエラーの場合の処理など書いたほうが良いのですが、この記載だけでAPIから値を取得します。
"articles"という変数に取得したJSONを詰め込みます。

想定されるJSON
[{"id":1,"name":"IT\u30d1\u30b9\u30dd\u30fc\u30c8\u8a66\u9a13","created_at":"2017-12-12 00:00:00","updated_at":"2017-12-12 00:00:00"},{"id":2,"name":"\u57fa\u672c\u60c5\u5831\u6280\u8853\u8005\u8a66\u9a13","created_at":"2017-12-12 00:00:00","updated_at":"2017-12-12 00:00:00"},{"id":3,"name":"\u5fdc\u7528\u60c5\u5831\u6280\u8853\u8005\u8a66\u9a13","created_at":"2017-12-12 00:00:00","updated_at":"2017-12-12 00:00:00"},{"id":4,"name":"\u60c5\u5831\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30de\u30cd\u30b8\u30e1\u30f3\u30c8\u8a66\u9a13","created_at":"2017-12-12 00:00:00","updated_at":"2017-12-12 00:00:00"}]

変数"articles"に格納された値はテンプレートで表示処理を書きます。
v-for="article in articles"
でループ処理をしています。
router-link :toでaタグを生成しています。
v-forなどの詳しい説明は公式サイトをみてください!

テンプレート
<template>
    <!-- コメントはHTMLの方式に従う -->
    <!-- templateタグ直下にv-forがあるとエラーとなるので注意 -->
    <div>
        <div v-for="article in articles">
            <p>
                <router-link :to="'/round/' + article.id">{{ article.name }}</router-link>
            </p>
        </div>
    </div>
</template>

templateタグ直下に、v-forを書くと、"Cannot use v-for on stateful component root element because it renders multiple elements."というエラーとなります。
雑訳すると「v-forはルートのコンポーネントじゃ使えねーよ。だって、複数ある前提だもの」ってニュアンスです。英語力0なので間違えていたらご指摘を

Examination.vueの全ソースです。

/resources/js/components/Articles/Examination.vue
<template>
    <!-- コメントはHTMLの方式に従う -->
    <!-- templateタグ直下にv-forがあるとエラーとなるので注意 -->
    <div>
        <div v-for="article in articles">
            <p>
                <router-link :to="'/round/' + article.id">{{ article.name }}</router-link>
            </p>
        </div>
    </div>
</template>

<style>
/*
 * コメントはCSSの方式に従う
 * このサンプルでは使わない
 */
</style>

<script>
    /*
     * コメントはJavaScriptの方式に従う
     */
    export default {
        created() {
            this.fetchArticles()
        },
        data() {
            return {
                articles: []
            }
        },
        methods: {
            fetchArticles() {
                this.$http({
                    url: '/api/getAllExamination',
                    method: 'GET'
                }).then(res =>  {
                    this.articles =  res.data
                })
            }
        }
    }
</script>

補足

web.php

"welcome.blade.php"を呼ぶためのルーティングはweb.phpに記載しています。
"/"ルートにアクセスすると、コントローラも呼ばずにwelcome.blade.phpを呼びます。

/routes/web.php
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Eclipseで.vueファイルを見やすくする

【自前のページ】

参考

Vue.js本家チュートリアル
かなり充実しています!ただ、どうしても説明が多くなるのでとりあえず動かしたいときには悩むかも
[Laravel 5.4 + Vue 2.1 でSPAアプリケーション作成チュートリアル](https://qiita.com/acro5piano/items/f33381fc60408abe9865
LaravelからVueを使ってSPAっぽくする
参考にさせていただきました!!!