序章

この記事では、GraphQLサーバーを利用するブログを作成します。 ApolloクライアントとVueを使用してブログアプリを構築します。

前提条件

このチュートリアルを完了するには、次のものが必要です。

このチュートリアルは、JavaScriptの知識と、VueおよびGraphQLにある程度精通していることを前提としています。

このチュートリアルは、Nodev14.4.0で検証されました。 npm v6.14.5、MySQL v14.14、 @adonisjs/cli v4.0.12、 @vue/cli v4.4.6、 vue v2.5.2、 graphql v15.1.0、および apollo-client v2.6.10。

GraphQLサーバーの作成

GraphQLサーバーを入手して、チュートリアルを進めることができます。

リポジトリのクローンを作成したら、GraphQLサーバーのプロジェクトディレクトリに移動します。

  1. cd adonis-graphql-server

必要なパッケージをインストールします。

  1. npm install

コピー .env.example.env:

  1. cp .env.example .env

編集します .env 必要に応じてファイルを作成し、データベース情報が実行中のMySQLデータベースの適切な資格情報を提供するようにします。 DB_USERDB_PASSWORD 変更が必要な場合があります。

アドニスのキーを生成します。

  1. npx @adonisjs/cli key:generate

データベース構成を移行します。

  1. npx @adonisjs/cli migration:run

CORSの有効化

GraphQLサーバーはAdonisJSで構築されました。 AdonisJSは、APIでクロスオリジンリソースシェアリング(CORS)を処理するために使用できるパッケージを提供します。 AdonisJSではデフォルトでCORSがオフになっているため、有効にする必要があります。

AdonisJSアプリでCORSを有効にするために、 origintrueconfig/cors.js 以下のように:

config / cors.js
origin: true

クローン化されたGraphQLサーバーではCORSがすでに有効になっていますが、言及する価値があります。

GraphQLサーバーの起動

ブログアプリはGraphQLサーバーを利用するため、サーバーを起動して、チュートリアルの残りの部分でサーバーを実行し続ける必要があります。

開始するには、GraphQLサーバーのプロジェクトディレクトリにいることを確認し、以下のコマンドを実行します。

  1. npx @adonisjs/cli serve --dev

これにより、GraphQLサーバーが起動し、実行を継続します。

チュートリアルの残りの部分では、GraphQLサーバーが既に起動されており、実行されていることを前提としています。

それが済んだら、ブログアプリの作成を始めましょう。

ステップ1—Vueアプリを作成する

まず、VueCLIを使用して新しいVueアプリを作成します。

  1. npx -p @vue/cli -p @vue/cli-init vue init webpack graphql-blog-app

注:最新のVueプロジェクトは以下を利用できます:

  1. npx @vue/cli create graphql-blog-app

プロジェクトに関する質問が表示されます。 行われた選択のいくつかを次に示します。 このチュートリアルでは、インストールすることが重要になります vue-router:

? Project name graphql-blog-app
? Project description A Vue.js project
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) npm

これにより、名前が付いた新しいVueアプリが作成されます graphql-blog-app 依存関係をインストールします。

新しく作成されたディレクトリに移動します。

  1. cd graphql-blog-app

アプリケーションは、端末で次のコマンドを実行することにより、いつでもブラウザで実行および表示できます。

  1. npm start

ステップ2—パッケージのインストール

アプリを作成したら、GraphQLブログアプリの構築に必要なパッケージのインストールに進むことができます。

  1. npm install --save vue-apollo graphql apollo-client apollo-link apollo-link-context apollo-link-http apollo-cache-inmemory graphql-tag

