Explorando a API do DEV.to para construir um Blog
Tags: api, i18n, nuxt, programacao
Published: 2024-03-12 19:16:00

Olá, pessoal! Hoje vou compartilhar com vocês como montei uma página de blog utilizando a API do Dev.to. Esta é uma ótima forma de expandir o alcance do seu conteúdo. Além disso escrevo o mesmo post tanto em português quanto em inglês para alcançar mais pessoas e com disso existe um desafio de implementar no blog a localização para que o mesmo post funcione tanto em uma lingua quanto em outra. 

Antes de falar sobre a utilização da api quero deixar três referências que me ajudaram a montar minha página de blog. Pensando na ideia de que nada se cria, apenas se combina, peguei como inspiração dois temas de blog para o Nuxt 3 e um post sobre como criar skeleton loader com tailwind CSS.

O Alpine tem um visual de posts agradável, destacando sempre o mais recente, enquanto o Nuxt Starter Blog tem uma maneira simples e eficaz de lidar com a paginação de muitos posts.

{% github https://github.com/nuxt-themes/alpine %}{% github https://github.com/narasimhajupally/tailwind-nuxtjs-starter-blog %}

Gostei da ideia de juntar os dois. Assim, pude criar uma experiência única que combina o visual elegante do Alpine com a praticidade de navegação do Nuxt Starter Blog.

{% link https://dev.to/kouts/skeleton-loader-using-vue-tailwind-422a %} Thanks [@kouts](https://dev.to/kouts) 


## O que você vai precisar:

- A [API do Dev.to](https://developers.forem.com/api/v0), que facilita a obtenção de posts e tags para o seu blog.
- Ferramentas como Nuxt.js e Vue-i18n para lidar com a localização do site e alternar entre os posts em diferentes idiomas.
- Conhecimento básico de HTML, CSS e JavaScript para manipular os dados retornados pela API e criar a estrutura da sua página de blog.

## Passo a passo:


### **Obtenha os posts e tags da API do [Dev.to](http://dev.to/)**: 
    
Utilizei a API para recuperar os posts escritos por você e as tags associadas a cada post. Usei  meu nome de usuário como parâmetro de consulta para essa chamada, juntamente com o estado "all", garantindo que a resposta retorne no máximo 1000 posts com as tags associadas, em vez dos 30 padrão. (espero escrever pelo menos 500 posts 😅)
    
```js
    const { data: posts, pending } = await useFetch(
    	"https://dev.to/api/articles?username=lfxa&state=all");
```


### **Trabalhe com a localização do site e manipule os dados retornados pela API**:
    

Agora vem a parte interessante: para tornar isso funcional, é necessário ter o post disponível tanto em inglês quanto em português no dev.to. Para determinar se o post está em uma das línguas, utilizo o campo `"canonical_url"` com a localização na URL (por exemplo: https://lfxa.vercel.app/en-US/blog?to=um-portfolio-de-um-engenheiro-de-software-162o,a-portfolio-of-a-software-engineer-3i47). Este campo indica a URL de onde o post foi originalmente publicado e é redirecionado para o meu site. Aplico um filtro para exibir apenas os posts na localização desejada. 
    
```js
    const route = useRoute();
    const { locale } = useI18n();
    
    const filteredBlogPosts = computed(() => {
      return props.posts
        ?.filter((post) => {
    	    // localização na url
          const postLang = post.canonical_url.split("/")[3];      
          const isSameLanguage = postLang === locale.value;
    
          //filtrar tag e localização
          const hasTagQuery = route.query.tag !== undefined;
          return isSameLanguage &&
               (!hasTagQuery || post.tag_list.includes(route.query.tag));
        })
        // paginação
        .slice(
          props.postPerPage * (currentPage.value - 1),
          currentPage.value * props.postPerPage,
        );
    });
```

Como o post foi originalmente publicado no [dev.to](http://dev.to/), faço um redirecionamento caso alguém clique no link que leva diretamente ao meu site. (precisa ser melhorado caso adicione mais localizações ao site 😉).

    
```js
    // redirecionar para o post em determinada localização
    if (route.query.to !== undefined) {
      const toPost = route.query.to.split(",");
      const index = locale.value === "pt-BR" ? 0 : 1;
      await navigateTo(`/blog/${toPost[index]}`);
    }
```
    
Filtrei as tags para que apareçam em sua determinada localização:
    
```js
    const tags = computed(() => {
      const tagCounts = {};
      props.posts?.forEach((post) => {
        const lang = post.canonical_url.split("/")[3];
        post.tag_list.forEach((tag) => {
          const key = tag + ":" + lang;
          if (tagCounts[key]) {
            tagCounts[key]++;
          } else {
            tagCounts[key] = 1;
          }
        });
      });
    
      const output = [];
      for (const tagLang in tagCounts) {
        const key = tagLang.split(":");
        output.push({ name: key[0], quantity: tagCounts[tagLang], lang: key[1] });
      }
      output.sort((a, b) => a.name.localeCompare(b.name));
      return output;
    });    
```
    

e adicionei também um filtro para as tags que são selecionadas e se tornam parâmetros de consulta:
    
```js
    // v-if
    tag.lang === $i18n.locale;
    
    // nuxtLink to
    route.fullPath.includes(tag.name) ? 'blog' : 'blog?tag=' + tag.name
```


### **Crie a estrutura da página de post blog**: 
    

Para obter o conteúdo do post, é necessário fazer uma consulta à API específica para aquele determinado post. Utilizei o slug do post juntamente com o meu nome de usuário como parâmetros de consulta na API. O conteúdo do post é fornecido no campo `"body_html"`, mantendo as classes CSS do site do dev.to. Para garantir uma visualização adequada do post, copiei parte do CSS do site que faz sentido. Recomendo evitar o uso da diretiva v-html, pois é sensível a [ataques XSS](https://dev-academy.com/vue-xss/#if-it-is-not-vue-is-it-you) (Cross-Site Scripting). (Espero que o [dev.to](http://dev.to/) não transmita scripts maliciosos que possam ser executados nos sites dos usuários).
    
```js
       const { data: post, pending } = await useFetch(
      "https://dev.to/api/articles/lfxa/" + slug,
    );
```
    
Além disso, caso haja uma alteração de idioma na página, faço uma nova chamada para o mesmo post na outra língua:
    
```js
    onBeforeRouteLeave(async (to, from, next) => {
      if (
        post.value &&
        to.fullPath.split("/").pop() === from.fullPath.split("/").pop()
      ) {
        const last = post.value.canonical_url.split("/").pop();
        const toPost = last.replace("blog?to=", "").split(",");
        const index = locale.value === "pt-BR" ? 0 : 1;
        await next(`/${locale.value}/blog/${toPost[index]}`);
      }
      next();
    });
```

Caso seja do seu interesse, pode ver o código fonte no github [aqui](https://github.com/LFXA/lfxa-nuxt-personal).


---

## Conclusão:

Compartilhar o que sabemos é essencial para tornar o aprendizado mais acessível e promover o crescimento de outros desenvolvedores. Além disso, ao compartilhar conhecimento, fortalecemos nossas próprias habilidades, vemos o que pode ser melhorado e contribuímos para o avanço da comunidade de desenvolvimento de software em geral.

> Assim brilhe a luz de vocês diante dos homens, para que vejam as suas boas obras e glorifiquem ao Pai de vocês, que está nos céus. Mateus 5:16