Vytváření rozhraní API GraphQL pomocí Vue.js a Apollo Client

Úvod

GraphQL je grafově orientovaný dotazovací jazyk napsaný Facebookem. Na rozdíl od REST API zavádí GraphQL funkce, které zefektivňují vývoj API a jsou v souladu s databázovými modely.

Funkce GraphQL

  • Na rozdíl od REST , existuje pouze jeden koncový bod, kam se budou odesílat všechny požadavky. Takže místo dotazování /users pro získání seznamu uživatelů nebo /user/:id pro získání konkrétního uživatele bude koncový bod vypadat jako /graphql pro všechny požadavky.
  • V GraphQL jsou data přicházející z odpovědi nastavena uvedenou knihovnou dotazů a lze ji nastavit tak, aby posílala pouze několik vlastností dat, takže dotazy v GraphQL mají lepší výkon.
  • V GraphQL není třeba nastavovat slovesa metody. Klíčová slova jako Dotaz nebo Mutace rozhodne, co bude žádost provádět.
  • Trasy REST API jsou obvykle zpracovávány jedním obslužným programem trasy. V GraphQL můžete mít jeden dotaz spouštějící více mutací a získat složenou odpověď z více zdrojů.

Dotazy

Dotaz je metoda GraphQL, která nám umožňuje ZÍSKAT data z našeho API. I když může přijímat parametry pro filtrování, objednávání nebo jednoduše vyhledávání konkrétního dokumentu, dotaz nemůže tato data změnit.

Mutace

Mutace jsou všechno, co není co by odkazovalo na sloveso GET v běžných API. Aktualizace, vytváření nebo mazání dat z našeho API se provádí pomocí mutací

Předplatné

Při použití webových soketů se předplatné vztahuje na spojení mezi klientem a serverem.

Server neustále sleduje mutace nebo dotazy, které jsou připojeny ke konkrétnímu předplatnému, a sděluje klientovi jakékoli změny v reálném čase. Předplatná se většinou používají pro widgety/aplikace v reálném čase.

Typy a vstupy

Abychom se ujistili, že naše dotazy a mutace dokážou zpracovat data pro dotazování v databázi, types fungují podobně jako model ORM pro databáze. Nastavením typů nahoru můžeme definovat typ proměnné, kterou naše resolvery vrátí.

Podobně musíme nastavit typy vstupů, které mají naše resolvery přijímat.

Například definujeme pár types a 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
}

Vlastnosti mohou mít vlastní typ kromě primitivních, jako například:

  • Řetězec
  • Int
  • Plovoucí
  • Boolovská hodnota
  • ID

A mohou to být také pole určitého typu určeného závorkami, což je znázorněno v příkladu výše.

Kromě toho lze povinný stav vlastnosti nastavit pomocí ! , což znamená, že vlastnost musí být přítomna.

Řešitele

Toto jsou akce, které se provádějí při volání dotazů a mutací.

getAllUsers a createUser budou připojeny k resolveru, který bude provádět skutečné výpočty a databázové dotazy.

Vytváření našeho projektu

Pro tento tutoriál vytvoříme projekt Vue.js pomocí Vue CLI 3.0 , který zavede projekt se strukturou složek, která vypadá takto:

Pokud potřebujete pomoc s nastavením projektu, můžete se podívat na tento tutoriál pro rozhraní příkazového řádku.

Naši aplikaci můžeme začít obsluhovat příkazem:

$ npm run serve

Klient Apollo

Apollo Client přináší nástroj pro vývoj front-endu, který usnadňuje GraphQL dotazy/mutace. Funguje jako klient HTTP, který se připojuje k rozhraní GraphQL API a poskytuje možnosti ukládání do mezipaměti, zpracování chyb a dokonce i správy stavu.

Pro tento tutoriál bude použit Vue-Apollo, což je integrace Apollo speciálně navržená pro Vue.js.

Konfigurace Apollo

Pro spuštění konfigurace Apollo bude potřeba nainstalovat několik balíčků:

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

Uvnitř /graphql složku v našem projektu, vytvoříme 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 je objekt, který vyžaduje uri vlastnost, která odkazuje na koncový bod GraphQL z používaného API. Příklad:localhost:8081/graphql

Poté nový ApolloClient je třeba vytvořit instanci, kde lze nastavit odkaz, instanci mezipaměti a další možnosti.

Nakonec zabalíme naše ApolloClient uvnitř VueApollo instance, abychom mohli použít její háčky uvnitř našich komponent Vue.

Globální zpracování chyb

V konfiguračním souboru existuje způsob, jak globálně zpracovat chyby. K tomu potřebujeme nainstalovat balíček npm s názvem apollo-link-error , který kontroluje a spravuje chyby ze sítě:

// 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
})

Po importu onError funkce z balíčku, můžeme ji implementovat jako jakýsi middleware klienta Apollo. Zachytí všechny chyby sítě nebo GraphQL, což nám dává možnost je spravovat globálně.

Zpětné volání je voláno s objektem s některými vlastnostmi, kdykoli dojde k chybě:

  • provoz :Operace, která spustila zpětné volání, protože byla nalezena chyba.
  • odpověď :Výsledek operace.
  • graphQLErrors :Pole chyb z koncového bodu GraphQL
  • chyba sítě :Jakákoli chyba během provádění operace nebo chyba serveru.
  • vpřed :Další odkaz v řetězci.

Správa stavu pomocí klienta Apollo

Jinou alternativou k používání Vuex s projekty Vue a při použití klienta Apollo je použití balíčku s názvem apollo-link-state .

