Usando Axios para Consumir APIs
Published: 2020-08-17 12:22:03

## Exemplo Base
Há diversos momentos quando você está desenvolvendo uma aplicação Web que podem necessitar consumir e exibir dados de uma API. Há várias maneiras de se fazer isso, mas a maneira mais popular é usando axios, um cliente HTTP baseado em Promises.

Neste exercício, usaremos a API CoinDesk para exibir os preços do Bitcoin, atualizados a cada minuto. Primeiramente, precisamos instalar o axios via npm/yarn, ou através do endereço CDN.

Temos várias maneiras de recuperarmos informações de uma API, mas primeiro é interessante descobrir o formato dos dados, para sabermos o que mostraremos. Para fazer isso, faremos uma requisição para o endpoint da API, para podermos ver os dados. Podemos ver na documentação da API CoinDesk que esta chamada será feita para https://api.coindesk.com/v1/bpi/currentprice.json. Assim, criaremos uma propriedade de dados que eventualmente abrigará nossa informação e, então, recuperaremos os dados e atribuiremos usando o gatilho de ciclo de vida mounted:
```vue
new Vue({
  el: '#app',
  data () {
    return {
      info: null
    }
  },
  mounted () {
    axios
      .get('https://api.coindesk.com/v1/bpi/currentprice.json')
      .then(response => (this.info = response))
  }
})
<div id="app">
  {{ info }}
</div>
```
E o que temos é isso:
```json
{ "data": { "time": { "updated": "Aug 16, 2020 12:43:00 UTC", "updatedISO": "2020-08-16T12:43:00+00:00", "updateduk": "Aug 16, 2020 at 13:43 BST" }, "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org", "chartName": "Bitcoin", "bpi": { "USD": { "code": "USD", "symbol": "&#36;", "rate": "11,791.0518", "description": "United States Dollar", "rate_float": 11791.0518 }, "GBP": { "code": "GBP", "symbol": "&pound;", "rate": "9,010.0851", "description": "British Pound Sterling", "rate_float": 9010.0851 }, "EUR": { "code": "EUR", "symbol": "&euro;", "rate": "9,956.6000", "description": "Euro", "rate_float": 9956.6 } } }, "status": 200, "statusText": "", "headers": { "cache-control": "max-age=15", "content-length": "672", "content-type": "application/javascript", "expires": "Sun, 16 Aug 2020 12:45:07 UTC" }, "config": { "transformRequest": {}, "transformResponse": {}, "timeout": 0, "xsrfCookieName": "XSRF-TOKEN", "xsrfHeaderName": "X-XSRF-TOKEN", "maxContentLength": -1, "headers": { "Accept": "application/json, text/plain, */*" }, "method": "get", "url": "https://api.coindesk.com/v1/bpi/currentprice.json" }, "request": {} }
```
Excelente! Já temos algumas informações. Mas parece um pouco confuso agora. Então, vamos exibir adequadamente a informação desejada e também adicionar algum tratamento de exceção no caso de alguma coisa não funcionar conforme esperado ou levar mais tempo do que esperávamos para recuperar as informações.

### Exemplo do Mundo Real: Trabalhando os Dados
Mostrando o Dado Desejado
É muito comum que as informações que precisaremos estejam internamente na resposta obtida, então teremos que analisar o que acabamos de obter para conseguirmos acessar adequadamente. Neste caso, podemos ver que o preço informado está em response.data.bpi. Se usarmos isso, nossa saída seria a seguinte:
```
axios
  .get('https://api.coindesk.com/v1/bpi/currentprice.json')
  .then(response => (this.info = response.data.bpi))
```
Isso é muito mais fácil para nós exibirmos, então podemos atualizar o HTML para mostrar somente a informação que recebemos. Criaremos um filter para ter certeza que a casa decimal estará no lugar correto.
```html
<div id="app">
  <h1>Preços do Bitcoin</h1>
  <div
    v-for="currency in info"
    class="currency">
    {{ currency.description }}:
    <span class="lighten">
      <span v-html="currency.symbol"></span>{{ currency.rate_float | currencydecimal }}
    </span>
  </div>
</div>
filters: {
  currencydecimal (value) {
    return value.toFixed(2)
  }
},
```
### Lidando com Erros
Às vezes, podemos não receber os dados que precisamos da API. Há vários motivos para que nossa chamada assíncrona possa falhar, seguem alguns exemplos:

### A API está fora do ar.
A requisição foi realizada de forma incorreta.
A API não retornou as informações da maneira que esperávamos.
Ao realizar a requisição, devemos checar todas essas circustâncias, obtendo informações em todos os casos para que possamos lidar com o problema. Em uma chamada axios, fazemos isso usando catch.
```
axios
  .get('https://api.coindesk.com/v1/bpi/currentprice.json')
  .then(response => (this.info = response.data.bpi))
  .catch(error => console.log(error))
```
Assim, saberemos se algo falhou durante a requisição da API. Mas, se o dado está desconfigurado ou a API está fora do ar? Neste caso, o usuário não verá nada. Podemos exibir uma informação de carregamento (um loader) durante a requisição e, em seguida, avisar o usuário se não conseguirmos recuperar os dados.
```vue
new Vue({
  el: '#app',
  data () {
    return {
      info: null,
      loading: true,
      errored: false
    }
  },
  filters: {
    currencydecimal (value) {
      return value.toFixed(2)
    }
  },
  mounted () {
    axios
      .get('https://api.coindesk.com/v1/bpi/currentprice.json')
      .then(response => {
        this.info = response.data.bpi
      })
      .catch(error => {
        console.log(error)
        this.errored = true
      })
      .finally(() => this.loading = false)
  }
})
<div id="app">
  <h1>Preços do Bitcoin</h1>

  <section v-if="errored">
    <p>Pedimos desculpas, não estamos conseguindo recuperar as informações no momento. Por favor, tente novamente mais tarde.</p>
  </section>

  <section v-else>
    <div v-if="loading">Carregando...</div>

    <div
      v-else
      v-for="currency in info"
      class="currency">
      {{ currency.description }}:
      <span class="lighten">
        <span v-html="currency.symbol"></span>{{ currency.rate_float | currencydecimal }}
      </span>
    </div>

  </section>
</div>
```
Você pode clicar no botão reexecutar no exemplo abaixo, para poder ver rapidamente o estado de carregamento, enquanto buscamos os dados da API:

Isso ainda poderia ser melhorado com o uso de componentes para diferentes seções e relatórios de erros mais distintos, dependendo da API que você está usando e da complexidade da sua aplicação.

### Padrões Alternativos
Fetch API
Fetch é uma API poderosa e nativa para requisições. Talvez você já tenha ouvido falar que um dos benefícios dela é que você não precisa carregar um código externo para utilizá-la, o que é verdade! Exceto… que ainda não é totalmente suportada, então você precisará de um polyfill. Existem também algumas armadilhas quando se trabalha com esta API, por isso que atualmente muitos preferem utilizar axios. Isso pode, muito bem, mudar no futuro.

### Considerações Finais
Existem vários caminhos para trabalhar com Vue e axios, além de consumir e mostrar um endpoint de uma API. Você também pode realizar comunicação com Serveless Functions, postar/editar/deletar de uma API que você tenha permissão de escrita, e entre outros casos. Devido à integração direta dessas duas bibliotecas, acabou se tornando uma escolha comum entre os desenvolvedores que precisam integrar clientes HTTP em seu fluxo de trabalho.