kothari_api
KothariAPI – Lightweight Crystal Web Framework
KothariAPI is a small, Rails‑inspired web framework for Crystal. It provides:
- CLI:
kotharifor generating apps and controllers. - Router DSL:
KothariAPI::Router::Router.draw do |r| ... end. - Base controller:
KothariAPI::Controllerwith JSON helpers.
This document explains what is currently implemented and what was fixed in this iteration.
Project Layout
-
Framework shard (this repo):
src/kothari_api.cr– main entry for the shard, requires all framework pieces.src/kothari_api/controller.cr– base controller class.src/kothari_api/router/route.cr–Routevalue object (method, path, controller, action).src/kothari_api/router/router.cr–Routerclass and routing DSL.src/cli/kothari.cr– CLI entry point (kothari).
-
Generated app (e.g.
/var/crystal_programs/demoapp):app/controllers/– application controllers.app/controllers.cr– requires all controllers.config/routes.cr– application routes.src/server.cr– HTTP server that uses the router and controllers.
Router: Design and Fix
Route Representation
KothariAPI::Router::Route holds the HTTP method, path, controller, and action:
method– HTTP verb (e.g."GET").path– request path pattern (e.g."/"or"/users").controller– string name from theto:DSL (e.g."home").action– action name (e.g."index").
It is created via Route.new(method, path, to), where to is of the form "controller#action".
Router DSL
The router lives in src/kothari_api/router/router.cr as KothariAPI::Router::Router and supports:
- Registering routes:
get(path : String, to : String)post(path : String, to : String)
- Looking up a route:
match(method : String, path : String)– returns aRoute?.
- DSL:
drawyields the router itself so you can define routes in a block.
The DSL is used like this:
KothariAPI::Router::Router.draw do |r|
r.get "/", to: "home#index"
end
Critical Fix: draw Block Parameter Error
Originally, draw was implemented as:
def self.draw(&block)
block.call(self)
end
Calling it with do |r| caused:
Error: wrong number of block parameters (given 1, expected 0)
Crystal’s compiler did not know that the block accepted one argument when written this way.
Solution: switch to yield self, letting Crystal infer the block arity correctly:
def self.draw
yield self
end
Now draw do |r| works exactly as intended, and there is only one router implementation: src/kothari_api/router/router.cr.
Base Controller
src/kothari_api/controller.cr defines KothariAPI::Controller:
- Holds the HTTP context:
getter context : HTTP::Server::Context- Initialized with
def initialize(@context).
- JSON helper:
def json(data)setsContent-Typetoapplication/jsonand printsdata.to_json.
All application controllers inherit from this base class, e.g.:
class HomeController < KothariAPI::Controller
def index
json({ message: "Welcome to KothariAPI" })
end
end
CLI (kothari)
The CLI entry is src/cli/kothari.cr and supports:
kothari new <app_name>– generate a new app.kothari server– runcrystal run src/server.crin the current app.kothari build [output] [--release]– compilesrc/server.crinto a binary.kothari g controller <name>– generate a new controller and route.
What kothari new Generates
For kothari new demoapp, the CLI:
-
Creates directories:
demoapp/app/controllersdemoapp/configdemoapp/src
-
Writes
demoapp/shard.yml:-
Adds a path dependency on this framework:
dependencies: kothari_api: path: /var/crystal_programs/kothari_api -
Sets the main target to
src/server.cr.
-
-
Generates
config/routes.cr:KothariAPI::Router::Router.draw do |r| r.get "/", to: "home#index" end -
Generates
app/controllers/home_controller.crwithHomeController#index. -
Generates
app/controllers.crthat requireskothari_apiandhome_controller.
Generated src/server.cr
The CLI now generates a simple, working HTTP server:
- Requires controllers, the framework, routes, and
http/server. - Creates
HTTP::Serverand uses the router to match incoming requests. - For now, it dispatches directly to
HomeController#indexwhen a route is found. - Returns 404 with a JSON error when no route is found.
This design:
- Avoids unsupported Ruby APIs (
Object.const_get,send). - Plays nicely with Crystal’s static type system.
- Ensures that
kothari new+kothari serverproduce a compilable, runnable app.
kothari g controller
The generator:
- Creates
app/controllers/<name>_controller.crwith a basicindexaction. - Appends a
requiretoapp/controllers.cr. - Inserts a new
r.get "/<name>", to: "<name>#index"route intoconfig/routes.crbefore the finalend.
This keeps all routes inside the single Router.draw block and lets you grow your app incrementally.
Install on Ubuntu Server
- Prereqs: Ubuntu,
sudoaccess, network access to GitHub.
1. Install Crystal and system libraries
sudo apt-get update
sudo apt-get install -y crystal
# Install Boehm GC runtime used by Crystal binaries
sudo apt-get install -y libgc1c2 || sudo apt-get install -y libgc1 libgc-dev
2. Clone KothariAPI and build the CLI
cd ~
git clone https://github.com/backlinkedclub/kothari_api.git
cd kothari_api
shards install
crystal build src/cli/kothari.cr -o kothari
sudo mv kothari /usr/local/bin/kothari
You can now run:
kothari
and see the Kothari logo and help.
3. Create a new Kothari app
mkdir -p /var/apps
cd /var/apps
kothari new myapp
cd myapp
shards install
The generated shard.yml will include:
dependencies:
kothari_api:
github: backlinkedclub/kothari_api
version: ~> 0.1.0
4. Run the server and test auth
# Run DB migrations if you've generated auth/scaffolds
kothari db:migrate
# Start dev server (listen on http://localhost:3000)
kothari server
In another terminal you can test:
# Signup
curl -s -X POST http://localhost:3000/signup \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"password123"}'
# Login
curl -s -X POST http://localhost:3000/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"password123"}'
If you scaffold a resource, e.g.:
kothari g scaffold post title:string body:text
kothari db:migrate
You can also:
# Create a post
curl -s -X POST http://localhost:3000/posts \
-H "Content-Type: application/json" \
-d '{"title":"Hello","body":"World"}'
# List posts
curl -s http://localhost:3000/posts
Summary of Key Fixes and Behaviors
- Router DSL:
Router.drawnow usesyield self, fixing the block parameter error.- There is a single, authoritative router implementation in
src/kothari_api/router/router.cr.
- CLI server template:
- Removed Ruby-style
Object.const_getandsend. - Generates a minimal, type-safe demo server using
HomeController#index. - Uses
HTTP::Status::NOT_FOUNDinstead of a bare integer for 404.
- Removed Ruby-style
- End‑to‑end flow now works:
kothari new demoappcd demoapp && shards installkothari server- Visit
http://localhost:3000to see the JSON welcome message.
From here you can iterate on more advanced, compile‑time‑safe controller dispatch (e.g., macros or registries), knowing the router and CLI scaffolding are in a correct, working state.
kothari_api
- 0
- 0
- 0
- 0
- 3
- about 1 hour ago
- November 24, 2025
Other
Mon, 24 Nov 2025 06:24:43 GMT