Tutorial Compojure I: Creando una aplicación web funcional

Llevo ya un tiempo escribiendo sobre clojure y hasta ahora hemos visto como resolver algunos problemas del proyecto euler e incluso como aplicarlo a un caso práctico.

Ha llegado el momento de comprobar cómo se comporta un lenguaje funcional en un entorno más habitual y para ello he decidido hacer un pequeño tutorial sobre cómo crear una aplicación usando compojure, un framework para desarrollar aplicaciones web con clojure.

Creando el esqueleto de la aplicación

Para crear la aplicación usaremos leiningen, que nos permite generar fácilmente el esqueleto de la aplicación con el siguiente comando:

lein new compojure compojure-sample

Esto usará la plantilla compojure para crear un nuevo proyecto en la carpeta compojure-sample. La carpeta contiene la estructura necesaria para empezar a trabajar:

  • ./project.clj: contiene la definición del proyecto, incluyendo las dependencias, plugins, configuración de inicio, etc.
  • ./src/compojure_sample/handler.clj: contiene la definición de rutas de la aplicación.
  • ./test/compojure_sample/handler.clj: contiene los tests para la aplicación.

Podemos comprobar que todo ha funcionado correctamente ejecutando desde la carpeta raíz del proyecto el comando:

lein ring server

Esto iniciará un servidor web en un puerto libre y abrirá un navegador a la raíz del sitio web. Si todo ha ido bien, deberías ver el clásico Hello World.

Además, podemos ejecutar los tests del proyecto y comprobar que todos pasan con el comando:

lein test

Conceptos Básicos

Ya tenemos la aplicación montada, pero como llevo diciendo mucho tiempo es importante saber lo que estamos haciendo, así que vamos a analizar que está pasando por debajo.

Compojure es un framework para crear aplicaciones web con clojure que se basa en una librería de más bajo nivel llamada ring. Ring define un API de bajo nivel para interactuar con sevidores web, algo similar a OWIN en el mundo de .NET.

Existen adapters de ring para poder ejecutarlo sobre distintos servidores como Jetty o plataformas online como Heroku o Amazon Elastic Beanstalk. En el caso de compojure, se utiliza Jetty como servidor de desarrollo.

Compojure define un DSL que permite utilizar más cómodamente las APIs de bajo de nivel de ring. Esto es algo muy frecuente en clojure, donde gracias al uso de macros definir DSLs es tan sencillo que la frontera entre API y DSL se difumina bastante.

En el fichero ./src/compojure_sample/handler.clj podemos ver cómo está definida hasta ahora nuestra aplicación:

(ns compojure-sample.handler
  (:use compojure.core)
  (:require [compojure.handler :as handler]
            [compojure.route :as route]))

(defroutes app-routes
  (GET "/" [] "Hello World")
  (route/not-found "Not Found"))

(def app
  (handler/site app-routes))

Lo primero que encontramos es la definición del espacio de nombres y las referencias a otros espacios de nombres que se van a utilizar. A continuación, encontramos la definición de rutas:

(defroutes app-routes
  (GET "/" [] "Hello World")
  (route/not-found "Not Found"))

Si alguna vez habéis trasteado con frameworks como Sinatra en Ruby o Nancy en .NET, seguramente os resulte familiar.

Las rutas se definen usando funciones que actúan como manejadores de rutas. Usando la macro defroutes se construye algo similar a una cadena de responsabilidad que se utiliza para buscar la función adecuada a la ruta que se debe manejar.

Para definir cada ruta existen macros que nos facilitan el trabajo, como por ejemplo GET o POST, que nos permiten crear rutas que responden a un método HTTP y path concreto, o not-found para definir qué hacer cuando se intenta acceder a un recursos para el que no hay ruta definida.

En este caso sólo estamos devolviendo un string con el texto, pero más adelante veremos como utilizar una función y cómo recibir parámetros a través de la ruta.

Una vez que hemos definido la tabla de rutas, se define el sitio web:

(def app
  (handler/site app-routes))

La variable a la que estamos asignado el sitio web es referenciada en el fichero project.clj y es lo que permite a leiningen saber qué tiene que ejecutar cuando lanzamos el servidor.

Proximamente…

Ya tenemos montada una aplicación web, podemos ejecutar sus tests y arrancar un servidor para visualizar las páginas. De momento no hace gran cosa, pero tenemos todo listo para empezar a añadir funcionalidad y, lo más importante, tenemos más o menos claro como se están enlazando las distintas piezas.

En el próximo post veremos como podemos hacer que nuestro servidor sirva algo más que un triste Hello World, para lo que aprenderemos a incluir contenido estático y generar páginas dinámicamente usando hiccup.

El código fuente completo de este tutorial lo puedes encontrar en mi cuenta en github: https://github.com/jmhdez/compojure-sample. Siéntete libre de clonarlo, cambiarlo y jugar con él todo lo que quieras, y si te animas a realizar alguna corrección, estaré encantado de recibirla.

2 comentarios en “Tutorial Compojure I: Creando una aplicación web funcional

  1. Vale la pena indicar que fragmentos como (GET «/» [] «Hello World») realmente se evalúan «normalmente», y no se pasan como listas. Generan una función.

    Por lo demás, un placer seguir el contenido de tu blog – el equilibrio entre conceptos y código me parece ideal.

  2. Tienes razón, tal y como estaba escrito daba a entender una cosa equivocada. Lo he actualizado para intentar explicarlo mejor y ver si queda más claro.

    Cree que me va a venir muy bien tenerte como lector durante esta serie de artículos ;-)

Comentarios cerrados.