Consumindo uma API GraphQL com SWR
Tags: swr, graphql, api, hook
Published: 2021-02-11 15:03:57

SWR nos disponibiliza React Hooks para realizar requisições, com a estratégia de stale-while-revalidate de forma padrão. SWR consiste em a primeira vista, temos os dados do *cache* (stale) e enquanto isso,uma requisição é enviada (revalidate) para validar esse cache, e por fim, se houver alguma mudança, os dados são atualizados.

Sugiro a leitura das principais funcionalidades do SWR

[SWR: React Hooks for Data Fetching](https://swr.vercel.app/#features)

Sem mais enrolação, bora pro código!

&nbsp;

Primeiro de tudo, vamos iniciar o nosso projeto e instalar o SWR

Vou utiilizar um template com Typescript

```bash
yarn create react-app swr-basics --template typescript
```

Após o setup, vamos adcionar o SWR

```bash
yarn add swr
```

Para todas as requisições que vamos utilizar o SWR, vamos precisar de uma fetcher function, que será uma função assíncrona que simplesmente retorna os dados. Para isso podemos utilizar tanto a API de *[fetch](https://developer.mozilla.org/pt-BR/docs/Web/API/Fetch_API)* do próprio javascript, ou bibliotecas como *[axios](https://github.com/axios/axios).* E para enviarmos requisições a APIs GraphQL, vamos precisar utilizar algum GraphQL Client

E nesse caso vamos usar o [graphql-request](https://github.com/prisma-labs/graphql-request)

```bash
yarn add graphql-request graphql
```

Além de todas essas libs, vamos precisar de alguma API GraphQL, para enviar nossas queries. Sendo assim, vamos utilizar uma API incrível da SpaceX

[GraphiQL Explorer](https://api.spacex.land/graphql/)

Para começar, vamos enviar uma query buscando por foguetes 🚀

```graphql
{
  rockets {
    active
    name
    mass {
      kg
    }
    description
  }
}
```

Para isso, vamos criar o nosso componente que vai realizar a requisição e mostrar na tela os dados dos foguetes

Rockets.tsx

```tsx
import { FunctionComponent } from "react";

const Rockets: FunctionComponent = () => {
  return (
    <div>
      <span>Rockets will land here</span>
    </div>
  );
};

export default Rockets;
```

E nosso App.tsx vai ficar assim:

```tsx
import "./app.css";
import Rockets from "./components/Rockets";

const App = () => {
  return (
    <div className="App">
      <Rockets />
    </div>
  );
};

export default App;
```

Certo, agora pra que tudo funcione, vamos criar um arquivo com uma configuração básica do nosso GraphQL Client, onde vamos inserir a rota para a API da SpaceX

Também é possível adicionarmos outras opções, como headers, credentials, e etc...

graphqlClient.ts

```tsx
import { GraphQLClient } from "graphql-request";

export const graphqlClient = new GraphQLClient(
  "https://api.spacex.land/graphql/"
);
```

Com nosso cliente GraphQL, vamos começar enviando a nossa query

Para isso vamos criar a nossa fetcher function

Rockets.tsx

```tsx
import { FunctionComponent } from "react";
import { RequestDocument } from "graphql-request/dist/types";
import { graphqlClient } from "../graphql/graphqClient";

const Rockets: FunctionComponent = () => {

  const fetcher = (query: RequestDocument) => graphqlClient.request(query)
  
  return (
    <div>
      <span>Rockets will land here</span>
    </div>
  );
};

export default Rockets;
```

E esse RequestDocument será a nossa query que vamos enviar para buscar os foguetes

Podemos escreve-la assim:

```tsx
const rocketsQuery = `
    {
      rockets {
        active
        name
        mass {
          kg
        }
        description
      }
    }
  `
```

E tudo que precisamos fazer é passar ela para o hook useSWR, juntamente com a nossa função fetcher

E desse hook podemos obter data e error

```tsx
const { data, error } = useSWR(rocketsQuery, fetcher)
```

E podemos mostrar na tela se existir algum dado:

```tsx
if (data) {
    return (
      <div>
        <pre>{JSON.stringify(data, null, 2)}</pre>
      </div>
    );
  }
```

Rockets.tsx

```tsx
import { FunctionComponent } from "react";
import { RequestDocument } from "graphql-request/dist/types";
import { graphqlClient } from "../graphql/graphqClient";
import useSWR from "swr";

const Rockets: FunctionComponent = () => {
  const fetcher = (query: RequestDocument) => graphqlClient.request(query);

  const rocketsQuery = `
    {
      rockets {
        active
        name
        mass {
          kg
        }
        description
      }
    }
  `;

  const { data, error } = useSWR(rocketsQuery, fetcher);

  if (data) {
    return (
      <div>
        <pre>{JSON.stringify(data, null, 2)}</pre>
      </div>
    );
  }

  if (error) {
    return (
      <div>
        <pre>Something went bad :(</pre>
      </div>
    );
  }

  return (
    <div>
      <span>Loading rockets...</span>
    </div>
  );
};

export default Rockets;
```

Se tudo ocorreu bem, teremos um JSON com os foguetes

![Rockets JSON](https://dev-to-uploads.s3.amazonaws.com/i/4qukk81nobz1onzbrpel.png)

Irado! 🤘🏼

&nbsp;

Agora que já pegamos a ideia da coisa, vamos enviar uma mutation para a API, criando um usuário

A mutation vai ser assim:

```tsx
mutation {
  insert_users(objects: {name: "Vinicius", rocket: "El Jalapeño Rocket"}) {
    returning {
      id
      name
      rocket
    }
  }
}
```

E a query para buscar os usuáros

```tsx
{
  users {
    id
    name
    rocket
  }
}
```

Então bora começar criando um componente para listar os usuários

E assim como nossa query de foguetes, vamos criar nossa fetcher function, adicionar nossa query de usuários, e por fim, nosso hook useSWR

Users.tsx

```tsx
import { FunctionComponent } from "react";
import { RequestDocument } from "graphql-request/dist/types";
import { graphqlClient } from "../graphql/graphqClient";
import useSWR from "swr";

const Users: FunctionComponent = () => {
  const fetcher = (query: RequestDocument) => graphqlClient.request(query);

  const usersQuery = `
    {
        users {
	        id
	        name
	        rocket
        }
    }
  
  `;

  const { data, error } = useSWR(usersQuery, fetcher);

 
  ...
  
};

export default Users;
```

Agora vamos colocar na tela os usuários, e enquanto eles não aparecem, podemos mostrar um "Loading..." na tela

Users.tsx

```tsx
if (data) {
    return (
      <div>
        <div>
          <pre>{JSON.stringify(data, null, 2)}</pre>
        </div>
      </div>
    );
  }

  if (error) {
    return <div>Something went bad!</div>;
  }

  return (
    <div>
      <span>Loading Users...</span>
    </div>
  );
```

Então, temos um JSON com os usuários

![Users JSON](https://dev-to-uploads.s3.amazonaws.com/i/i3ye3se0grjloysxy522.png)

Nice! 🤘🏼

&nbsp;

Por fim, vamos criar um formulário para adicionar um novo usuário, e ver se ele aparece na nossa lista de usuários

UserForm.tsx

```tsx
import { FormEvent, FunctionComponent, useState } from "react";

const UserForm: FunctionComponent = () => {
  const [username, setUsername] = useState<string>("");
  const [rocketName, setRocketName] = useState<string>("");

  const handleCreateuser = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    console.log({username, rocketName})
  };

  return (
    <form onSubmit={(event) => handleCreateuser(event)}>
      <input
        type="text"
        placeholder="username"
        value={username}
        onChange={(event) => setUsername(event.target.value)}
      />
      <input
        type="text"
        placeholder="rocket name"
        value={rocketName}
        onChange={(event) => setRocketName(event.target.value)}
      />
      <button>Create User</button>
    </form>
  );
};

export default UserForm;
```

Por enquanto, nosso componente está apenas fazendo um log com os valores dos inputs

Agora precisamos criar uma mutation, passando esses valores

Essa é a mutation para inserir usuários

```graphql
mutation insertUsers($name: String!, $rocket: String!){
            insert_users(objects: {name: $name, rocket: $rocket}) {
                returning {
                    id
                    name
                    rocket
                }
            }
        }
```

E agora junto com a mutation, utlizando o graphql-request, vamos passar as variáveis que vamos criar o usuário

UserForm.tsx

```tsx
const [username, setUsername] = useState<string>("");
const [rocketName, setRocketName] = useState<string>("");

const createUserMutation = `
        mutation insertUsers($name: String!, $rocket: String!){
            insert_users(objects: {name: $name, rocket: $rocket}) {
                returning {
                    id
                    name
                    rocket
               }
           }
      }
 `;

const handleCreateuser = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    const response = await graphqlClient.request(createUserMutation, {
      name: username,
      rocket: rocketName,
    });

    console.log(response);
  };
```
Agora assim que enviarmos a nossa mutation, nossa query de users vai notar que houve uma mudança, e irá revalidar os dados, carregando o nosso novo usuário na tela.

Então o resultado final será esse:


UserForm.tsx

```tsx

import { FormEvent, FunctionComponent, useState } from "react";
import { graphqlClient } from "../graphql/graphqClient";

const UserForm: FunctionComponent = () => {
  const [username, setUsername] = useState<string>("");
  const [rocketName, setRocketName] = useState<string>("");

  const createUserMutation = `
        mutation insertUsers($name: String!, $rocket: String!){
            insert_users(objects: {name: $name, rocket: $rocket}) {
                returning {
                    id
                    name
                    rocket
                }
            }
        }
    `;

  const handleCreateuser = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    const response = await graphqlClient.request(createUserMutation, {
      name: username,
      rocket: rocketName,
    });

    console.log(response);
  };

  return (
    <form onSubmit={(event) => handleCreateuser(event)}>
      <input
        type="text"
        placeholder="username"
        value={username}
        onChange={(event) => setUsername(event.target.value)}
      />
      <input
        type="text"
        placeholder="rocket name"
        value={rocketName}
        onChange={(event) => setRocketName(event.target.value)}
      />
      <button>Create User</button>
    </form>
  );
};

export default UserForm;

 
```

E podemos fazer um teste:

E após enviarmos o formulário, a nossa query de users vai revalidar a requisição e assim que tiver algum novo usuário, vamos ter a atualização na tela.

![Users JSON with created User](https://dev-to-uploads.s3.amazonaws.com/i/85zaotyrsmpbo2vb1tcs.png)

Incrível! 🔥

Espero que agora as requisições para APIs GraphQL utilizando SWR tenha ficado mais claro. E caso precise de alguma ajuda, mande uma mensagem 👍🏼

&nbsp;

Se esse post foi útil, e te ajudou de alguma maneira, deixe uma reação e me siga nas redes.

[vinisaveg - Github](https://github.com/vinisaveg)

[Vinicius Savegnago - LinkedIn](https://www.linkedin.com/in/vinicius-savegnago-95b438179/)

&nbsp;

Happy Coding!

Links úteis:

[vinisaveg/swr-basics](https://github.com/vinisaveg/swr-basics)

[SWR: React Hooks for Data Fetching](https://swr.vercel.app)

[prisma-labs/graphql-request](https://github.com/prisma-labs/graphql-request)