各パッケージを簡単に見ていきましょう。

  • vue-apollo:VueJS用のApollo/GraphQL統合。 プラグインの最新バージョンをインストールして、Apolloクライアント2.0に付属するすべての優れた機能を使用できるようにします。
  • graphql:JavaScript用のGraphQLのリファレンス実装。
  • apollo-client:すべてのサーバーまたはUIフレームワーク用のフル機能の本番環境対応のキャッシングGraphQLクライアント。
  • apollo-link:GraphQLリクエストの制御フローを変更し、GraphQL結果をフェッチするための標準インターフェース。
  • apollo-link-context:操作のコンテキストを設定するために使用されます。これは、チェーンのさらに下流にある他のリンクによって使用されます。
  • apollo-link-http:HTTPフェッチを使用してネットワーク経由でGraphQLの結果を取得するために使用されます。
  • apollo-cache-inmemory:ApolloClient2.0のキャッシュ実装。
  • graphql-tag:GraphQLクエリを解析するJavaScriptテンプレートリテラルタグ。

ステップ3—VueApolloを設定する

次に、使用するパッケージを配置しましょう。 まず、 ApolloClient インスタンスをインストールし、 VueApollo プラグイン。 開ける src/main.js 以下のコードを追加します。

src / main.js
// ...

import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'

const httpLink = new HttpLink({
    // URL to graphql server, you should use an absolute URL here
    uri: 'http://localhost:3333/graphql'
})

// create the apollo client
const apolloClient = new ApolloClient({
    link: httpLink,
    cache: new InMemoryCache()
})

// install the vue plugin
Vue.use(VueApollo)

