Criando uma página pessoal com a API do dev.to e VueJS
Tags: api, vue, typescript
Published: 2022-09-02 05:00:36

Estava há muito tempo querendo fazer uma página pessoal pra usar de portifólio e também como blog de tecnologia, e depois de estudar várias soluções, descobri que o dev.to tem uma API que possibilita a consulta dos dados do usuário assim como seus artigos. Com isso na mão, me animei a fazer uma aplicação em Vue que lesse esses dados

## A API

Inicialmente cheguei neste artigo que demonstrava como consumir a API da plataforma, com exemplo em PHP.

{% embed https://dev.to/nataliedeweerd/how-to-use-the-dev-to-api-5gl3 %}

No artigo, tem um link para um outro que mostra vários endpoints que você pode consultar pra obter os dados que deseja. Pesquisando um pouco mais, cheguei à documentação oficial.

{% embed https://developers.forem.com/api/v0 %}

E com isso, cheguei nos 2 endpoints que precisava:

- [users](https://dev.to/api/users/by_username?url=stsmuniz) 
- [articles](https://dev.to/api/articles?username=stsmuniz)

## Vue

Tendo a API e os endpoints, o próximo passo foi buscar esses dados dentro do site, pra depois exibir do jeito que eu queria.

### Consumindo a API

O primeiro passo foi criar um método pra centralizar as requisições à api, que fiz com axios

```typescript
import axios, {AxiosInstance} from "axios";

 const http: AxiosInstance = axios.create({
    baseURL: "https://dev.to/api/",
    headers: {
        'Accept': "application/json",
        'Content-Type': 'application/json'
    }
})

export default http;
```

Depois disso, criei serviços distindos para fazer a consulta aos endpoints.

O service pra receber artigos:
```typescript
import http from "@/http";

export const getArticles = () => http.get('articles', {
    params: {
        username: 'stsmuniz'
    }
})
```

E o service para receber o perfil
```typescript
import http from "@/http";

export const getProfile = () => http.get('users/by_username', {
    params: {
        url: 'stsmuniz'
    }
})
```
Com os services criados, agora podemos usar no site

###Exibindo o perfil

Antes de mais nada, é necessário fazer a consulta efetivamente. Como usei composition api, usei o método `onBeforeMount` pra buscar os dados antes de renderizar a página.

```typescript
  setup() {
    const profile = ref()

    onBeforeMount(() => {
      getProfile()
          .then(res => profile.value = res.data)
    })
    ....
    return {
        profile
    }
})
```
E na página vai o componente que "monta" o perfil

```typescript
    <ProfileComponent profile="profile" v-if="profile"/>
    <i class="fa-solid fa-spinner fa-spin-pulse" v-else></i>
```

O `ProfileComponent` é o componente que recebe as informações do perfil e "monta" o perfil na tela.

```typescript
<template>
  <div class="profile">
    <img class="profile-picture" :alt="profile.username" :src="profile.profile_image">
    <h1>{{profile.name}}</h1>
    <p class="description" v-html="profile.summary.replace('\n', '<br />')"></p>
    <p><i class="fa-solid fa-location-dot"></i> {{profile.location}}</p>
  </div>
</template>

<script lang="ts">
import {defineComponent} from "vue";

export default defineComponent({
  name: "ProfileComponent",
  props: {
    profile: {
      required: true
    }
  },
})
</script>
```

E com isso conseguimos fazer o perfil ser renderizado na tela. O próximo passo é fazer o mesmo processo para os artigos

###Exibindo os artigos

A primeira coisa aqui é criar a view para exibir os artigos, que chamei aqui de Blog. No setup há a chamada para a API pelo service ArticleService, com o 

```typescript
<template>
  <div class="home" v-if="articles">
    <h1>Blog</h1>
    <ArticleList :articles="articles"/>
  </div>
  <i class="fa-solid fa-spinner fa-spin-pulse" v-else></i>
</template>

<script lang="ts">
import {defineComponent, onMounted, ref} from 'vue';
import {getArticles} from "@/service/ArticleService";

import ArticleList from '@/components/ArticleList.vue';

export default defineComponent({
  name: 'BlogView',
  components: {
    ArticleList,
  },
  setup() {
    const articles = ref()

    onMounted(() => {
      document.title = 'Blog'
    })

    getArticles()
        .then(res => articles.value = res.data)

    return {
      articles
    }
  }
});
</script>
```

O `ArticleList` é um componente container que, basicamente, organiza o container pra lista de artigos

```typescript
<template>
  <div class="container">
    <ArticleItem v-for="article in articles" :article="article" :key="article.id" />
  </div>
</template>

<script>
import {defineComponent} from 'vue';
import ArticleItem from "@/components/ArticleItem";

export default defineComponent({
  name: 'ArticleList',
  components: {ArticleItem},
  props: {
    articles: {
      required: true
    }
  }
});
</script>
```

E por fim, o componente `ArticleItem` organiza as informações no template pra fazer a exibição

```typescript
<template>
  <article>
    <a :href="article.url"
       :title="article.title"
       target="_blank">
      <img class="responsive"
           :src="article.cover_image"
           :alt="article.title" />
    </a>
    <div class="article-data">
      <h1>
        <a :href="article.url"
           :title="article.title"
           target="_blank">
          {{ article.title }}
        </a>
      </h1>
      <p class="article-description">{{article.description}}</p>
      <p class="publish-date">
        <i class="fa-solid fa-calendar"></i> <DateFormatter :date="article.published_at" />
      </p>
    </div>
  </article>
</template>

<script>
import DateFormatter from "./DateFormatter";
import {defineComponent} from "vue";

export default defineComponent({
  name: "ArticleItem",
  components: {DateFormatter},
  props: {
    article: {
      required: true
    }
  }
})
</script>
```

Como eu queria exibir a data no formato `dd/mm/yyyy`, criei o componente `DateFormatter` pra tratar a string que vem no formato ISO.

##Deploy

Dei uma fuçada e acabei encontrando um artigo interessante que explica bem como fazer o deploy:

{% embed https://blog.logrocket.com/automatically-build-deploy-vuejs-app-github-pages/ %}

Se você for usar esse método, tome cuidado com o nome da branch principal no arquivo `gh-pages-deploy.js`. No artigo ela está sendo chamada como `master`.

## Fechando

Com isso, mais a estrutura básica do vue e alguma estilização, pode se ter um site simples com informações básicas vindas do seu perfil do dev.to e uma página com link para seus artigos mais recentes.

Pretendo criar um repositório aberto pra compartilhar o que fiz aqui e deixar fácil pra qualquer pessoa com perfil aqui também ter sua página pessoal, assim como a minha

![Home page da minha página pessoal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6hubgsomnc5zraych2ox.png)

Obrigado por acompanhar até aqui e nos vemos na próxima :wave: