Volver

¿Puedo utilizar Next.js para construir una aplicación back-end?

Categorías

Next.js | Javascript | Fullstack

Fecha

31-05-2024

Quizás te hayas preguntado alguna vez si puedes utilizar Next.js para construir una API Rest o para construir algún otro proceso back-end que pueda ser utilizado por el frontal de tu aplicación. Hace poco tuve que responderme yo mismo a esta pregunta. Tenía una aplicación hecha en Next.js a la que debía integrarle ciertas operativas más puras de back-end y me pregunté si podía aprovechar las funcionalidades de Next.js para evitarme construir a parte un servidor Node.js o similar. Por lo que en este artículo os contaré mi experiencia y conclusiones.

Imagen a pantalla completa

Antes de meternos en harina hablemos sobre el sujeto principal de este artículo, ¿qué es Next.js?. Quizás la definición que más podemos encontrar por internet es la siguiente: framework de desarrollo front-end que permite la generación de sitios estáticos y sitios renderizados desde el servidor para aplicaciones basadas en React. A esto comúnmente se le llama Static Site Generation (SSG) y Server-side Rendering (SSR). Obviamente, también puedes utilizar Next.js para hacer el renderizado clásico de aplicaciones javascript en el navegador, Client-side Rendering (CSR), pero digamos que las dos primeras operativas fueron las que impulsaron a Next.js a nivel de mercado, debido a que solucionaban una gran cantidad de problemas, gran parte de ellos relacionados con el SEO de las aplicaciones que se renderizan directamente en el navegador. En cualquier caso es importante destacar que el centro operativo del framework se ejecuta en servidor, concretamente sobre un proceso de Node.js.

Pero revisando la definición dada anteriormente, nos podemos plantear una pregunta: ¿realmente es un framework front-end? Aunque quizás antes de responder a esta pregunta debemos esclarecer cómo delimitamos si un framework es de front-end o de back-end. Personalmente, veo dos indicadores que pueden ayudarnos a resolver esta cuestión. El primero de ellos es juzgar el framework por la finalidad de lo que desarrolla, es decir, cuál es el fin último, la razón de ser, de dicho framework. El segundo indicador consiste en analizar dónde reside el core de su lógica, es decir, dónde se ejecutan la mayoría de procesos de dicho framework.

En el caso de Next.js, siendo concisos, su razón de ser es la de poder renderizar aplicaciones desarrolladas en React en el lado del servidor. Ahora bien, nos encontramos ante una pequeña ambivalencia, debido a que la finalidad es desarrollar el frontal de nuestra aplicación, pero la mayoría de la lógica del framework se desarrolla en el servidor, routing, middlewares, generación de estáticos…

Quizás el argumento de que se utiliza para construir frontales en React es un argumento de peso, pero bueno, intentando buscar un paralelismo, Symfony también utiliza Twig para renderizar el frontal de sus aplicaciones y no por ello se considera a Symfony un framework de front-end, ni mucho menos. Es cierto que la potencia que te da React en el front-end no te la da Twig, que es un mero sistema de plantillas. Como es una cuestión muy filosófica, no quiero extenderme mucho más. Para mí, la conclusión es que ambos son frameworks de back-end, debido a que su operativa principal se ejecuta en el lado del servidor y para trabajar con ellos debes conocer ciertas operativas específicas de back-end, pero con focos totalmente distintos. Ambos te permiten construir aplicaciones E2E, pero Next.js tiene mucho más foco en la experiencia de desarrollo front-end, mientras que Symfony tiene mucho más foco en la experiencia back-end.

Obviamente, una aplicación pura en React también necesita de un servidor para ejecutarse, como Nginx, por ejemplo. Pero dicho servidor no es parte de la naturaleza propia del framework/librería, sino que es un tercer actor necesario para la mayoría de escenarios cuando queremos poner nuestra aplicación React en producción.

¿Qué tipos de procesos back-end puedo construir en Next.js?

A estas alturas ya tendréis más o menos clara la respuesta al título del artículo, siendo la respuesta sí, si podemos utilizar Next.js para construir una aplicación back-end, debido a que podemos construir una aplicación cuyo core reside en el lado del servidor. Ahora bien, no todas las tipologías de aplicaciones back-end tienen cabida en Next.js. Veamos qué operativas podemos construir en Next.js:

  • SSR y SSG: podemos compilar y renderizar el contenido de nuestra aplicación puramente desde el lado del servidor. Podemos hacer que el contenido se recompile en cada request, SSR o bien tenerlo pre-compilado y cacheado durante un tiempo determinado para reducir la latencia, SSG. El punto a destacar es que si nuestros componentes de React hacen llamadas a determinadas API’s para alimentar el contenido de nuestra aplicación, estas llamadas se resuelven en el lado del servidor, entregando todo el contenido ya renderizado, evitando llamadas XHR en el navegador, en caso de que así lo queramos.
  • API Rest y Serverless functions: gracias a los Route Handlers podemos desarrollar pequeñas API’s que sean consultadas por los componentes de nuestra aplicación o por un tercero. A su vez, podemos aprovechar esta funcionalidad para desarrollar funciones serverless que se ejecutan cada vez que llamamos a su ruta asociada.

