Peticiones a una API Rest con Gatsby - Parte II.

July 31, 2019 • ☕️ 3 minutos de lectura

En el post anterior, vimos como hacer una petición a una API Rest con Gatsby y mostramos los post en una nueva página, pero nos falta una parte importante, ya que si hacemos clic en cualquier post, nos devolverá un 404.

Para solucionar esto debemos creanos una página para cada post y la haremos accesible cargando una nueva plantilla y asignando un ruta.

Lo primero es editar el archivo gatsby-node.js

Creamos una constante postDetails con el archivo de plantilla ./src/templates/post-details.js, este lo creamos más adelante.

const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)

exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions
  const postDetails = path.resolve(`./src/templates/post-details.js`)  // ...
}

Añadirmos al query de GraphQL el siguiente código, básicamente buscará en todos los post ordenadores por ID Descententemente y límite de 100. Luego simplemente exportamos los datos a los que queremos acceder.

allApiArticles(sort: { fields: [id], order: DESC }, limit: 100) {
          edges {
            node {
              id
              alternative_id
              title
            }
          }
        }

Definimos la constante postApi que contiene todos los post resultantes del query de arriba. Luego los recorremos con un forEach y aquí viene lo importante, usaremos la función createPage() la cual recibe como parámetro un objeto javascript. Esta función es la encargada de crear las nuevas páginas.

  • path: Url válida y debe empezar por /, entro caso /post/${post.node.id}
  • component: Es el component que debemos cargar, en nuestro caso postDetails
  • context: Aquí pasaremos las variables que queremos usar. Luego podremos acceder a ellas con this.props.pageContext
const postsApi = result.data.allApiArticles.edges

postsApi.forEach((post, index) => {
  const previous =
    index === postsApi.length - 1 ? null : postsApi[index + 1].node
  const next = index === 0 ? null : postsApi[index - 1].node
  createPage({
    path: `/post/${post.node.id}`,
    component: postDetails,
    context: {
      slug: `${post.node.id}`,
      previous,
      next,
    },
  })
})

Ahora crearemos el fichero de la plantilla en el directorio src/templates/, le llamaremos post-details.js, para ello usaremos touch.

touch src/templates/post-details.js

Destaco las líneas que me parecen más importantes.

Para acceder a { precius, next }, almacenados en context, podemos hacerlo a través de this.props.pageContext

El query de GraphQL, tiene como peculiaridad que usamos el siguiente filtro: apiArticles(id: { eq: $slug }) {...}

{
  apiArticles(id: { eq: $slug }) {
      id
      alternative_id
      userId
      title
      body
    }
  }
}

El fichero post-details.js quedaría así:

import React from "react"
import { Link, graphql } from "gatsby"
import Layout from "../components/layout"

class BlogDetailsTemplate extends React.Component {
  render() {
    const post = this.props.data.apiArticles    const siteTitle = this.props.data.site.siteMetadata.title
    const { previous, next } = this.props.pageContext    return (
      <Layout location={this.props.location} title={siteTitle}>
        <h1>{post.title}</h1>
        <div dangerouslySetInnerHTML={{ __html: post.body }} />
        <ul
          style={{
            display: `flex`,
            flexWrap: `wrap`,
            justifyContent: `space-between`,
            listStyle: `none`,
            padding: 0,
          }}
        >
          <li>
            {previous && (
              <Link to={`post/${previous.id}`} rel="prev">
{previous.title}
              </Link>
            )}
          </li>
          <li>
            {next && (
              <Link to={`post/${next.id}`} rel="next">
                {next.title}
              </Link>
            )}
          </li>
        </ul>
      </Layout>
    )
  }
}

export default BlogDetailsTemplate

export const pageQuery = graphql`
  query BlogPostById($slug: String!) {    site {
      siteMetadata {
        title
        author
      }
    }
    apiArticles(id: { eq: $slug }) {      id      alternative_id      userId      title      body    }  }
`

Ahora podemos acceder a cada uno de los post en la url http://localhost:8000/post/:slug donde slug, en este caso sería el id.

Además, una vez que hagamos gatsby build, creará un archivo html por cada post, esto ayudará a nuestro posicionamiento SEO 🚀.