Translate

domingo, 25 de enero de 2026

API REST con Crystal, Kemal y SQLite


En este post vamos a crear una API REST usando el lenguaje Crystal, el microframework Kemal, y la base de datos SQLite, sin depender de ORMs.

El objetivo: lograr una API rápida, compilada a binario, y con sintaxis clara.

Asegurate de tener instalado:

  • Crystal
  • Shards (el gestor de dependencias)
  • SQLite3


Verificá con:

crystal --version

sqlite3 --version


Creamos el proyecto base:


crystal init app kemal_api

cd kemal_api


Editá el archivo shard.yml y agregá las dependencias:


dependencies:

  kemal:

    github: kemalcr/kemal

  sqlite3:

    github: crystal-lang/crystal-sqlite3


Instalá las dependencias:

shards install


Creamos una base de datos SQLite y una tabla simple:


sqlite3 data.db "CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, email TEXT);"


A hacer las apis: 


require "kemal"

require "sqlite3"

require "json"


DB_URL = "sqlite3://./data.db"


# --- Funciones de acceso a la base de datos ---

def get_users

  users = [] of Hash(String, String)

  DB.open DB_URL do |db|

    db.query("SELECT id, name, email FROM users") do |rs|

      rs.each do

        users << {

          "id" => rs.read(Int32).to_s,

          "name" => rs.read(String),

          "email" => rs.read(String)

        }

      end

    end

  end

  users

end


def get_user(id : Int32)

  DB.open DB_URL do |db|

    db.query_one?("SELECT id, name, email FROM users WHERE id = ?", id, as: {Int32, String, String})

  end

end


def create_user(name : String, email : String)

  DB.open DB_URL do |db|

    db.exec("INSERT INTO users (name, email) VALUES (?, ?)", name, email)

  end

end


# --- Rutas Kemal ---


get "/users" do

  get_users.to_json

end


get "/users/:id" do |env|

  id = env.params.url["id"].to_i

  if user = get_user(id)

    { id: user[0], name: user[1], email: user[2] }.to_json

  else

    env.response.status_code = 404

    { error: "User not found" }.to_json

  end

end


post "/users" do |env|

  data = JSON.parse(env.request.body.not_nil!)

  create_user(data["name"].as_s, data["email"].as_s)

  env.response.status_code = 201

  { message: "User created" }.to_json

end


Kemal.run



Ejecutá:

crystal run src/kemal_api.cr


La API se levanta en http://localhost:3000


Con Get

curl http://localhost:3000/users


Con Post

curl -X POST http://localhost:3000/users \

  -H "Content-Type: application/json" \

  -d '{"name": "Emanuel", "email": "ema@example.com"}'


Buscar un nuevo users es con id:

curl http://localhost:3000/users/1


Con Crystal + Kemal + SQLite podés construir APIs REST livianas, rápidas y auto-contenidas, ideales para proyectos pequeños o microservicios.

El código es legible, la ejecución veloz, y la experiencia de desarrollo tan fluida como en Ruby, pero con el rendimiento de C.