Existen otras operativas que podemos realizar, como aplicar middlewares sobre otras operativas, que no vamos a abordar hoy por reducir la complejidad del artículo.

Caso práctico

De nada sirve la teoría sin la práctica. A continuación, vamos a realizar un pequeño experimento extrapolado de la situación a la que me tuve que enfrentar recientemente, obviamente para este artículo vamos a simplificar mucho el problema. La aplicación que vamos a desarrollar se encarga de listar modelos de vehículos provenientes de una base de datos. Para ello, tenemos tres piezas claves en la arquitectura de nuestra aplicación:

  • Una página/componente que se renderiza en el lado del servidor cada vez que el usuario entra a la ruta /cars.
  • Una API expuesta en la ruta /api/cars que devuelve todos los vehículos encontrados en la base de datos.
  • Una base de datos SQLite que almacena la información de los vehículos. Para este caso en concreto hemos desarrollado un pequeño script que provea de datos a dicho SQLite.

Bien, sabiendo que tenemos nuestra base de datos lista para ser consultada, lo primero es desarrollar el único endpoint de nuestra API, en este caso de tipo GET, que extraiga dicha información y la exponga:

import { createConnection } from "../../../config/db-connection"

const connection = createConnection()

export async function GET() {
  const cars = await connection("Car").select("*")
  return Response.json({ cars })
}

Una vez hecho esto podemos consumir los datos desde nuestros componentes, por ejemplo:

export default async function CarsPage() {
  const res = await fetch("http://localhost:3000/api/cars")
  const { cars } = await res.json()
  return (
    <>
      <p>Cars list:</p>
      <ul>
        {cars.map((car: Car, i: number) => (
          <li key={i}>{`${car.brand} ${car.model}`}</li>
        ))}
      </ul>
    </>
  )
}

El código que acabamos de ver es muy vago, con una finalidad meramente didáctica. En este repositorio podéis encontrar todo el código, incluida la base de datos ya alimentada para que podáis realizar vuestras propias pruebas.

Ventajas

  • Versatilidad: Next.js nos permite llevar a cabo desarrollos tanto front-end como back-end utilizando un único framework. Además, soporta múltiples métodos de renderizado, como hemos visto y se integra fácilmente con diversas tecnologías, lo que lo hace adecuado para una amplia gama de aplicaciones web.
  • Rapidez para iterar: nos permite hacer validaciones técnicas y de producto de manera muy rápida y si en algún momento nuestra aplicación crece siempre podemos llevarnos nuestra lógica de back-end a otro framework más potente a nivel de back-end.
  • SEO: poco que aportar aquí, todos hemos sufrido alguna vez problemas de SEO con aplicaciones que se renderizan exclusivamente en el navegador.

Desventajas

Obviando el hecho de que no puedes desarrollar operativas tan complejas como en otros frameworks como Express o Koa, quizás la mayor desventaja para mí sea la estructura de carpetas que te impone Next.js para la construcción de las rutas. ¿Cómo sabemos que nuestro endpoint se expone en la ruta /api/cars? Bien, es debido a que el fichero sigue la siguiente convención de carpetas y correspondiente nombre de fichero: src/app/api/cars/route.ts. Os aconsejo ir a la documentación oficial de Next.js para saber más. Para mí esto es una desventaja debido a que nos lastra a la hora de construir un sistema de carpetas coherente o que tenga sentido, ya que en mi caso me gusta que la estructura de carpetas represente una abstracción de la arquitectura de la aplicación que estoy construyendo.

Conclusiones

Existe una dualidad muy presente que difumina la línea entre lo front-end y lo back-end, lo que está claro es que Next.js nos permite construir de manera más o menos efectiva aplicaciones E2E, según su complejidad. Queda en nuestra mano, como desarrolladores, saber elegir la mejor herramienta según la tipología de nuestro proyecto. Por ejemplo, ¿es correcto utilizar Next.js para construir una aplicación que es puramente una API Rest? la respuesta es no, aunque como hemos visto anteriormente, podemos desarrollar endpoints que complementen el ecosistema de nuestra aplicación para casos determinados.

Enjoy!