の新しいインスタンスを作成します httpLink URL(http://localhost:3333/graphql)私たちのGraphQLサーバーの。 次に、を使用してApolloクライアントを作成します httpLink 上で作成し、メモリ内キャッシュが必要であることを指定します。 最後に、VueApolloプラグインをインストールします。

次に、を作成しましょう apolloProvider ルートコンポーネントで指定するオブジェクト:

src / main.js
// ...

const apolloProvider = new VueApollo({
    defaultClient: apolloClient
})

// update Vue instance by adding `apolloProvider`
/* eslint-disable no-new */
new Vue({
    el: '#app',
    router,
    apolloProvider,
    template: '<App/>',
    components: { App }
})

を使用してVueApolloプラグインの新しいインスタンスを作成します apolloClient デフォルトのクライアントとして作成されました。 最後に、 apolloProvider Vueルーターを使用するのと同じ方法で、Vueインスタンスにオブジェクトを追加します。

ステップ4—ブルマを追加する

このチュートリアルでは、 BullmaCSSを使用します。 それでは、に追加しましょう。 開ける index.html 以下のように更新します。

index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>GraphQL Blog App</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css">
</head>
<body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
</body>
</html>

このコンテンツ配信ネットワーク(CDN)でBulmaを参照します。

ステップ5—未使用のコードを削除する

このチュートリアルでは使用しないVueアプリを作成したときに、いくつかのファイルとコードが付属していました。 それらがアプリに干渉しないように、それらを削除しましょう。

を削除します HelloWorld コンポーネントとそのすべての参照をから削除します src/router/index.js.

ステップ6—プライマリレイアウトを作成する

ブログは、ページ全体で一般的なレイアウトを使用します。 その場合、すべてのページが使用するレイアウトを定義しましょう。 これを行うには、 src/App.vue 以下のように更新します。

src / App.vue
<template>
    <div id="app">
        <nav class="navbar is-primary" role="navigation" aria-label="main navigation">
            <div class="container">
                <div class="navbar-brand">
                    <router-link class="navbar-item" to="/">Blog App</router-link>

                    <button class="button navbar-burger">
                        <span></span>
                        <span></span>
                        <span></span>
                    </button>
                </div>
            </div>
        </nav>
        <router-view/>
    </div>
</template>

<script>
export default {
  name: 'app'
}
</script>

すべてのページが使用するヘッダーを追加します。

ステップ7—ユーザーサインアップページの作成

ユーザーはブログアプリにサインアップできるはずです。 作成します SignUp それを処理するコンポーネント。 だから、内 src/components 新しいを作成します Admin フォルダ。 管理者関連のすべてのコンポーネントは、このフォルダー内に作成されます。

作成する前に SignUp コンポーネントでは、すべてのGraphQLクエリとミューテーションを保持する専用ファイルを作成しましょう。 このファイルを直接内部に作成します src. 作成する graphql.js 内部のファイル src 以下のコードを貼り付けます。

src /graphql.js
import gql from 'graphql-tag'

export const SIGNUP_MUTATION = gql`
  mutation SignupMutation($username: String!, $email: String!, $password: String!) {
    createUser(
      username: $username,
      email: $email,
      password: $password
    ) {
      id
      username
      email
    }
  }
`

これは、GraphQLサーバーでの新しいユーザーの作成を処理するGraphQLミューテーションです。 ユーザーのユーザー名、電子メール、およびパスワードを受け取ります。 これらの変数はから渡されます SignUp 成分。

次に、を作成しましょう SignUp 成分。 以内 Admin フォルダ、作成 SignUp.vue 以下のコードをファイルして貼り付けます。

src / components / Admin / SignUp.vue
<template>
   <section class="section">
    <div class="columns">
      <div class="column is-4 is-offset-4">

        <h2 class="title has-text-centered">Signup</h2>

        <form method="POST" @submit.prevent="signup">
          <div class="field">
            <label class="label">Username</label>
            <p class="control">
              <input
                type="text"
                class="input"
                v-model="username"
              />
            </p>
          </div>

          <div class="field">
            <label class="label">E-Mail Address</label>
            <p class="control">
              <input
                type="email"
                class="input"
                v-model="email"
              />
            </p>
          </div>

          <div class="field">
            <label class="label">Password</label>
            <p class="control">
              <input
                type="password"
                class="input"
                v-model="password"
              />
            </p>
          </div>

          <p class="control">
            <button class="button is-primary is-fullwidth is-uppercase">SignUp</button>
          </p>
        </form>
      </div>
    </div>
   </section>
</template>

<script>
import { SIGNUP_MUTATION } from '@/graphql'

export default {
  name: 'SignUp',
  data () {
    return {
      username: '',
      email: '',
      password: ''
    }
  },
  methods: {
    signup () {
      this.$apollo
        .mutate({
          mutation: SIGNUP_MUTATION,
          variables: {
            username: this.username,
            email: this.email,
            password: this.password
          }
        })
        .then(response => {
          // redirect to login page
          this.$router.replace('/login')
        })
    }
  }
}
</script>

このコンポーネントは、ユーザーがサインアップするためのフォームをレンダリングします。 フォームが送信されると、 signup メソッドが呼び出されます。 以内 signup 方法、私たちは利用します mutate で利用可能な方法 this.$apollo (Vue Apolloプラグインから)。 を使用します SIGNUP_MUTATION 以前に作成された突然変異は、必要な変数を渡します。 サインアッププロセスが成功すると(つまり、ユーザーが作成されると)、ユーザーをログインページ(まもなく作成します)にリダイレクトします。

サインアップルートの追加

開ける src/router/index.js、以下のコードを追加します。

src / router / index.js
// ...

import SignUp from '@/components/Admin/SignUp'

// ...

export default new Router({
  routes: [
    // add these inside the `routes` array
    {
      path: '/signup',
      name: 'SignUp',
      component: SignUp
    }
  ]
})

今私たちが訪問するとき /signup ルート、下の画像のようにサインアップフォームが表示されます。

ステップ8—ユーザーログインページの作成

ユーザーがログインする機能を追加しましょう。 ユーザーのサインアップで行ったのと同じように、最初にGraphQLミューテーションを作成しましょう。 以下のコードをに追加します src/graphql.js:

src /graphql.js
export const LOGIN_MUTATION = gql`
  mutation LoginMutation($email: String!, $password: String!) {
    login(
      email: $email,
      password: $password
    )
  }
`

このGraphQLミューテーションは、GraphQLサーバーへのユーザーログインを処理します。 ユーザーのメールアドレスとパスワードを受け取ります。

次に、 Admin フォルダ、作成 LogIn.vue 以下のコードをファイルして貼り付けます。

src / components / Admin / LogIn.vue
<template>
   <section class="section">
    <div class="columns">
      <div class="column is-4 is-offset-4">

        <h2 class="title has-text-centered">Login</h2>

        <form method="POST" @submit.prevent="login">
          <div class="field">
            <label class="label">E-Mail Address</label>

            <p class="control">
              <input
                type="email"
                class="input"
                v-model="email"
              />
            </p>
          </div>

          <div class="field">
            <label class="label">Password</label>

            <p class="control">
              <input
                type="password"
                class="input"
                v-model="password"
              />
            </p>
          </div>

          <p class="control">
            <button class="button is-primary is-fullwidth is-uppercase">Login</button>
          </p>
        </form>
      </div>
    </div>
   </section>
</template>

<script>
import { LOGIN_MUTATION } from '@/graphql'

export default {
  name: 'LogIn',
  data () {
    return {
      email: '',
      password: ''
    }
  },
  methods: {
    login () {
      this.$apollo
        .mutate({
          mutation: LOGIN_MUTATION,
          variables: {
            email: this.email,
            password: this.password
          }
        })
        .then(response => {
          // save user token to localstorage
          localStorage.setItem('blog-app-token', response.data.login)

          // redirect user
          this.$router.replace('/admin/posts')
        })
    }
  }
}
</script>

このコンポーネントは、ユーザーがログインするための簡単なフォームをレンダリングします。 フォームが送信されると、 login メソッドが呼び出されます。 以内 login 方法、私たちは利用します mutate 方法。 を使用します LOGIN_MUTATION 以前に作成された突然変異は、必要な変数を渡します。 ログインプロセスが成功したら、GraphQLサーバーから取得したトークンをlocalStorageに保存し、ユーザーをリダイレクトします。

ログインルートの追加

開ける src/router/index.js、以下のコードを追加します。

src / router / index.js
// ...

import LogIn from '@/components/Admin/LogIn'

// ...

export default new Router({
  routes: [
    // ...

    // add these inside the `routes` array
    {
      path: '/login',
      name: 'LogIn',
      component: LogIn
    }
  ]
})

今私たちが訪問するとき /login ルート、下の画像のようにログインフォームが表示されます。

ステップ9—メニューコンポーネントの作成

ブログの管理者向けの部分を具体化する前に、 Menu サイドバーのナビゲーションメニューとして機能するコンポーネント。 以内 Admin フォルダ、作成 Menu.vue 以下のコードをファイルして貼り付けます。

src / components / Admin / Menu.vue
<template>
  <aside class="menu">
    <p class="menu-label">Post</p>
      <ul class="menu-list">
        <li>
          <router-link to="/admin/posts/new">New Post</router-link>
        </li>
        <li>
          <router-link to="/admin/posts">Posts</router-link>
        </li>
      </ul>
    <p class="menu-label">User</p>
    <ul class="menu-list">
      <li>
        <router-link to="/admin/users">Users</router-link>
      </li>
    </ul>
  </aside>
</template>

これにより、ブログアプリの一部の管理セクションへのリンクがレンダリングされます。

ステップ10—ユーザーリストページの作成

管理セクションでは、作成されたユーザーのリストを表示できるようにする必要があります。 そのために、 Users 成分。 しかし、最初に、作成されたすべてのユーザーをフェッチするGraphQLクエリを作成しましょう。 以下のコードをに追加します src/graphql.js:

src /graphql.js
export const ALL_USERS_QUERY = gql`
  query AllUsersQuery {
    allUsers {
      id
      username
      email
    }
  }
`

このGraphQLクエリは、GraphQLサーバーからすべてのユーザーをフェッチします。

次に、を作成しましょう Users 成分。 以内 Admin フォルダ、作成 Users.vue 以下のコードをファイルして貼り付けます。

src / components / Admin / Users.vue
<template>
  <section class="section">
    <div class="container">
      <div class="columns">
        <div class="column is-3">
          <Menu/>
        </div>
        <div class="column is-9">
          <h2 class="title">Users</h2>

          <table class="table is-striped is-narrow is-hoverable is-fullwidth">
            <thead>
              <tr>
                <th>Username</th>
                <th>Email</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              <tr
                v-for="user in allUsers"
                :key="user.id">
                <td>{{ user.username }}</td>
                <td>{{ user.email }}</td>
                <td>
                  <router-link :to="`/admin/users/${user.id}`">View</router-link>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
import Menu from '@/components/Admin/Menu'
import { ALL_USERS_QUERY } from '@/graphql'

export default {
  name: 'Users',
  components: {
    Menu
  },
  data () {
    return {
      allUsers: []
    }
  },
  apollo: {
    // fetch all users
    allUsers: {
      query: ALL_USERS_QUERY
    }
  }
}
</script>

私たちは利用します Menu 以前に作成されたコンポーネント。 次に、GraphQLサーバーからデータを取得したときに入力されるデータを定義します。 以内 apollo オブジェクトの場合、GraphQLクエリを追加してすべてのユーザーをフェッチします。 これはを利用します ALL_USERS_QUERY 上で作成しました。 データの名前(allUsers この場合)は、GraphQLクエリで使用されているものと同じ名前である必要があります(allUsers この場合)。 一度 allUsers GraphQLサーバーからのデータが入力されている場合、ユーザーの配列をループすることにより、テーブルにユーザーを表示します。 また、各ユーザーの詳細を表示するためのリンクを追加します。

ユーザールートの追加

開ける src/router/index.js、以下のコードを追加します。

src / router / index.js
// ...

import Users from '@/components/Admin/Users'

// ...

export default new Router({
  routes: [
    // ...

    // add these inside the `routes` array
    {
      path: '/admin/users',
      name: 'Users',
      component: Users
    }
  ]
})

今私たちが訪問するとき /admin/users ルート、下の画像のようにユーザーのリストが表示されます。

ステップ11—ユーザー詳細ページの作成

最後のセクションでは、ユーザーの詳細を表示するためのリンクを追加します。 それでは、実装しましょう。 以下のコードをに追加します src/graphql.js:

src /graphql.js
export const USER_QUERY = gql`
  query UserQuery($id: Int!) {
    user(id: $id) {
      id
      username
      email
      posts {
        id
      }
    }
  }
`

このGraphQLクエリは、GraphQLサーバーからIDでユーザーをフェッチします。 ユーザーのIDを引数として取ります。 ユーザーIDはから渡されます UserDetails 成分。

次に、を作成しましょう UserDetails 成分。 以内 Admin フォルダ、作成 UserDetails.vue 以下のコードをファイルして貼り付けます。

src / components / Admin / UserDetails.vue
<template>
  <section class="section">
    <div class="container">
      <div class="columns">
        <div class="column is-3">
          <Menu/>
        </div>
        <div class="column is-9">
          <h2 class="title">User Details</h2>

          <div class="field is-horizontal">
            <div class="field-label is-normal">
              <label class="label">Username</label>
            </div>
            <div class="field-body">
              <div class="field">
                <p class="control">
                  <input class="input is-static" :value="user.username" readonly />
                </p>
              </div>
            </div>
          </div>

          <div class="field is-horizontal">
            <div class="field-label is-normal">
              <label class="label">Email Address</label>
            </div>
            <div class="field-body">
              <div class="field">
                <p class="control">
                  <input class="input is-static" :value="user.email" readonly />
                </p>
              </div>
            </div>
          </div>

          <div class="field is-horizontal">
            <div class="field-label is-normal">
              <label class="label">Number of posts</label>
            </div>
            <div class="field-body">
              <div class="field">
                <p class="control">
                  <input class="input is-static" :value="user.posts.length" readonly />
                </p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
import Menu from '@/components/Admin/Menu'
import { USER_QUERY } from '@/graphql'

export default {
  name: 'UserDetails',
  components: {
    Menu
  },
  data () {
    return {
      user: '',
      id: this.$route.params.id
    }
  },
  apollo: {
    // fetch user by ID
    user: {
      query: USER_QUERY,
      variables () {
        return {
          id: this.id
        }
      }
    }
  }
}
</script>

指定したユーザーのユーザー名、メールアドレス、作成された投稿数を表示します。 The USER_QUERY 詳細を表示するユーザーのIDを受け入れます。 ユーザーIDは、ルートパラメータから取得されます。 つまり、与えられた /admin/users/12、12は特定のユーザーのIDです。 このIDをクエリに渡す方法が必要です。 これを行うには、反応パラメータを使用して、 variables ユーザーIDを含むオブジェクトを返す関数。

ユーザー詳細ルートの追加

開ける src/router/index.js、以下のコードを追加します。 このルートは、以前のすべてのルートより下にある必要があります。

src / router / index.js
// ...

import UserDetails from '@/components/Admin/UserDetails'

// ...

export default new Router({
  routes: [
    // ...

    // add these inside the `routes` array
    {
      path: '/admin/users/:id',
      name: 'UserDetails',
      component: UserDetails,
      props: true
    }
  ]
})

これで、特定のユーザーの詳細を表示できるようになります。

ステップ12—ユーザーの承認

認証されたユーザーのみが新しい投稿を追加できます。 だから、私たちは合格する方法が必要です Authorization ユーザートークンと、ユーザーが実際に新しい投稿を追加できることを示す新しい投稿を追加するリクエストを含むヘッダー。 と apollo-link-context、これは簡単に実行できます。 開ける src/main.js 以下のコードを追加します。

src / main.js
// ...

import { setContext } from 'apollo-link-context'

// ...

const authLink = setContext((_, { headers }) => {
  // get the authentication token from localstorage if it exists
  const token = localStorage.getItem('blog-app-token')

  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : null
    }
  }
})

// ...

// update apollo client as below
const apolloClient = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
})

まず、インポートします apollo-link-context. 次に、それを使用して作成します authLink これは、ローカルストレージからユーザートークンを取得し、Authorizationヘッダーを含むヘッダーを返します。 最後に、 authLink Apolloクライアントで。

これで、Authorizationヘッダーが、GraphQLサーバーに対して行われたすべてのリクエストとともに送信されます。

ステップ13—新しい投稿ページを作成する

投稿はブログの中心です。 ユーザーは新しい投稿を追加できるはずです。 繰り返しになりますが、最初にブログに新しい投稿を追加するためのGraphQLミューテーションを作成します。 以下のコードをに追加します src/graphql.js:

src /graphql.js
export const ADD_POST_MUTATION = gql`
  mutation AddPostMutation($title: String!, $content: String!) {
    addPost(
      title: $title,
      content: $content
    ) {
      id
      slug
      title
      content
      user {
        id
        username
        email
      }
    }
  }
`

このミューテーションは、GraphQLサーバーに追加する投稿のタイトルとコンテンツを取得します。

次に、を作成します AddPost 内のコンポーネント Admin フォルダを作成し、以下のコードをその中に貼り付けます。

src / components / Admin / AddPost.vue
<template>
  <section class="section">
    <div class="container">
      <div class="columns">
        <div class="column is-3">
          <Menu/>
        </div>
        <div class="column is-9">
          <h2 class="title">Add Post</h2>

          <form method="post" @submit.prevent="addPost">
            <div class="field">
              <label class="label">Title</label>

              <p class="control">
                <input
                  class="input"
                  v-model="title"
                  placeholder="Post title"
                />
              </p>
            </div>

            <div class="field">
              <label class="label">Content</label>

              <p class="control">
                <textarea
                  class="textarea"
                  rows="10"
                  v-model="content"
                  placeholder="Post content"
                  ></textarea>
              </p>
            </div>

            <p class="control">
              <button class="button is-primary">Add Post</button>
            </p>
          </form>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
