「Laravel + Vue.jsではじめる 実践 GraphQL入門」の全貌を大公開します!〜GraphQL + VueでSPAフロントエンドを開発!(ログインページ/機能の実装〜残りのAPI機能/実装について)編〜
こんにちは。kzkohashi です。
FISM という会社でCTOをやっております。
今年4月に「Laravel + Vue.jsではじめる 実践 GraphQL入門」という技術書籍を出版しました。
本記事では、GraphQL + Vue でのSPAフロントエンド開発について、書籍の内容をそのまま公開しております。
▼マガジンで更新中!
▼ Wantedlyでダイジェストまとめています!
今回、なんと最終章!
「GraphQL + VueでSPAフロントエンドを開発!(ログインページ/機能の実装〜残りのAPI機能/実装について)編」です!
どうぞご覧ください!
✂︎ ---------------------
ログインページ/機能の実装
続いてログインページを作成します
ここまで結構ボリュームがあったかと思いますが、フォーム入力・mutationが終わったので後は、
- query通信
- 通信後のviewアップデート
この2点ができればほぼできる事のすべてとなります。
それでは、ログインページを作成していきます。サインアップページ同様
- views フォルダに新しくページ用のvueファイルを作成
- routerにurlとページ用のvueの紐付けを記述
- ページ用vueファイルにDOMを記載
- GraphQLを記述
- ページ用vueファイルにロジックを記載
となります。
viewsフォルダにLogin.vueを作成
signup同様にフォームを記述していきます。
• twitter-like-client/src/views/Login.vue
<template>
<v-form @submit="login" onSubmit="return false;">
<v-container>
<v-layout>
<v-flex xs12 md4>
<v-text-field
v-model="email"
label="E-mail"
required
></v-text-field>
<v-text-field
v-model="pass"
label="password"
required
></v-text-field>
<v-btn color="primary" type="submit">login</v-btn>
<router-link to="/signup"><v-btn flat>signup</v-btn></router-link>
</v-flex>
</v-layout>
</v-container>
</v-form>
</template>
router.jsに追記
ログインページを追加しました
• twitter-like-client/src/router.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import Signup from './views/Signup.vue'
import Login from "./views/Login.vue";
Vue.use(Router)
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
component: Home
},
{
path: "/signup",
name: "signup",
component: Signup
},
{
path: " /login",
name: "login",
component: Login
}
]
});
ログインページにアクセス
http://localhost:8080/login このような表示がされていれば成功です
ログインのGraphQLを記述
先ほど同様にmutation.jsに追記します
• twitter-like-client/src/graphql/mutation.js
// ログイン
export const LOGIN = gql`
mutation($email: String! $password: String!) {
Login(
email: $email
password: $password
){
access_token
expires_in
}
}
`;
ログインの通信ロジックを記述
ここもSignupと同様、フォームの入力値をvariablesにいれてmutateメソッドを叩きます。通信後の処理も同じです。
• twitter-like-client/src/views/Login.vue
<script>
import { LOGIN } from "../graphql/mutation.js";
import store from "../store.js";
export default {
data: () => ({
email: "",
pass: ""
}),
methods: {
login(e){
// ミューテーション
this.$apollo.mutate({
// Query mutation: LOGIN,
// Parameters
variables: {
email: this.email,
password: this.pass
},
}).then((data) => {
const token = localStorage.setItem('vue_token', data.data.Login.access_token);
store.commit("logined");
this.$router.push("/");
});
}
}
}
</script>
ログインして見る
ログイン後TOPページにいくように設定していますので、Vuetifyのtopページが出れば成功です。
これでLogin.vueの記述は終わりです。すべてのスクリプトはこちらです
• twitter-like-client/src/views/Login.vue
<template>
<v-form @submit="login" onSubmit="return false;">
<v-container>
<v-layout>
<v-flex xs12 md4>
<v-text-field
v-model="email"
label="E-mail"
required
></v-text-field>
<v-text-field
v-model="pass"
label="password"
required
></v-text-field>
<v-btn color="primary" type="submit">login</v-btn>
<router-link to="/signup"><v-btn flat>signup</v-btn></router-link>
</v-flex>
</v-layout>
</v-container>
</v-form>
</template>
<script>
import { LOGIN } from "../graphql/mutation.js";
import store from "../store.js";
export default {
data: () => ({
email: "",
pass: ""
}),
methods: {
login(e){
// ミューテーション
this.$apollo.mutate({
// Query
mutation: LOGIN,
// Parameters
variables: {
email: this.email,
password: this.pass
},
}).then((data) => {
const token = localStorage.setItem('vue_token', data.data.Login.access_token);
store.commit("logined");
this.$router.push("/");
});
}
}
}
</script>
ツイート/タイムラインページ/機能の実装
続いて、いよいよツイート/タイムライン表示の画面を作ります
ツイート、タイムライン表示はトップページがいいので、すでにrouterで定義されているHome.vueを修正していきたいと思います。
まずはツイート送信をする
慣れてきていると思いますので、 先にmutationを書き、DOMとロジック両方を同時に記述します。 mutation.jsに以下を追記
• twitter-like-client/src/graphql/mutation.js
export const CREATE_TWEET = gql`
mutation($tweet: String!) {
CreateTweet(content: $tweet) {
id
content
tweeted_at
}
}
`;
Home.vue
すでにHome.vueで定義されているコードはすべて消して下記を記述します。
• twitter-like-client/src/views/Home.vue
<template>
<v-container>
<v-layout row wrap>
<v-flex xs12>
<v-subheader>
Tweet
</v-subheader>
</v-flex>
<v-flex mb-2>
<v-sheet class="pa-4" elevation=6>
<v-form @submit="postTweet" onSubmit="return false;">
<v-text-field
v-model="tweet"
label="tweet"
required
></v-text-field>
<v-btn type="submit" color="primary">ツイート</v-btn>
</v-form>
</v-sheet>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
import { CREATE_TWEET } from "../graphql/mutation.js";
export default {
data: () => ({
tweet: ""
}),
methods: {
postTweet(e){
this.$apollo.mutate({
mutation: CREATE_TWEET,
variables: {
tweet: this.tweet,
}
});
}
}
}
</script>
通信を確認
表示上特に代わりが無いのですが、devツール上でツイートが送信されているのが確認できると思います
タイムラインを作成する
今までmutationでの通信をしてきたのですが、queryでの通信が始まります。 Vue-apolloでの記述方法も変わるので注意してみていただければと思います。
まずはquery通信のみ確認する
いきなり、query通信とDOM描画を同時に説明するとわかりづらいかと思いますので、先に通信から始めます。
query.jsにGraphQLを記載
• twitter-like-client/src/graphql/query.js
import gql from 'graphql-tag';
export const TIMELINE = gql`
query($id: Int!) {
Timeline(id: $id) {
id
tweet {
id
content
account {
twitter_id
avatar
}
}
originalFavorite {
account {
twitter_id
name
}
}
favorite {
favorite_at
}
}
}
`;
Home.vueにquery通信を書きます
Home.vueのscriptを下記に書き換えます。
mutateとの違いは、export defaultのオブジェクトにapolloというプロパティを作ります。
• twitter-like-client/src/views/Home.vue
<script>
import { CREATE_TWEET } from "../graphql/mutation.js";
import { TIMELINE } from "../graphql/query.js";
export default {
data: () => ({
tweet: "",
timelines: [],
}),
methods: {
postTweet(e){
this.$apollo.mutate({
mutation: CREATE_TWEET,
variables: {
tweet: this.tweet,
}
});
}
},
apollo: {
timelines: {
query: TIMELINE,
loadingKey: 'loading',
// Parameters
variables () {
return {
id: 0
}
},
update (data) {
return data.Timeline;
},
}
}
}
</script>
ポイント1:dataとのリンク
export defaultオブジェクトに、queryの内容を書いていくのですが、ポイントとして、上で定義してる timelines:[] という変数とapolloオブジェクト内に記載した、 timelines:{ というプロパティはリンク しています。
※ここが違うとエラーが出てしまうので、気をつけてください。
ポイント2:updateメソッドでdataに代入
updateメソッドは無くても、dataのtimelinesに代入されますが、 配列のみ取得したい時などはupdateメソッドからデータをreturnする事で、 必要なデータのみ返却できます。
update (data) {
return data.Timeline;
},
通信の確認
上記の記述でqueryは通信されます。 devtool上で通信がされているか確認してみましょう。
ツイートの表示
今回、ツイートを表示するに伴い、Vueの子コンポーネントに表示しようと思います。 まずは、componentsデ ィレクトリにTimeline.vueを作成しましょう。
Timeline.vueにコードを記載
ここは基本的なvueのコンポーネント作成となります。
• twitter-like-client/src/components/Timeline.vue
<template>
<v-list two-line>
<template v-for="(timeline, index) in timelines">
<v-list-tile
:key="index"
avatar
>
<v-list-tile-avatar>
<img :src="'http://localhost:8000/storage/images/' + timeline.tweet.account.
avatar" v-if="timeline.tweet.account.avatar"/>
<v-icon v-else>account_circle</v-icon>
</v-list-tile-avatar>
<v-list-tile-content>
<div v-text="timeline.originalFavorite ? timeline.originalFavorite.account.n
ame + 'さんがいいねしました' : ''"></div>
<v-list-tile-sub-title v-html="timeline.tweet.account.twitter_id"></v-list-tile-sub-title>
<v-list-tile-title v-html="timeline.tweet.content"></v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-divider
:key="index+'_divider'"
></v-divider>
</template>
</v-list>
</template>
<script>
export default {
props: {
timelines: Array
}
}
</script>
Home.vueにTimelineコンポーネントを入れ込む
Home.vueを以下のコードに書き換え 変更点は、Timelineをインポートして、export default内のコンポーネン トプロパティに登録 TimelineタグをDOMに配置して、Timelineデータを:v-bindディレクティブで紐付けしてい ます。
• twitter-like-client/src/views/Home.vue
<template>
<v-container>
<v-layout row wrap>
<v-flex xs12>
<v-subheader>
Tweet
</v-subheader>
</v-flex>
<v-flex mb-2>
<v-sheet class="pa-4" elevation=6>
<v-form @submit="postTweet" onSubmit="return false;">
<v-text-field
v-model="tweet"
label="tweet"
required
></v-text-field>
<v-btn type="submit" color="primary">ツイート</v-btn>
</v-form>
</v-sheet>
</v-flex>
<!-- タイムラインコンポーネント -->
<v-flex xs12>
<v-sheet class="pa-4" elevation=6>
<Timeline v-bind:timelines="timelines" />
</v-sheet>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
import { CREATE_TWEET } from "../graphql/mutation.js";
import { TIMELINE } from "../graphql/query.js";
import Timeline from "../components/Timeline.vue";
export defcalut {
components: {Timeline},
data: () => ({
tweet: "",
timelines: [],
}),
methods: {
postTweet(e){
this.$apollo.mutate({
mutation: CREATE_TWEET,
variables: {
tweet: this.tweet,
}
});
}
},
apollo: {
timelines: {
query: TIMELINE,
loadingKey: 'loading',
// Parameters
variables () {
return {
id: 0
}
},
update (data) {
return data.Timeline;
},
}
}
}
</script>
表示の確認
以下のような表示になっていれば成功です。
ツイートをしたらタイムラインを更新する
大分ツイッターらしくなってきたかと思います。 ただ、ここまでだとツイートをしてもタイムラインは更新さ れないので、 ツイート送信が完了したらタイムラインを再度更新するようコードを書き換えます。
Home.vueのpostTweetメソッドにthenをつけて、再度GraphQLを叩くようにします。
this.$apollo はmutateメソッドだけでなくqueryも叩けるようメソッドが用意されています。 今回はrefetchメソッドをタイムラインを最新にします。
• twitter-like-client/src/views/Home.vue
postTweet(e){
this.$apollo.mutate({
mutation: CREATE_TWEET,
variables: {
tweet: this.tweet,
}
}).then((data) => { // thenを追加
this.$apollo.queries.timelines.refetch({
id: 0
});
});
リストが更新されるようになっていれば成功です。
残りのAPI機能/実装について
残りのAPI機能/実装に関しては、ここまでご説明した以下の作成手順で問題なく実装が可能です。
- views フォルダに新しくページ用のvueファイルを作成
- routerにurlとページ用のvueの紐付けを記述
- ページ用vueファイルにDOMを記載
- GraphQLを記述
- ページ用vueファイルにロジックを記載
- 実行!
他のAPIに関しても実装を見たい方へ
残りのAPI実装に関しても、私の方で実装したサンプルがございますので、 githubのURLをご確認いただければと思います。
✂︎ ---------------------
いかがでしたでしょうか?
最後までお読みいただき、ありがとうございます!
本連載はこれにて一旦おしまいになりますが、直近だと 1/23 にGraphQLのイベントも開催予定となっております。
今後とも大橋とFISMをよろしくお願い致します!
Fin.
▼ Twitterもやってます。よければフォローもお願いします🙇🏿♂️
▼ FISM社についてはこちら💁🏿♂️
▼ 現在Wantedlyにて開発メンバー募集中です!GraphQL + Laravel + Vue.js + Swift で開発しております👨🏿💻まずはお気軽にお話ししましょう🙋🏿♂️
この記事が気に入ったらサポートをしてみませんか?