GraphQLとVueでファイル処理アプリを構築する方法
序章
このチュートリアルでは、フルスタックアプリを構築して、GraphQLでファイルのアップロードを処理する方法について説明します。 このチュートリアルは、GraphQL APIの構築と、フロントエンドアプリの作成という2つの主要なセクションに分かれています。 GraphQL APIはApolloサーバーを使用して構築され、フロントエンドアプリはVue.jsとVueApolloを使用して構築されます。
前提条件
このチュートリアルは、GraphQLとVueに慣れていることを前提としています。 詳細なガイダンスについては、この GraphQL with Nodeチュートリアル、およびVue、GraphQL、およびApolloClientを使用してブログを構築するこのチュートリアルから学ぶことができます。
構築するもの
このチュートリアルでは、ユーザーが写真をアップロードしたり表示したりできるフォトアルバムアプリを作成します。 すべての写真はCloudinaryに直接アップロードされます。 以下は、最終的なアプリの簡単なデモです。
ステップ1—Cloudinaryキーを取得する
コードに飛び込む前に、Cloudinaryキーが設定されていることを確認しましょう。 まだアカウントをお持ちでない場合は、無料でサインアップできます。 それ以外の場合は、ダッシュボードにログインすると、アカウントの詳細とキーが表示されます。
ステップ2—GraphQLサーバーを構築する
それでは、GraphQLサーバーの構築を始めましょう。 まず、プロジェクトディレクトリを作成しましょう。
$ mkdir graphql-vue-photo-upload && cd graphql-vue-photo-upload
$ mkdir server && cd server
$ npm init -y
すべてのGraphQLAPI関連のコードは内部にあります server
ディレクトリ。 次に、GraphQLサーバーに必要な依存関係をインストールしましょう。
$ npm install graphql apollo-server cloudinary dotenv
Apollo Serverとその依存関係のインストールに加えて、CloudinaryNode.jsライブラリと環境変数を読み取るためのパッケージもインストールします。
インストールが完了したら、GraphQLサーバーの構築を開始できます。 新しいを作成します src
ディレクトリを作成し、新しい index.js
その中にファイルを追加し、次のコードを追加します。
// server/src/index.js
const { ApolloServer } = require('apollo-server')
require('dotenv').config()
const typeDefs = require('./schema')
const resolvers = require('./resolvers')
const server = new ApolloServer({
typeDefs,
resolvers
})
server.listen().then(({ url }) => console.log(`Server ready at ${url}`))
次に、GraphQLサーバーが参照するスキーマとリゾルバーを作成する必要があります。 スキーマの作成から始めます。 作成する schema.js
中身 src
ディレクトリに次のコードを貼り付けます。
// server/src/schema.js
const { gql } = require('apollo-server')
const typeDefs = gql`type Photo {
filename: String!
path: String!
}
type Query {
allPhotos: [Photo]
}
type Mutation {
uploadPhoto(photo: Upload!): Photo!
}`
module.exports = typeDefs
ここでは、 Photo
写真のファイル名と実際の写真へのパスの2つのフィールドで構成されるタイプ。 次に、単一のクエリを定義します allPhotos
アップロードされたすべての写真を取得します。 最後に、写真をアップロードするためのミューテーションがあります。 The uploadPhoto
ミューテーションは、アップロードされる写真である単一の引数を受け入れます。 引数はスカラー型です Upload
、ファイルアップロードのサポートが組み込まれているため、Apolloサーバーで利用できるようになります。 ミューテーションはアップロードされた写真を返します。
次に行うことは、リゾルバーを作成することです。 まだ中に src
ディレクトリ、作成 resolvers.js
以下のコードを追加します。
// server/src/resolvers.js
const cloudinary = require('cloudinary').v2
cloudinary.config({
cloud_name: process.env.CLOUD_NAME,
api_key: process.env.API_KEY,
api_secret: process.env.API_SECRET
})
const photos = []
const resolvers = {
Query: {
allPhotos () {
return photos
}
},
Mutation: {
async uploadPhoto (parent, { photo }) {
const { filename, createReadStream } = await photo
try {
const result = await new Promise((resolve, reject) => {
createReadStream().pipe(
cloudinary.uploader.upload_stream((error, result) => {
if (error) {
reject(error)
}
resolve(result)
})
)
})
const newPhoto = { filename, path: result.secure_url }
photos.push(newPhoto)
return newPhoto
} catch (err) {
console.log(err)
}
}
}
}
module.exports = resolvers
まず、Cloudinaryライブラリを取得し、環境変数から取得するクレデンシャルを構成します。 次に、写真を保持する空の配列を作成します。 次に、のリゾルバを定義します allPhotos
クエリ。写真の配列を返します。
のために uploadPhoto
ミューテーションの場合、ApolloServerは選択したファイルを次のように返します。 Promise
、次のようなファイルに関する一連の詳細が含まれています。 createReadStream
, filename
, mimetype
と encoding
. このチュートリアルでは、最初の2つのみを使用するため、オブジェクトからそれらを抽出します。 使用する createReadStream
、ファイルをCloudinaryに直接ストリーミングします。 これは非同期操作であるため、 Promise
と await
座る。 の場合 Promise
が解決されました。つまり、ファイルがCloudinaryに正常にアップロードされました。アップロードされたファイル名と、ファイルへのCloudinaryパスを含む新しいオブジェクトを作成します。 次に、新しいオブジェクトをphotos配列にプッシュし、最後に新しいオブジェクトを返します。
最後に、Cloudinaryへのファイルのアップロードでエラーが発生した場合は、エラーをコンソールログに記録できます。
GraphQL APIをまとめる前に、環境変数を簡単に追加しましょう。 作成する .env
直接ファイル server
ディレクトリを作成し、その中に以下のコードを追加します。
// server/.env
CLOUD_NAME=YOUR_CLOUD_NAME
API_KEY=YOUR_API_KEY
API_SECRET=YOUR_API_SECRET
プレースホルダーを実際のアカウントの詳細に置き換えることを忘れないでください。
最後に、サーバーを起動しましょう。
$ node src/index.js
サーバーはで実行されている必要があります [http://localhost:4000](http://localhost:4000)
ステップ3—フロントエンドアプリを構築する
すでに述べたように、フロントエンドアプリはVue.jsで構築されるので、VueCLIを使用して新しいVue.jsアプリを作成しましょう。
$ vue create client
プロンプトが表示されたら、Enterキーを押してデフォルトのプリセットを選択します。 アプリを起動し、ビルド中は実行したままにします。
$ cd client
$ yarn serve
アプリはhttp:// localhost:8080で実行されている必要があります
Vueアプリが作成されたら、必要な依存関係をインストールしましょう。
$ npm install vue-apollo graphql-tag graphql apollo-cache-inmemory apollo-client apollo-upload-client
これらの依存関係のうち、新しくて指摘したいのは [apollo-upload-client](https://github.com/jaydenseric/apollo-upload-client)
. これは、GraphQLマルチパートリクエストを送信できるようにするApolloクライアント用のパッケージです。 代わりに使用されます apollo-link
.
次に、VueApolloとこれらの依存関係を構成しましょう。 アップデート main.js
以下のように:
// client/src/main.js
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloClient } from 'apollo-client'
import { createUploadLink } from 'apollo-upload-client'
import Vue from 'vue'
import VueApollo from 'vue-apollo'
import App from './App.vue'
Vue.config.productionTip = false
Vue.use(VueApollo)
const apolloClient = new ApolloClient({
link: createUploadLink({ uri: 'http://localhost:4000' }),
cache: new InMemoryCache()
})
const apolloProvider = new VueApollo({
defaultClient: apolloClient
})
new Vue({
apolloProvider,
render: h => h(App)
}).$mount('#app')
ここで私たちが使用していることに気付くでしょう createUploadLink
から apollo-upload-client
を作成するには ApolloClient
リンク、GraphQLAPIエンドポイントを渡します。
アプリに少しスタイルを与えるために、UIKitを使用します。 以下の行をに追加します head
のセクション index.html
:
<!-- client/public/index.html -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.1.5/css/uikit.min.css" />
ステップ4—写真を取得する
すべての写真をフェッチするためのGraphQLクエリから始めます。 作成する graphql
内部のディレクトリ client/src
ディレクトリとで、を作成します AllPhotos.js
以下のコードをファイルして貼り付けます。
// client/src/graphql/AllPhotos.js
import gql from 'graphql-tag'
export default gql`query allPhotos {
allPhotos {
filename
path
}
}`
このチュートリアルの学習目的では、 App.vue
成分。 それでは、以下のように更新しましょう。
// client/src/App.vue
<template>
<section class="uk-section">
<div class="uk-container uk-container-small">
<h2>Photo Album</h2>
<div class="uk-grid uk-child-width-1-3@m">
<div class="uk-margin" v-for="(photo, index) in allPhotos" :key="index">
<div class="uk-card uk-card-default">
<div class="uk-card-media-top">
<img :src="photo.path">
</div>
<div class="uk-card-body">{{ photo.filename }}</div>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
import ALL_PHOTOS from "./graphql/AllPhotos";
export default {
name: "app",
apollo: {
allPhotos: ALL_PHOTOS
}
};
</script>
以内 apollo
オブジェクト、追加します ALL_PHOTOS
すべての写真を取得して保存するためのクエリ allPhotos
. 一度 allPhotos
GraphQL APIからのデータが入力されている場合は、写真をループして表示します。
アプリを表示すると、次のようなものが表示されます。
ステップ5—写真をアップロードする
もちろん、写真を見る前にアップロードしておく必要があります。 それを実装しましょう。 まだ中に graphql
ディレクトリ、作成 UploadPhoto.js
以下のコードを貼り付けます。
// client/src/graphql/UploadPhoto.js
import gql from 'graphql-tag'
export default gql`mutation uploadPhoto($photo: Upload!) {
uploadPhoto(photo: $photo) {
filename
path
}
}`
次に、以下のスニペットをに追加します template
のセクション App.vue
、フォトアルバムの見出しのすぐ下:
// client/src/App.vue
<div class="uk-margin">
<input type="file" accept="image/*" @change="uploadPhoto">
</div>
ここには、画像のみを受け入れるファイル入力フィールドがあります。 入力フィールドの変更時に uploadPhoto
メソッドがトリガーされます。
の中に script
セクション、追加:
// client/src/App.vue
import UPLOAD_PHOTO from "./graphql/UploadPhoto";
methods: {
async uploadPhoto({ target }) {
await this.$apollo.mutate({
mutation: UPLOAD_PHOTO,
variables: {
photo: target.files[0]
},
update: (store, { data: { uploadPhoto } }) => {
const data = store.readQuery({ query: ALL_PHOTOS });
data.allPhotos.push(uploadPhoto);
store.writeQuery({ query: ALL_PHOTOS, data });
}
});
}
}
抽出します target
入力イベントから、を呼び出します mutate
メソッド、それに渡す UPLOAD_PHOTO
突然変異と必要な引数( variables
物体)。 選択したファイルを files
に target
物体。 ミューテーションが実行されると、新しくアップロードされた写真をに追加してキャッシュを更新します allPhotos
配列。
結論
したがって、このチュートリアルでは、サーバー側でApollo Serverを使用し、クライアント側でVueとVue Apolloを使用して、GraphQLでファイルのアップロードを処理する方法を見てきました。 写真の保存にはCloudinaryを使用しましたが、他のクラウドストレージサービス用にラップしたり、独自のローカルファイルシステムに直接保存したりすることもできます。