A lightweight, single-threaded HTTP server for the JVM built on java.nio. MicroServe uses a Node.js-style event loop with non-blocking I/O, Future-based async handlers, HTTP/1.1 keep-alive, and a familiar createServer API.
Add to your build.sbt:
libraryDependencies += "io.github.edadma" %% "microserve" % "0.2.0"import io.github.edadma.microserve.*
@main def run(): Unit =
val loop = new EventLoop
val server = createServer(loop) { (req, res) =>
req.path match
case "/" => res.send("Hello from MicroServe!\n")
case "/json" => res.sendJson("""{"message": "hello"}""" + "\n")
case _ => res.status(404).send("Not Found\n")
}
server.listen(3000) { () =>
println("MicroServe listening on http://localhost:3000")
}
loop.run()Handlers return Future[Unit] — the response methods (send, sendJson, sendHtml, end) return Future.unit, so synchronous handlers just work. For async work, use the loop's ExecutionContext:
import scala.concurrent.Future
val loop = new EventLoop
given scala.concurrent.ExecutionContext = loop.executionContext
val server = createServer(loop) { (req, res) =>
Future {
val result = someComputation()
res.send(result)
}.flatten
}server.close() stops accepting new connections and closes idle keep-alive connections immediately, while letting in-flight requests finish. The drain callback fires once all active requests have completed:
server.close { () =>
println("All connections drained")
loop.stop()
}- Single-threaded, non-blocking I/O via
java.nioselectors - Node.js-style event loop with microtask/macrotask separation (
nextTick,setImmediate,setTimeout,setInterval) ExecutionContextfor runningFuturecallbacks on the event loop thread- Ref-counted lifecycle — loop exits automatically when all work is done
- HTTP/1.1 keep-alive with 30-second idle timeouts
- Graceful shutdown — in-flight requests complete, idle connections close immediately
- Hand-rolled HTTP/1.1 request parser with configurable limits
- Simple
Request/ResponseAPI with helpers for text, HTML, and JSON - No external dependencies
ISC