Funguje jako místní nástroj pro správu dat, který funguje, jako byste se dotazovali na server, ale dělá to lokálně.

Zdarma e-kniha:Git Essentials

Prohlédněte si našeho praktického průvodce učením Git s osvědčenými postupy, průmyslově uznávanými standardy a přiloženým cheat sheetem. Přestaňte používat příkazy Google Git a skutečně se naučte to!

Je to také skvělý způsob správy mezipaměti pro naši aplikaci, čímž se Apollo Client stává klientem HTTP a nástrojem pro správu stavu/mezipaměti.

Další informace najdete v oficiální dokumentaci pro Apollo-link-state.

Vytváření dotazů

Pro vytváření dotazů potřebujeme nastavit tag typu string s balíčkem graphql-tag . Pro udržení pořádku a strukturovaného projektu vytvoříme složku s názvem queries uvnitř složky graphql.

Za předpokladu, že server přijímající dotaz je správně nastaven tak, aby tento dotaz interpretoval, můžeme například spustit překladač nazvaný getAllUsers :

import gql from 'graphql-tag'

export const GET_ALL_USERS_QUERY = gql`
  query getAllUsers {
    getAllUsers {
      // Fields to retrieve
      name
      age
    }
  }
`

Výchozí operace v GraphQL je query , tedy query klíčové slovo je nepovinné.

Pokud má načtené pole podpole, mělo by být načteno alespoň jedno z nich, aby byl dotaz úspěšný.

Použití mutací

Podobně jako u dotazů můžeme také použít mutace vytvořením gql-string .

import gql from 'graphql-tag'

export const CREATE_USER_MUTATION = gql`
  mutation createUser($user: UserInput!) {
    createUser(user: $user)
  }
`

Naše createUser mutace očekává UserInput vstup a, aby bylo možné používat parametry předané Apollo. Nejprve definujeme proměnnou s $ s názvem user . Potom vnější obal předá proměnnou do createUser mutace, jak očekává server.

Fragmenty

Abychom zachovali naše gql-type řetězce čisté a čitelné, můžeme použít fragmenty znovu použít logiku dotazu.

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

query getAllUsers {
  getAllUsers {
    ...UserFragment
  }
}

Použití GraphQL v komponentách Vue

Uvnitř main.js Abychom nakonfigurovali klienta Apollo, musíme klienta importovat a připojit k naší instanci.

// 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)
})

Protože jsme přidali našeho ApolloProvider k instanci Vue, můžeme přistupovat ke klientovi prostřednictvím $apollo klíčové slovo:

// GraphQLTest.vue
<template>
    <div class="graphql-test">
        <h3 v-if="loading">Loading...</h3>
        <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>

Pokud chceme vytvořit uživatele, můžeme použít 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>

Použití tohoto přístupu nám umožňuje mikro-řídit, kdy a kde se naše mutace a dotazy provedou. Nyní uvidíme některé další způsoby zacházení s těmito metodami, které nám nabízí Vue Apollo.

Objekt Apollo

Uvnitř našich komponent Vue získáváme přístup k Apollo objekt, který lze použít ke snadné správě našich dotazů a odběrů:

<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>
Obnovení dotazů

Při definování dotazu uvnitř objektu Apollo je možné refetch tento dotaz při volání mutace nebo jiného dotazu s refetch nebo refetchQueries vlastnost:

<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>

Pomocí Apollo objekt, který nám poskytla společnost Vue-Apollo , již nepotřebujeme aktivně používat způsob spouštění dotazů/předplatných pomocí klienta Apollo a zpřístupní se nám některé užitečné vlastnosti a možnosti.

Vlastnosti objektu Apollo
  • dotaz :Toto je gql zadejte řetězec odkazující na dotaz, který chce být spuštěn.
  • proměnné :Objekt, který přijímá parametry předávané danému dotazu.
  • fetchPolicy :Vlastnost, která nastavuje způsob interakce dotazu s mezipamětí. Možnosti jsou cache-and-network , network-only , cache-only , no-cache , standby a výchozí je cache-first .
  • pollInterval :Čas v milisekundách, který určuje, jak často se dotaz automaticky spustí.
Speciální možnosti
  • $error k zachycení chyb v obslužném programu sady.
  • $deep hluboce sleduje změny v dotazu.
  • $skip :zakáže všechny dotazy a odběry v dané komponentě.
  • $skipAllQueries :zakáže všechny dotazy z komponenty.
  • $skipAllSubscriptions :zakáže všechny odběry v komponentě.

Komponenty Apollo

Inspirováno tím, jak je Apollo Client implementován pro React (React-Apollo), nám Vue-Apollo poskytuje několik komponent, které můžeme hned po vybalení použít ke správě uživatelského rozhraní a stavu našich dotazů a mutací s komponentou Vue uvnitř. šablony.

ApolloQuery

Jednodušší způsob správy našich dotazů intuitivnějším způsobem:

<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>
ApolloMutation

Velmi podobné výše uvedenému příkladu, ale mutaci musíme spustit pomocí mutate volání funkce:

<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>

Závěr

GraphQL přináší do vývoje API velkou flexibilitu, od výkonu, snadného použití a celkově odlišné perspektivy toho, jak by API mělo vypadat a chovat se. ApolloClient a Vue Apollo navíc poskytují sadu nástrojů pro lepší správu našeho uživatelského rozhraní, stavu a operací, dokonce i zpracování chyb a mezipaměti!

Pro více informací o GraphQL a Apollo Client můžete navštívit následující:

  • Oficiální stránka GraphQL
  • Oficiální stránka klienta Apollo