import Menu from '@/components/Admin/Menu'
import { ADD_POST_MUTATION, ALL_POSTS_QUERY } from '@/graphql'

export default {
  name: 'AddPost',
  components: {
    Menu
  },
  data () {
    return {
      title: '',
      content: ''
    }
  },
  methods: {
    addPost () {
      this.$apollo
        .mutate({
          mutation: ADD_POST_MUTATION,
          variables: {
            title: this.title,
            content: this.content
          },
          update: (store, { data: { addPost } }) => {
            // read data from cache for this query
            const data = store.readQuery({ query: ALL_POSTS_QUERY })

            // add new post from the mutation to existing posts
            data.allPosts.push(addPost)

            // write data back to the cache
            store.writeQuery({ query: ALL_POSTS_QUERY, data })
          }
        })
        .then(response => {
          // redirect to all posts
          this.$router.replace('/admin/posts')
        })
    }
  }
}
</script>

このコンポーネントは、新しい投稿を追加するためのフォームをレンダリングします。 それは使用します ADD_POST_MUTATION それに必要な変数を渡します。 Apolloクライアントは(この場合はメモリ内に)クエリを実行するため、ミューテーションアクションを実行するたびにキャッシュを更新する方法が必要です。 あることに注意してください update 新しく追加された投稿をキャッシュに追加してストアを更新するために使用する関数。 まず、クエリに一致するキャッシュからデータをフェッチします(ALL_POSTS_QUERY)、新しい投稿をに追加します allPosts 配列。 最後に、新しいデータをキャッシュに書き戻します。 投稿が正常に追加されると、投稿のリストにリダイレクトされます(これはまもなく作成されます)。

