Creando un sencillo API REST con Cabal
En está ocasión vamos a crear un sencillo servicio API Rest con Cabal.
Consumiremos un sencillo JSON como este:
[ {"autor":"Thomas Muller","id":"1000","precio":"299.0","titulo":"Sangre roja"}, {"autor":"Mariana Seller","id":"1001","precio":"309.0","titulo":"Tierra Hueca"} ]
Requerimientos:
- Tener instalado Haskell.
- Tener instalado Cabal.
- Instalar las dependencias: aeson, text, wai, warp, servant, servant-server.
Creando el servicio API con Cabal
Veremos algo sobre las dependencias necesarias.
Aeson (análisis y codificación rápidos de JSON)
Se trata de una biblioteca de análisis y codificación JSON optimizada para ofrecer facilidad de uso y un alto rendimiento.
Servant
Servant es un conjunto de paquetes para declarar APIs web a nivel de tipos y utilizar dichas especificaciones de API para:
- Escribir servidores.
- Obtener funciones cliente (en Haskell).
- Generar funciones cliente para otros lenguajes de programación.
- Generar documentación para tus aplicaciones web.
- Etc.
Warp
Un servidor web rápido y ligero para aplicaciones WAI.
Wai (Web Application Interface)
Proporciona un protocolo común para la comunicación entre aplicaciones web y servidores web.
Text
Una implementación de texto Unicode eficiente en cuanto a tiempo y espacio.
Creando el proyecto con Cabal
1. Crearemos un directorio y nos ubicaremos en el:
$ mkdir hola-mundo $ cd hola-mundo
2. Crearemos el proyecto con Cabal:
$ cabal init
Esto creará la estructura del proyecto:
hola-mundo/ app/ Main.hs CHANGELOG.md dist-newstyle hola-mundo.cabal LICENSE
Los archivos que modificaremos serán:
- app/Main.hs
- hola-mundo.cabal
3. Modificaremos el archivo hola-mundo.cabal para agregar las siguientes dependencias:
build-depends: base >=4.18 && <4.20, aeson ^>= 2.2, text ^>= 2.0, wai ^>= 3.2, warp ^>= 3.3, servant ^>= 0.20, servant-server ^>= 0.20
4. Ahora modificaremos el programa app/Main.hs. Comenzaremos agregando las extensiones:
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeOperators #-}
Donde:
- DataKinds: permite promover valores a tipos (útil en Servant para rutas).
- DeriveGeneric: habilita la derivación automática de la clase Generic, necesaria para serialización JSON.
- OverloadedStrings: permite usar literales de texto ("hola") como Text sin necesidad de pack.
- TypeOperators: habilita operadores de tipos como :> usados en Servant.
Modificaremos el módulo:
module Main (main) where
Agregaremos las importaciones:
import Data.Aeson (ToJSON) import Data.Text (Text) import GHC.Generics (Generic) import Network.Wai.Handler.Warp (run) import Servant
Esto para:
- Data.Aeson: para convertir tipos Haskell a JSON.
- Data.Text: tipo eficiente para manejar texto.
- GHC.Generics: soporte para derivar instancias automáticamente.
- Warp: servidor HTTP rápido.
- Servant: framework para definir APIs de manera declarativa.
Agregaremos la definición del objeto Libro, en Haskell se denominan records:
data Libro = Libro { id :: Text , titulo :: Text , autor :: Text , precio :: Text } deriving (Eq, Show, Generic)
La instancia del JSON:
instance ToJSON Libro
Definimos la lista del Libro:
libros :: [Libro] libros = [ Libro "1000" "Sangre roja" "Thomas Muller" "299.0" , Libro "1001" "Tierra Hueca" "Mariana Seller" "309.0" ]
Definimos la API:
type API = "api" :> "libros" :> Get '[JSON] [Libro]
Definimos el Proxy:
api :: Proxy API api = Proxy
Definimos el Servidor:
server :: Server API server = return libros
Definimos la aplicación (App):
app :: Application app = serve api server
Programa completo:
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeOperators #-} module Main (main) where import Data.Aeson(ToJSON) import Data.Text(Text) import GHC.Generics(Generic) import Network.Wai.Handler.Warp(run) import Servant data Libro = Libro{ id::Text, titulo::Text, autor::Text, precio::Text } deriving (Eq,Show,Generic) instance ToJSON Libro libros :: [Libro] libros = [ Libro "1000" "Sangre roja" "Thomas Muller" "299.0" , Libro "1001" "Tierra Hueca" "Mariana Seller" "309.0" ] type API = "api":> "libros" :> Get '[JSON] [Libro] api :: Proxy API api = Proxy server :: Server API server = return libros app :: Application app = serve api server main :: IO () main = do putStrLn "Servidor escuchando en http://localhost:8080" run 8080 app
Ejecutamos la aplicación:
$ cabal update $ cabal run
Si todo va bien, podremos consumir la API con un CURL:
$ curl -X GET http://localhost:8080/api/libros
Obtendremos lo siguiente:
[{"autor":"Thomas Muller","id":"1000","precio":"299.0","titulo":"Sangre roja"}, {"autor":"Mariana Seller","id":"1001","precio":"309.0","titulo":"Tierra Hueca"} ]
¡Hemos visto como crear una aplicación Cabal y Servant!
Continuaremos más sobre el tema en próximas entregas.
Enlaces:
https://onlyhaskellforyou.blogspot.com/2026/02/cabal-en-otro-vistazo.htmlhttps://www.servant.dev/
https://www.haskell.org/cabal/
https://hackage.haskell.org/



Comentarios
Publicar un comentario