Creaci贸n de API GraphQL con Vue.js y Apollo Client

    Introducci贸n

    GraphQL es un lenguaje de consulta orientado a gr谩ficos escrito por Facebook. A diferencia de las API REST, GraphQL presenta caracter铆sticas que hacen que el desarrollo de API sea m谩s eficiente y est茅 en sinton铆a con los modelos de bases de datos.

    Funciones GraphQL

    • diferente a DESCANSO, solo hay un punto final al que se enviar谩n todas las solicitudes. Entonces, en lugar de consultar /users para obtener una lista de usuarios, o /user/:id para obtener un usuario en particular, el punto final se ver谩 como /graphql para todas las solicitudes.
    • En GraphQL, los datos que regresan de una respuesta los establece la biblioteca de consultas indicada y se puede configurar para enviar solo algunas propiedades de datos, por lo tanto, las consultas en GraphQL tienen un mejor rendimiento.
    • No es necesario establecer verbos de m茅todo en GraphQL. Palabras clave como Consulta o Mutaci贸n decidir谩 qu茅 realizar谩 la solicitud.
    • Las rutas de la API REST generalmente son manejadas por un manejador de ruta. En GraphQL, puede hacer que una sola consulta active m煤ltiples mutaciones y obtenga una respuesta compuesta de m煤ltiples fuentes.

    Consultas

    Una consulta es un m茅todo GraphQL que nos permite OBTENER datos de nuestra API. Aunque pueda recibir par谩metros para filtrar, ordenar o simplemente buscar un documento en particular, una consulta no puede mutar estos datos.

    Mutaciones

    Mutaciones son todo lo que no es lo que se referir铆a a un verbo GET en las API normales. La actualizaci贸n, creaci贸n o eliminaci贸n de datos de nuestra API se realiza mediante mutaciones.

    Suscripciones

    Con el uso de sockets web, una suscripci贸n se refiere a una conexi贸n entre el cliente y el servidor.

    El servidor est谩 constantemente atento a las mutaciones o consultas que se adjuntan a una suscripci贸n en particular y comunica cualquier cambio al cliente en tiempo real. Las suscripciones se utilizan principalmente para widgets / aplicaciones en tiempo real.

    Tipos y entradas

    Para asegurarnos de que nuestras consultas y mutaciones puedan procesar los datos para consultar una base de datos, types funciona de forma muy similar a un modelo ORM para bases de datos. Configurando tipos arriba podemos definir el tipo de variable que devolver谩n nuestros resolutores.

    De manera similar, necesitamos establecer tipos de entrada para que reciban nuestros resolutores.

    Por ejemplo, definiremos un par types y inputs:

    type User {
      id: ID
      name: String!
      age: Int!
      address: Address
      followers: [ID]
    }
    
    type Address {
      street: String
      city: String
      country: String
    }
    
    input UserInput {
      name: String!
      age: Int!
    }
    
    type Query {
      getAllUsers: [User]
    }
    
    type Mutation {
      createUser(user: UserInput!): ID
    }
    

    Las propiedades pueden tener un tipo personalizado como su tipo adem谩s de los primitivos, como:

    • String
    • En t
    • Flotador
    • Booleano
    • CARN脡 DE IDENTIDAD

    Y tambi茅n pueden ser una matriz de cierto tipo determinado por los corchetes, que se muestra en el ejemplo anterior.

    Adem谩s, el estado obligatorio de una propiedad se puede establecer con el !, lo que significa que la propiedad debe estar presente.

    Resolvers

    Estas son las acciones que se realizan al llamar a consultas y mutaciones.

    getAllUsers y createUser se conectar谩n a un resolutor que realizar谩 los c谩lculos reales y las consultas a la base de datos.

    Creando nuestro Proyecto

    Para este tutorial, crearemos un proyecto Vue.js usando el Vue CLI 3.0, que arrancar谩 un proyecto con una estructura de carpetas similar a esta:

    Si necesita ayuda para configurar el proyecto, puede consultar este tutorial para la interfaz de l铆nea de comandos.

    Podemos empezar a servir nuestra aplicaci贸n con el comando:

    $ npm run serve
    

    Cliente Apollo

    Cliente Apollo trae una herramienta para el desarrollo front-end para facilitar las consultas / mutaciones GraphQL. Act煤a como un cliente HTTP que se conecta a una API GraphQL y proporciona almacenamiento en cach茅, manejo de errores e incluso capacidades de administraci贸n de estado.

    Para este tutorial, Vue-Apollo se utilizar谩, que es la integraci贸n de Apollo especialmente dise帽ada para Vue.js.

    Configuraci贸n de Apolo

    Para iniciar nuestra configuraci贸n de Apollo, ser谩 necesario instalar algunos paquetes:

    $ npm install apollo-client apollo-link-http apollo-cache-inmemory vue-apollo graphql graphql-tag
    

    Dentro de una /graphql carpeta en nuestro proyecto, crearemos apollo.js:

    // apollo.js
    
    import Vue from 'vue'
    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({
        uri: process.env.VUE_APP_GRAPHQL_ENDPOINT
    })
    
    // Create the apollo client
    export const apolloClient = new ApolloClient({
        link: httpLink,
        cache: new InMemoryCache(),
        connectToDevTools: true
    })
    
    // Install the Vue plugin
    
    Vue.use(VueApollo)
    
    export const apolloProvider = new VueApollo({
        defaultClient: apolloClient
    })
    

    HttpLink es un objeto que requiere un uri propiedad, que se refiere al punto final GraphQL de la API que se est谩 utilizando. Ex: localhost:8081/graphql

    Entonces, un nuevo ApolloClient Se necesita crear una instancia, donde se pueden establecer el enlace, la instancia de cach茅 y otras opciones.

    Finalmente, envolvemos nuestro ApolloClient dentro de una VueApollo instancia para que podamos usar sus ganchos dentro de nuestros componentes Vue.

    Manejo de errores globales

    Hay una forma de manejar los errores globalmente dentro del archivo de configuraci贸n. Para eso necesitamos instalar un paquete npm llamado apollo-link-error, que inspecciona y gestiona errores de la red:

    // apollo.js
    
    import Vue from 'vue'
    import { ApolloClient } from 'apollo-client'
    import { HttpLink } from 'apollo-link-http'
    import { onError } from "apollo-link-error"
    import { InMemoryCache } from 'apollo-cache-inmemory'
    import VueApollo from 'vue-apollo'
    
    const httpLink = new HttpLink({
        uri: process.env.VUE_APP_GRAPHQL_ENDPOINT
    })
    
    // Error Handling
    const errorLink = onError(({ graphQLErrors, networkError }) => {
        if (graphQLErrors)
            graphQLErrors.map(({ message, locations, path }) =>
                console.log(
                    `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
                )
            )
        if (networkError) console.log(`[Network error]: ${networkError}`)
    })
    
    // Create the apollo client
    export const apolloClient = new ApolloClient({
        link: errorLink.concat(httpLink),
        cache: new InMemoryCache(),
        connectToDevTools: true
    })
    
    // Install the Vue plugin
    Vue.use(VueApollo)
    
    export const apolloProvider = new VueApollo({
        defaultClient: apolloClient
    })
    

    Despu茅s de importar el onError funci贸n del paquete, podemos implementarlo como una especie de middleware de Apollo Client. Detectar谩 cualquier error de red o GraphQL, d谩ndonos la oportunidad de gestionarlos globalmente.

    La devoluci贸n de llamada se llama con un objeto con algunas propiedades cada vez que ocurre un error:

    • operaci贸n: La operaci贸n que desencaden贸 la devoluci贸n de llamada porque se encontr贸 un error.
    • respuesta: El resultado de la operaci贸n.
    • graphQLErrors: Una matriz de errores del punto final GraphQL
    • error de red: Cualquier error durante la ejecuci贸n de la operaci贸n o error del servidor.
    • adelante: El siguiente eslab贸n al que se hace referencia en la cadena.

    Administrar el estado con el cliente Apollo

    Una alternativa diferente al uso Vuex con proyectos de Vue, y cuando se usa Apollo Client es usar un paquete llamado apollo-link-state.

    Funciona como una herramienta de gesti贸n de datos local que funciona como si estuviera consultando a un servidor, pero lo hace localmente.

    Adem谩s, es una excelente manera de administrar el cach茅 de nuestra aplicaci贸n, lo que convierte a Apollo Client en un cliente HTTP y una herramienta de administraci贸n de estado / cach茅.

    Para m谩s informaci贸n, puede consultar la documentaci贸n oficial de Apollo-link-state.

    Crear consultas

    Para crear consultas, necesitamos configurar una etiqueta de tipo cadena con el paquete Graphql-tag. Para mantener un proyecto ordenado y estructurado, crearemos una carpeta llamada queries dentro de la carpeta graphql.

    Suponiendo que el servidor que recibe la consulta est谩 configurado correctamente para interpretar esta consulta, por ejemplo, podemos activar un resolutor llamado getAllUsers:

    import gql from 'graphql-tag'
    
    export const GET_ALL_USERS_QUERY = gql`
      query getAllUsers {
        getAllUsers {
          // Fields to retrieve
          name
          age
        }
      }
    `
    

    La operaci贸n predeterminada en GraphQL es query, entonces el query la palabra clave es opcional.

    Si un campo recuperado tiene subcampos, al menos uno de ellos debe buscarse para que la consulta sea exitosa.

    Usando mutaciones

    Al igual que las consultas, tambi茅n podemos utilizar mutaciones creando un gql-string.

    import gql from 'graphql-tag'
    
    export const CREATE_USER_MUTATION = gql`
      mutation createUser($user: UserInput!) {
        createUser(user: $user)
      }
    `
    

    Nuestro createUser mutaci贸n espera un UserInput input y, para poder utilizar los par谩metros pasados 鈥嬧媝or Apollo. Primero definiremos una variable con el $ llamado user. Luego, la envoltura exterior pasar谩 la variable a la createUser mutaci贸n, como esperaba el servidor.

    Fragmentos

    Para mantener nuestro gql-type cadenas ordenadas y legibles, podemos usar fragmentos para reutilizar la l贸gica de consulta.

    fragment UserFragment on User {
      name: String!
      age: Int!
    }
    
    query getAllUsers {
      getAllUsers {
        ...UserFragment
      }
    }
    

    Usando GraphQL en componentes de Vue

    Dentro de main.js archivo, para configurar el cliente Apollo, necesitamos importar y adjuntar el cliente a nuestra instancia.

    // main.js
    import Vue from 'vue'
    import { apolloProvider } from './graphql/apollo'
    
    Vue.config.productionTip = false
    
    /* eslint-disable no-new */
    new Vue({
        el: '#app',
        apolloProvider,
        render: h => h(App)
    })
    

    Desde que hemos agregado nuestro ApolloProvider a la instancia de Vue, podemos acceder al cliente a trav茅s del $apollo palabra clave:

    // GraphQLTest.vue
    <template>
        <div class="graphql-test">
            <h2 v-if="loading">Loading...</h2>
            <h4 v-if="!loading">{{ getAllUsers }}</h4>
        </div>
    </template>
    
    <script>
    import { GET_ALL_USERS_QUERY } from '../graphl/queries/userQueries'
    export default {
        name: 'GraphQLTest',
        data () {
            return {
                users: []
            }
        },
        async mounted () {
            this.loading = true
            this.users = await this.$apollo.query({ query: GET_ALL_USERS_QUERY })
            this.loading = false
        }
    }
    </script>
    

    Si queremos crear un usuario, podemos usar un mutation:

    // GraphQLTest.vue
    <template>
        <div class="graphql-test">
            <input v-model="user.name" type="text" placeholder="Name" />
            <input v-model="user.age" placeholder="Age" />
            <button @click="createUser">Create User</button>
        </div>
    </template>
    
    <script>
    import { CREATE_USER_MUTATION } from '../graphl/queries/userQueries'
    export default {
        name: 'GraphQLTest',
        data() {
            return {
                user: {
                    name: null,
                    age: null
                }
            }
        },
        methods: {
            async createUser () {
                const userCreated = await this.$apollo.mutate({
                    mutation: CREATE_USER_MUTATION,
                    variables: {
                        user: this.user // this should be the same name as the one the server is expecting
                    }
                })
                // We log the created user ID
                console.log(userCreated.data.createUser)
            }
        }
    }
    </script>
    

    El uso de este enfoque nos permite microgestionar cu谩ndo y d贸nde se ejecutar谩n nuestras mutaciones y consultas. Ahora veremos algunas otras formas de manejar estos m茅todos que nos brinda Vue Apollo.

    El objeto Apolo

    Dentro de nuestros componentes de Vue, tenemos acceso a la Apollo objeto, que se puede utilizar para gestionar f谩cilmente nuestras consultas y suscripciones:

    <template>
        <div class="graphql-test">
            {{ getAllUsers }}
        </div>
    </template>
    
    <script>
    import { GET_ALL_USERS_QUERY } from '../graphl/queries/userQueries'
    export default {
        name: 'GraphQL-Test',
        apollo: {
            getAllUsers: {
                query: GET_ALL_USERS_QUERY
            }
        }
    }
    </script>
    

    Recuperaci贸n de consultas

    Al definir una consulta dentro del objeto Apollo, es posible volver a buscar esta consulta al llamar a una mutaci贸n u otra consulta con el refetch m茅todo o el refetchQueries propiedad:

    <template>
        <div class="graphql-test">
            {{ getAllUsers }}
        </div>
    </template>
    
    <script>
    import { GET_ALL_USERS_QUERY, CREATE_USER_MUTATION } from '../graphl/queries/userQueries'
    export default {
        name: 'GraphQL-Test',
        apollo: {
            getAllUsers: {
                query: GET_ALL_USERS_QUERY
            }
        },
        methods: {
            refetch () {
                this.$apollo.queries.getAllUsers.refetch()
            },
            queryUsers () {
                const user = { name: Lucas, age: 26 }
                this.$apollo.mutate({
                    mutation: CREATE_USER_MUTATION,
                    variables: {
                        user
                    }
                    refetchQueries: [
                        { query: GET_ALL_USERS_QUERY }
                    ]
                })
            }
        }
    }
    </script>
    

    Usando el Apollo , que nos proporcion贸 Vue-Apollo, ya no necesitamos utilizar activamente la forma del cliente Apollo de activar consultas / suscripciones y algunas propiedades y opciones 煤tiles est谩n disponibles para nosotros.

    Propiedades del objeto Apollo

    • consulta: Este es el gql escriba una cadena que haga referencia a la consulta que desea que se active.
    • variables: Un objeto que acepta los par谩metros que se pasan a una consulta determinada.
    • fetchPolicy: Una propiedad que establece la forma en que la consulta interactuar谩 con la cach茅. Las opciones son cache-and-network, network-only, cache-only, no-cache, standby y el valor predeterminado es cache-first.
    • intervalo de encuesta: Tiempo en milisegundos que determina la frecuencia con la que se activar谩 autom谩ticamente una consulta.

    Opciones especiales

    • $ error para detectar errores en un manejador de conjuntos.
    • $ profundo observa profundamente los cambios en una consulta.
    • $ omitir: desactiva todas las consultas y suscripciones en un componente determinado.
    • $ skipAllQueries: desactiva todas las consultas de un componente.
    • $ skipAllSubscriptions: para deshabilita todas las suscripciones en un componente.

    Componentes Apollo

    Inspirado en la forma en que se implementa el cliente Apollo para Reaccionar (React-Apollo), Vue-Apollo nos proporciona algunos componentes que podemos usar listos para usar para administrar la interfaz de usuario y el estado de nuestras consultas y mutaciones con un componente de Vue dentro de la plantilla.

    ApolloQuery

    Forma m谩s sencilla de gestionar nuestras consultas de forma m谩s intuitiva:

    <ApolloQuery
      :query="GET_ALL_USERS_QUERY"
    >
        <template slot-scope="{ result: { loading, error, data } }">
            <!-- Loading -->
            <div v-if="loading">Query is loading.</div>
    
            <!-- Error -->
            <div v-else-if="error">We got an error!</div>
    
            <!-- Result -->
            <div v-else-if="data">{{ data.getAllUsers }}</div>
    
            <!-- No result (if the query succeed but there's no data) -->
            <div v-else>No result from the server</div>
        </template>
    </ApolloQuery>
    

    ApoloMutaci贸n

    Muy similar al ejemplo anterior, pero debemos desencadenar la mutaci贸n con el mutate Llamada de funci贸n:

    <ApolloMutation
      :mutation="CREATE_USER_MUTATION"
      :variables="{
        name,
        age
      }"
      @done="mutationFinished"
    >
        <template slot-scope="{ mutate, loading, error }">
            <!-- Loading -->
            <h4 v-if="loading">The mutation is loading!</h4>
    
            <!-- Mutation Trigger -->
            <button @click="mutate()">Create User</button>
    
            <!-- Error -->
            <p v-if="error">An error has occurred!</p>
        </template>
    </ApolloMutation>
    

    Conclusi贸n

    GraphQL aporta mucha flexibilidad al desarrollo de API, desde el rendimiento, la facilidad de uso y una perspectiva general diferente de c贸mo deber铆a verse y comportarse una API. Adem谩s, ApolloClient y Vue Apollo ofrecen un conjunto de herramientas para una mejor administraci贸n de nuestra interfaz de usuario, estado y operaciones, 隆incluso manejo de errores y cach茅!

    Para obtener m谩s informaci贸n sobre GraphQL y Apollo Client, puede visitar lo siguiente:

     

    Etiquetas:

    Deja una respuesta

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