投稿ルートの追加

開ける src/router/index.js、以下のコードを追加します。

src / router / index.js
// ...

import AddPost from '@/components/Admin/AddPost'

// ...

export default new Router({
  routes: [
    // ...

    // add these inside the `routes` array
    {
      path: '/admin/posts/new',
      name: 'AddPost',
      component: AddPost
    }
  ]
})

ユーザーは今すぐ新しい投稿を追加できるはずです:

ステップ14—すべての投稿を表示する

まず、以下のコードを追加してGraphQLクエリを作成します。 src/graphql.js:

src /graphql.js
export const ALL_POSTS_QUERY = gql`
  query AllPostsQuery {
    allPosts {
      id
      title
      slug
      user {
        username
      }
    }
  }
`

このGraphQLクエリは、GraphQLサーバーからすべての投稿をフェッチします。

次に、 Posts 内のコンポーネント Admin フォルダを作成し、以下のコードをその中に貼り付けます。

src / components / Admin / Posts.vue
<template>
  <section class="section">
    <div class="container">
      <div class="columns">
        <div class="column is-3">
          <Menu/>
        </div>
        <div class="column is-9">
          <h2 class="title">Posts</h2>

          <table class="table is-striped is-narrow is-hoverable is-fullwidth">
            <thead>
              <tr>
                <th>Title</th>
                <th>User</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              <tr
                v-for="post in allPosts"
                :key="post.id"
              >
                <td>{{ post.title }}</td>
                <td>{{ post.user.username }}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
