crystalapi

Source code for project-87-crystalapi

CrystalAPI

A task management REST API built with Crystal 1.11 + Kemal — a compiled language with Ruby-like syntax delivering native performance. Features JWT authentication, bcrypt password hashing, and a thread-safe in-memory store.

Features

  • Crystal + Kemal — compiled native binary, Ruby-like syntax, zero-overhead HTTP framework
  • JWT authPOST /auth/register + POST /auth/login return signed tokens
  • Bcrypt passwordsCrypto::Bcrypt::Password for secure hashing
  • Task CRUD — full create/read/update/delete with status and priority filtering
  • Task stats — aggregated counts by status and priority
  • CORS middlewarebefore_all sets headers for all routes
  • Thread-safe storeMutex-protected in-memory MemoryStore singleton
  • EnumsTaskStatus (todo/in_progress/done) and TaskPriority (low/medium/high)

Tech Stack

Component Technology
Language Crystal 1.11
HTTP Kemal ~> 1.4
Auth JWT ~> 1.6 + Bcrypt
Storage In-memory (Mutex-protected)
Serialization JSON::Serializable

Quick Start

# Requires Crystal 1.11+ and shards
shards install
crystal run src/crystalapi.cr

# Or build a native binary
shards build --release
./bin/crystalapi

# Server at http://localhost:3000
PORT=8080 crystal run src/crystalapi.cr   # custom port

API Endpoints

GET  /health                   Health check
GET  /                         API info

POST /auth/register            { username, email, password }
POST /auth/login               { email, password } → { token, user }
GET  /auth/me                  (Bearer) current user

GET  /tasks                    (Bearer) ?status=todo&priority=high
GET  /tasks/stats              (Bearer) counts by status/priority
GET  /tasks/:id                (Bearer)
POST /tasks                    (Bearer) { title, description, status, priority }
PUT  /tasks/:id                (Bearer) partial update
DELETE /tasks/:id              (Bearer)

Project Structure

project-87-crystalapi/
├── shard.yml
├── shard.lock
└── src/
    ├── crystalapi.cr          # Kemal routes, middleware, Kemal.run
    ├── models/
    │   └── task.cr            # Task, User structs + enums
    ├── store/
    │   └── memory_store.cr    # Singleton in-memory store (Mutex)
    └── auth/
        └── jwt_auth.cr        # JWT encode/decode, require_auth helper

Key Crystal Patterns

# JSON::Serializable struct
struct Task
  include JSON::Serializable
  property id : Int64
  property title : String
  property status : TaskStatus
end

# Mutex-protected singleton
class MemoryStore
  @@instance = new
  @mutex = Mutex.new

  def self.instance
    @@instance
  end

  def create_task(owner_id, title, desc, status, priority)
    @mutex.synchronize do
      # thread-safe mutation
    end
  end
end

# JWT auth middleware
def self.require_auth(env)
  token = env.request.headers["Authorization"]?.try(&.sub("Bearer ", "")) || ""
  payload, _ = JWT.decode(token, SECRET, JWT::Algorithm::HS256)
  user_id = payload["sub"].as_i64
  MemoryStore.instance.get_user(user_id) || raise "Unauthorized"
end

# Kemal route with next for early return
post "/tasks" do |env|
  user = CrystalAPI.require_auth(env)
  title = env.params.json["title"]?.try(&.as_s) || ""
  if title.empty?
    env.response.status_code = 400
    next %({"error":"title is required"})
  end
  task = MemoryStore.instance.create_task(user.id, title, nil, TaskStatus::Todo, TaskPriority::Medium)
  env.response.status_code = 201
  task.to_json
end

Example Usage

# Register
curl -X POST http://localhost:3000/auth/register \
  -H "Content-Type: application/json" \
  -d '{"username":"alice","email":"alice@example.com","password":"secret123"}'

# Login
TOKEN=$(curl -s -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"alice@example.com","password":"secret123"}' | jq -r .token)

# Create task
curl -X POST http://localhost:3000/tasks \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Ship feature","priority":"high"}'

# List tasks
curl http://localhost:3000/tasks?status=todo \
  -H "Authorization: Bearer $TOKEN"
Repository

crystalapi

Owner
Statistic
  • 0
  • 0
  • 0
  • 0
  • 2
  • about 2 hours ago
  • April 29, 2026
License

Links
Synced at

Tue, 02 Jun 2026 07:25:49 GMT

Languages