sábado, 8 de março de 2025

UFCD 5414 - Next.js - Rotas de API

 


Rotas de API

As rotas de API permitem que você crie APIs com Next.js.

Se você abrir pages/api/hello.jsverá o seguinte:

// Next.js API route support: https://nextjs.org/docs/api-routes/introduction

export default function handler(req, res) {
  res.status(200).json({ name: 'John Doe' })
}

Inicie o servidor de desenvolvimento Next.js com:

npm run dev

Então abra http://localhost:3000/api/hello no seu navegador. Você deve ver o seguinte:

olá-api-route.png

Como temos um arquivo chamado hello.jsdentro do pages/apiNext.js, criaremos uma rota para esta API em /api/hello. Rotas de API também podem ser dinâmicas , assim como páginas dinâmicas que abordamos na lição anterior. Abordaremos como criar rotas de API dinâmicas mais adiante neste artigo.

Detalhamento do código

Vamos dar uma olhada mais aprofundada no hello.jsarquivo.

export default function handler(req, res) {
  res.status(200).json({ name: 'John Doe' })
}

Este arquivo contém uma única função exportada chamada handler(). O nome desta função não é importante, você pode nomeá-la como quiser, mas handler é uma convenção comum. A função tem dois parâmetros reqres.

O Next.js também fornece alguns middlewares e funções auxiliares integrados para facilitar o trabalho com os objetos de solicitação e resposta.

O corpo da nossa handler()função contém o seguinte:

res.status(200).json({ name: 'John Doe' })

Isso retorna um código de status de resposta de 200 e, em seguida, retorna um objeto JSON com uma propriedade de nome e “John Doe” como seu valor.

Métodos de solicitação HTTP

Nosso método handler responderá atualmente a qualquer método de solicitação HTTP, mas e se quisermos ter respostas diferentes para solicitações diferentes? Podemos fazer isso detectando qual tipo de método HTTP nossa rota de API está recebendo usando o reqobjeto.

Vamos atualizar nossa handler()função para responder apenas a solicitações HTTP Get.

export default function handler(req, res) {
  if (req.method === 'GET') {
    res.status(200).json({ name: 'John Doe' })
  }
}

Usando uma if()declaração simples, podemos detectar diferentes métodos de solicitação HTTP que nossa rota de API recebe e responder adequadamente.

Vamos atualizar nosso handler()para lançar um código de status 400 se ele receber qualquer método HTTP diferente de GET.

export default function handler(req, res) {
  if (req.method === 'GET') {
    res.status(200).json({ name: 'John Doe' })
  } else {
    res.status(400).json({ error: 'Your request could not be processed.' })
  }
}

Rotas de API e getStaticProps

Agora que temos um melhor entendimento das rotas de API, vamos ver como podemos usá-las dentro das páginas Next.js. Dentro delas, pages/posts/[id].jsestamos fazendo uma chamada de API para uma API externa para obter nossos dados de postagem.

export async function getStaticProps({ params }) {
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${params.id}`
  )
  const post = await res.json()

  console.log(post)

  return { props: { post } }
}

Vamos criar uma nova rota de API para nossas postagens e usá-la dentro da getStaticProps()função.

Rota da API de postagens

Primeiro, crie um novo arquivo chamado posts.jsdentro de /pages/apialgo assim.

posts-arquivo.png

Em seguida, criaremos nossa handler()função.

export default function handler(req, res) {}

Em seguida, precisaremos retornar os dados de nossos posts. Para fazer isso, copiaremos o JSON de https://jsonplaceholder.typicode.com/posts para um novo arquivo e o usaremos dentro do nosso handler().

Crie uma nova pasta chamada datana raiz do nosso projeto Next.js. Então crie um arquivo chamado posts.jsondentro dela.

posts-json.png

Copie e cole todas as postagens de https://jsonplaceholder.typicode.com/posts no posts.jsonarquivo.

posts-json-dados.png

Em seguida, precisaremos importar esse arquivo para o nosso pages/api/posts.jsarquivo assim:

import posts from '../../data/posts.json'

export default function handler(req, res) {}

Agora tudo o que precisamos fazer é retornar nossas postagens da nossa handler()função assim:

import posts from '../../data/posts.json'

export default function handler(req, res) {
  res.status(200).json(posts)
}

Agora, se você acessar a URL http://localhost:3000/api/posts no seu navegador, verá o seguinte:

api-posts-rota.png

Agora que nossa rota de API retorna nossas postagens, precisamos atualizar as funções getStaticProps()getStaticPaths()para nossa rota de API assim:

Aqui está todo o conteúdo depages/posts/[id].js

function Post({ post }) {
  return (
    <>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </>
  )
}

export async function getStaticPaths() {
  const res = await fetch('http://localhost:3000/api/posts')
  const posts = await res.json()

  const paths = posts.map((post) => ({
    params: { id: post.id.toString() },
  }))

  return { paths, fallback: false }
}

export async function getStaticProps({ params }) {
  const res = await fetch(`http://localhost:3000/api/posts/${params.id}`)
  const post = await res.json()

  console.log(post)

  return { props: { post } }
}

export default Post

Você deve receber um erro.

Vamos tentar obter uma de nossas postagens visitando http://localhost:3000/posts/1 você deverá ver o seguinte erro:

erro-de-resposta-json-inválido.png

Então o que exatamente está acontecendo aqui? Bem, se você olhar de perto, dentro de getStaticProps()nós estamos tentando buscar cada post por um número de ID:

const res = await fetch(`http://localhost:3000/api/posts/${params.id}`)

O problema é que criamos apenas uma rota de API para, /api/postsnão para /api/posts/1. Para que isso funcione, precisamos criar uma rota de API dinâmica .

Rotas de API dinâmicas

Crie uma pasta chamada postsdentro de /pages/apialgo assim:

pasta-posts.png

Em seguida, vá /pages/api/posts.jspara dentro da /pages/api/postspasta e renomeie-a paraindex.js

posts-index-js.png

Agora crie um arquivo com o /api/posts/[id].jsseguinte nome:

posts-id-arquivo.png

Em seguida, copie e cole o seguinte em pages/api/[id].js.

import posts from '../../../data/posts.json'

export default function handler(req, res) {
  res.status(200).json(posts)
}

posts-id-arquivo-conteúdo.png

Agora, se você acessar a URL http://localhost:3000/api/posts/1, verá o seguinte:

api-posts-1-rota.png

Nossa rota de API dinâmica está retornando todos os dados das postagens em vez de apenas uma única postagem com o ID 1. Vamos escrever alguma lógica dentro da nossa handler()função para filtrar esses dados e retornar a postagem correta com base no ID na URL.

A primeira coisa que precisamos fazer é obter o número de identificação da solicitação.

export default function handler(req, res) {
  const { id } = req.query
  res.status(200).json(posts)
}

Estamos usando a desestruturação para obter o ID do objeto de solicitação.

const { id } = req.query

Podemos verificar isso passando a idvariável para o nosso resassim:

export default function handler(req, res) {
  const { id } = req.query
  res.status(200).json(id)
}

Agora, se você visitar http://localhost:3000/api/posts/1, deverá ver o seguinte:

post-id-json-resposta.png

Agora que estamos obtendo o ID da resposta, podemos usá-lo para filtrar todos os dados das postagens e retornar a postagem com o ID correto.

export default function handler(req, res) {
  const { id } = req.query
  const post = posts.filter((post) => id == post.id)

  res.status(200).json(post)
}

Agora, quando visitarmos http://localhost:3000/api/posts/1, veremos apenas os dados da postagem para esse ID.

api-post-1-dados.png

Cada vez que você alterar o ID na URL, você deverá receber uma postagem diferente.

Agora, se você tentar visitar http://localhost:3000/posts/1, você notará que a tela está em branco!?! Se você olhar atentamente para os dados JSON retornados de cada post, verá que os dados do post estão aninhados dentro de um array.

Dentro pages/posts/[id].jsdo topo do nosso arquivo, nossa Postfunção é a seguinte:

function Post({ post }) {
  return (
    <>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </>
  )
}

Não esperamos que os dados sejam aninhados dentro de um array, e é por isso que o post não está sendo exibido. Temos duas opções para consertar isso.

A primeira opção é atualizar Post()assim:

function Post({ post }) {
  console.log(post)
  return (
    <>
      <h1>{post[0].title}</h1>
      <p>{post[0].body}</p>
    </>
  )
}

pós-função-matriz-atualizações.png

A segunda opção e melhor opção na minha opinião é usar a desestruturação novamente. Atualize getStaticProps()para o seguinte:

function Post({ post }) {
  console.log(post)
  return (
    <>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </>
  )
}

// ...

export async function getStaticProps({ params }) {
  const res = await fetch(`http://localhost:3000/api/posts/${params.id}`)
  const [post] = await res.json() // this is destructuring

  return { props: { post } }
}

<aside> 💡 Observe que não precisamos atualizar nada na Postfunção no topo, pois agora estamos enviando os dados corretos.

</à parte>

Nesta linha aqui:

const [post] = await res.json()

estamos desestruturando o objeto post do array em que ele está aninhado.

Encerrar

Neste artigo você aprendeu o seguinte:

  • Como criar rotas de API em Next.js
  • Como responder a diferentes métodos e solicitações HTTP
  • Como usar rotas de API dentro de páginas Next.js
  • Como criar rotas de API dinâmicas

Nenhum comentário:

Postar um comentário