import Menu from '@/components/Admin/Menu'
import { ALL_POSTS_QUERY } from '@/graphql'

export default {
  name: 'Posts',
  components: {
    Menu
  },
  data () {
    return {
      allPosts: []
    }
  },
  apollo: {
    // fetch all posts
    allPosts: {
      query: ALL_POSTS_QUERY
    }
  }
}
</script>

私たちは利用します Menu 以前に作成されたコンポーネント。 次に、GraphQLサーバーからデータを取得したときに入力されるデータを定義します。 以内 apollo オブジェクトの場合、GraphQLクエリを追加してすべてのユーザーをフェッチします。 これはを利用します ALL_USERS_QUERY 上で作成しました。 データの名前(allUsers この場合)は、GraphQLクエリで使用されているものと同じ名前である必要があります(allUsers この場合)。 一度 allUsers GraphQLサーバーからのデータが入力されている場合、ユーザーの配列をループすることにより、テーブルにユーザーを表示します。 また、各ユーザーの詳細を表示するためのリンクを追加します。

投稿ルートの追加

開ける src/router/index.js、以下のコードを追加します。

src / router / index.js
// ...

import Posts from '@/components/Admin/Posts'

// ...

export default new Router({
  routes: [
    // ...

    // add these inside the `routes` array
    {
      path: '/admin/posts',
      name: 'Posts',
      component: Posts
    }
  ]
})

今私たちが訪問するとき /admin/posts ルート、下の画像のように投稿のリストが表示されます。

ステップ15—ブログホームページの作成

ブログのホームページには、投稿の表示セクションと同じように作成されたすべての投稿のリストが表示されます。 実際、ホームページは投稿の表示に使用されるものとまったく同じGraphQLを使用します。 異なるのはホームページのマークアップのみです。 作成する Home 内部のコンポーネント src/components 以下のコードを追加します。

src / components / Home.vue
<template>
  <section class="section">
    <div class="columns">
      <div class="column is-6 is-offset-3">
        <h1 class="title">Latest Posts</h1>

        <h3
          v-for="post in allPosts"
          :key="post.id"
          class="title is-5"
        >
          <router-link :to="post.slug">
            {{ post.title }}
          </router-link>
        </h3>
      </div>
    </div>
  </section>
</template>

<script>
import { ALL_POSTS_QUERY } from '@/graphql'

export default {
  name: 'Home',
  data () {
    return {
      allPosts: []
    }
  },
  apollo: {
    // fetch all posts
    allPosts: {
      query: ALL_POSTS_QUERY
    }
  }
}
</script>

ご覧のとおり、JavaScriptセクションは Posts 成分。 ちょうど異なるマークアップ。 投稿配列をループして、スラッグにリンクされた各投稿のタイトルを表示します。

ホームルートの追加

開ける src/router/index.js、以下のコードを追加します。

src / router / index.js
// ...

import Home from '@/components/Home'

// ...

export default new Router({
  routes: [
    // ...

    // add these inside the `routes` array
    {
      path: '/',
      name: 'Home',
      component: Home
    }
  ]
})

訪問 / ルート、下の画像のようにブログのホームページが表示されます。

ステップ16—単一の投稿ページを作成する

最後に追加するのは、特定の投稿を表示する機能です。 以下のコードをに追加します src/graphql.js:

src /graphql.js
export const POST_QUERY = gql`
  query PostQuery($slug: String!) {
    post(slug: $slug) {
      id
      title
      slug
      content
      user {
        id
        username
        email
      }
    }
  }
`

このクエリは、スラッグによって投稿をフェッチします。 引数としてフェッチされるのは投稿のスラッグです。

次に、 SinglePost 内部のコンポーネント src/components 以下のコードを追加します。

src / components / SinglePost.vue
<template>
  <section class="section">
    <div class="columns">
      <div class="column is-6 is-offset-3">
        <router-link class="button is-link is-small" to="/">Back Home</router-link>

        <h1 class="title">
          {{ post.title }}
        </h1>

        <div class="content">
          {{ post.content }}
        </div>
      </div>
    </div>
  </section>
</template>

<script>
import { POST_QUERY } from '@/graphql'

export default {
  name: 'SinglePost',
  data () {
    return {
      post: '',
      slug: this.$route.params.slug
    }
  },
  apollo: {
    // fetch post by slug
    post: {
      query: POST_QUERY,
      variables () {
        return {
          slug: this.slug
        }
      }
    }
  }
}
</script>

投稿のタイトルとその内容、およびホームページに戻るためのリンクを表示します。 JavaScriptセクションは、ユーザーの詳細を表示する際に使用される実装に従います。 この場合、ルートパラメータからポストスラッグを取得します。

ビューポストルートの追加

開ける src/router/index.js、以下のコードを追加します。

src / router / index.js
// ...

import SinglePost from '@/components/SinglePost'

// ...

export default new Router({
  routes: [
    // ...

    // add these inside the `routes` array
    {
      path: '/:slug',
      name: 'SinglePost',
      component: SinglePost,
      props: true
    }
  ]
})

注:このルートは、routes配列の最後のルートである必要があります。

これで、1つの投稿を表示できるようになります。

結論

このチュートリアルでは、GraphQL、Apolloクライアント、およびVueJSを使用してブログアプリを構築する方法を見てきました。 また、フロントエンドアプリをGraphQLサーバーに接続する方法も確認しました。

このチュートリアルの完全なコードは、GitHubで入手できます。