Criando uma página pessoal com a API do dev.to e VueJS

stsmuniz

Salustiano Muniz

Posted on September 2, 2022

Criando uma página pessoal com a API do dev.to e VueJS

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.

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.

DEV API (beta) | Forem Docs

Access Forem articles, users and other resources via API. For a real-world example of Forem in action, check out [DEV](https://www.dev.to). All endpoints that don't require authentication are CORS enabled. All requests must send a user-agent header. Dates and date times, unless otherwise specified, must be in the [RFC 3339](https://tools.ietf.org/html/rfc3339) format.

favicon developers.forem.com

E com isso, cheguei nos 2 endpoints que precisava:

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

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;
Enter fullscreen mode Exit fullscreen mode

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

O service pra receber artigos:

import http from "@/http";

export const getArticles = () => http.get('articles', {
    params: {
        username: 'stsmuniz'
    }
})
Enter fullscreen mode Exit fullscreen mode

E o service para receber o perfil

import http from "@/http";

export const getProfile = () => http.get('users/by_username', {
    params: {
        url: 'stsmuniz'
    }
})
Enter fullscreen mode Exit fullscreen mode

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.

  setup() {
    const profile = ref()

    onBeforeMount(() => {
      getProfile()
          .then(res => profile.value = res.data)
    })
    ....
    return {
        profile
    }
})
Enter fullscreen mode Exit fullscreen mode

E na página vai o componente que "monta" o perfil

    <ProfileComponent profile="profile" v-if="profile"/>
    <i class="fa-solid fa-spinner fa-spin-pulse" v-else></i>
Enter fullscreen mode Exit fullscreen mode

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

<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>
Enter fullscreen mode Exit fullscreen mode

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

<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>
Enter fullscreen mode Exit fullscreen mode

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

<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>
Enter fullscreen mode Exit fullscreen mode

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

<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>
Enter fullscreen mode Exit fullscreen mode

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:

Automatically build and deploy a Vue.js app with GitHub Pages - LogRocket Blog

Learn how to automatically build and deploy a Vue.js project to GitHub Pages, a static site hosting service for your GitHub projects.

favicon blog.logrocket.com

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

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

💖 💪 🙅 🚩
stsmuniz
Salustiano Muniz

Posted on September 2, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related