Cómo crear una aplicación de gestión de archivos en GraphQL y Vue

Introducción

Índice
  1. Introducción
  • Prerrequisitos
  • Lo que vamos a construir
  • Paso 1: obtención de claves de Cloudinary
  • Paso 2: creación del servidor GraphQL
  • Paso 3: creación de la aplicación front-end
  • Paso 4: Obtener fotos
  • Paso 5: Carga de fotografías
  • Conclusión
  • En este tutorial, repasaremos cómo gestionar las cargas de archivos en GraphQL mediante la creación de una aplicación full-stack. Este tutorial se dividirá en dos secciones principales: creación de la API de GraphQL y creación de la aplicación frontend. La API de GraphQL se creará con Apollo Server y la aplicación frontend se creará con Vue.js y Vue Apollo.

    Prerrequisitos

    En este tutorial se presupone que estás familiarizado con GraphQL y Vue. Para obtener más orientación, puedes consultar este tutorial de GraphQL con Node y este tutorial que crea un blog con Vue, GraphQL y Apollo Client.

    Lo que vamos a construir

    Para este tutorial, crearemos una aplicación de álbum de fotos en la que los usuarios podrán cargar y ver sus fotos. Todas las fotos se cargarán directamente en Cloudinary. A continuación, se muestra una demostración rápida de la aplicación final:

    Paso 1: obtención de claves de Cloudinary

    Antes de comenzar con el código, asegurémonos de que tenemos nuestra clave de Cloudinary. Si aún no tienes una cuenta con ellos, puedes registrarte de forma gratuita. De lo contrario, inicia sesión en tu panel de control, donde verás los detalles de tu cuenta junto con tus claves.

    Paso 2: creación del servidor GraphQL

    Ahora, comencemos a crear el servidor GraphQL. Primero, creemos nuestro directorio de proyecto:

    $ mkdir graphql-vue-photo-upload  cd graphql-vue-photo-upload$ mkdir server  cd server$ npm init -y

    Todo el código relacionado con la API de GraphQL estará dentro del serverdirectorio. A continuación, instalemos las dependencias necesarias para nuestro servidor GraphQL:

    $ npm install graphql apollo-server cloudinary dotenv

    Además de instalar Apollo Server y sus dependencias, también instalamos la librería Node.js de Cloudinary y un paquete para leer variables de entorno.

    Una vez que se haya realizado la instalación, podemos comenzar a crear el servidor GraphQL. Crea un nuevo srcdirectorio y crea un nuevo index.jsarchivo dentro de él. Luego, agrega el siguiente código:

    // server/src/index.jsconst { 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}`))

    A continuación, debemos crear el esquema y los solucionadores a los que hace referencia nuestro servidor GraphQL. Comenzaremos creando el esquema. Cree un directorio schema.jsinterno y pegue el siguiente código en él:src

    // server/src/schema.jsconst { 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

    Aquí, definimos un Phototipo que consta de dos campos: el nombre de archivo de la foto y la ruta a la foto real. Luego, definimos una única consulta allPhotospara obtener todas las fotos cargadas. Por último, tenemos una mutación para cargar una foto. La uploadPhotomutación acepta un único argumento, que es la foto que se va a cargar. El argumento es del tipo escalar Upload, que está disponible para nosotros en mi servidor Apollo, ya que tiene soporte integrado para la carga de archivos. La mutación devolverá la foto cargada.

    El siguiente paso es crear los solucionadores. Dentro srcdel directorio, crea un resolvers.jsy agrega el código que se muestra a continuación:

    // server/src/resolvers.jsconst cloudinary = require('cloudinary').v2cloudinary.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

    Primero, incorporamos la biblioteca Cloudinary y la configuramos con nuestras credenciales, que se obtienen de las variables de entorno. Luego, creamos una matriz vacía, que contendrá nuestras fotos. A continuación, definimos el solucionador para la allPhotosconsulta, que devuelve la matriz de fotos.

    Para la uploadPhotomutación, Apollo Server devolvería el archivo seleccionado como Promise, que contiene un montón de detalles sobre el archivo, como: createReadStream, y . En este tutorial, solo haremos uso de los dos primeros, por lo que los extraemos del objeto. Usando , transmitimos el archivo directamente a filenameCloudinary . Dado que es una operación asincrónica, lo envolvemos en un y lo s. Si se resolvió, es decir, el archivo se cargó correctamente a Cloudinary, creamos un nuevo objeto que contiene el nombre del archivo cargado y la ruta de Cloudinary al archivo. Luego, enviamos el nuevo objeto a la matriz de fotos y finalmente devolvemos el nuevo objeto.mimetypeencodingcreateReadStreamPromiseawaitPromise

    Por último, si hubo un error al cargar el archivo a Cloudinary, podemos registrar el error en la consola.

    Antes de finalizar la API de GraphQL, agreguemos rápidamente nuestras variables de entorno. Cree un .envarchivo directamente en el serverdirectorio y agregue el código que se muestra a continuación:

    // server/.envCLOUD_NAME=YOUR_CLOUD_NAMEAPI_KEY=YOUR_API_KEYAPI_SECRET=YOUR_API_SECRET

    Recuerde reemplazar los marcadores de posición con los detalles reales de su cuenta.

    Por último, iniciemos el servidor:

    $ node src/index.js

    El servidor debería estar ejecutándose en[http://localhost:4000](http://localhost:4000)

    Paso 3: creación de la aplicación front-end

    Como ya se mencionó, la aplicación frontend se creará con Vue.js, así que creemos una nueva aplicación Vue.js usando Vue CLI:

    $ vue create client

    Cuando se le solicite, presione Enter para seleccionar el valor predeterminado. Inicie la aplicación y déjela ejecutándose mientras la desarrollamos:

    $ cd client$ yarn serve

    La aplicación debe ejecutarse en http://localhost:8080

    Una vez creada la aplicación Vue, instalemos las dependencias necesarias:

    $ npm install vue-apollo graphql-tag graphql apollo-cache-inmemory apollo-client apollo-upload-client

    De estas dependencias, la que es nueva y que me gustaría destacar es [apollo-upload-client](https://github.com/jaydenseric/apollo-upload-client). Es un paquete para Apollo Client que nos permite enviar solicitudes multiparte GraphQL. Se utilizará en lugar de apollo-link.

    A continuación, configuremos Vue Apollo y estas dependencias. Actualice main.jscomo se indica a continuación:

    // client/src/main.jsimport { 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 = falseVue.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')

    Notarás que aquí usamos createUploadLinkfrom apollo-upload-clientpara crear el ApolloClientenlace y le pasamos nuestro punto final de API GraphQL.

    Para darle un poco de estilo a nuestra aplicación, utilizaremos UIKit. Agregue la siguiente línea a headla sección de index.html:

    !-- client/public/index.html --link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.1.5/css/uikit.min.css" /

    Paso 4: Obtener fotos

    Comenzaremos con la consulta GraphQL para obtener todas nuestras fotos. Crea un graphqldirectorio dentro del client/srcdirectorio y, dentro de él, crea un AllPhotos.jsarchivo y pega el código que aparece a continuación:

    // client/src/graphql/AllPhotos.jsimport gql from 'graphql-tag'export default gql`query allPhotos {    allPhotos {      filename      path    }  }`

    Para los fines de aprendizaje de este tutorial, utilizaremos únicamente el App.vue componente. Por lo tanto, actualicémoslo de la siguiente manera:

    // client/src/App.vuetemplate  section    div      h2Photo Album/h2      div        div v-for="(photo, index) in allPhotos" :key="index"          div            div              img :src="photo.path"            /div            div{{ photo.filename }}/div          /div        /div      /div    /div  /section/templatescriptimport ALL_PHOTOS from "./graphql/AllPhotos";export default {  name: "app",  apollo: {    allPhotos: ALL_PHOTOS  }};/script

    Dentro del apolloobjeto, agregamos la ALL_PHOTOSconsulta para obtener todas las fotos y guardarlas en un archivo allPhotos. Una vez que allPhotosse completa con datos de nuestra API GraphQL, mostramos las fotos recorriéndolas en bucle.

    Si visualizamos nuestra aplicación, deberíamos obtener algo similar a lo siguiente:

    Paso 5: Carga de fotografías

    Por supuesto, necesitamos haber subido algunas fotos antes de poder verlas. Vamos a implementar eso ahora. Dentro del graphqldirectorio, crea un archivo UploadPhoto.jsy pega el código que aparece a continuación:

    // client/src/graphql/UploadPhoto.jsimport gql from 'graphql-tag'export default gql`mutation uploadPhoto($photo: Upload!) {    uploadPhoto(photo: $photo) {      filename      path    }  }`

    A continuación, agregue el fragmento a continuación a la templatesección de App.vue, justo debajo del encabezado Álbum de fotos :

    // client/src/App.vuediv  input type="file" accept="image/*" @change="uploadPhoto"/div

    Aquí tenemos un campo de entrada de archivo que solo acepta imágenes. Al cambiar el campo de entrada, uploadPhotose activa un método.

    En la scriptsección, agregue:

    // client/src/App.vueimport 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 });      }    });  }}

    Extraemos el archivo targetdel evento de entrada, luego llamamos al mutatemétodo y le pasamos la UPLOAD_PHOTOmutación y el argumento requerido (a través del variablesobjeto). Obtenemos el archivo seleccionado del filesobjeto target. Una vez que se ejecuta la mutación, actualizamos la caché agregando la foto recién cargada a la allPhotosmatriz.

    Conclusión

    En este tutorial, hemos visto cómo gestionar las cargas de archivos en GraphQL utilizando Apollo Server en el lado del servidor y Vue y Vue Apollo en el lado del cliente. Aunque utilizamos Cloudinary para almacenar nuestras fotos, también puedes empaquetarlas para cualquier otro servicio de almacenamiento en la nube o incluso puedes guardarlas directamente en tu propio sistema de archivos local.

    SUSCRÍBETE A NUESTRO BOLETÍN 
    No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

    Subir

    Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion