Introducción
Contenido
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:
Te puede interesar:Funciones de flecha en JavaScript$ 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 por 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 escache-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é!
Te puede interesar:Cómo copiar objetos en JavaScriptPara obtener más información sobre GraphQL y Apollo Client, puede visitar lo siguiente: