Supranim ships with an idiomatic MVC structure built around routing, controllers, middleware and templates, but you are not required to use it that way. For custom web apps, microservices or lightweight prototypes that follow a non-idiomatic setup, you can skip the framework layer and work directly with the low-level networking APIs. Built on powpow, these APIs let you create HTTP servers as well as TCP/UDP and WebSocket servers for various use cases.
🔗Examples using the powpow backend
You can skip the Supranim MVC structure and use the low-level API directly.
🔗A simple HTTP server
Creating a simple HTTP server looks like this:
import supranim/network/webserver
var server = newWebServer()
proc onRequest(req: var webserver.Request) =
req.send(Http200, "All cheese is good cheese")
server.start(onRequest, startupCallback = nil, threads = 2) # default 8080The Request type exposes send(code, body), sendFile, sendChunk and streaming helpers for low-level responses.
🔗Adding Router
If you need routing without the routes macro DSL, use the runtime API from supranim/core/router. Create a router with newHttpRouter, register handlers with registerRoute, then dispatch inside onRequest with checkExists:
import std/[httpcore, tables]
import supranim/core/[router, request, response]
import supranim/network/webserver
proc helloHandler(req: var Request, res: var Response) {.nimcall, gcsafe.} =
res.setBody("hello world")
proc usersHandler(req: var Request, res: var Response) {.nimcall, gcsafe.} =
res.setBody("id=" & req.routeParams.getOrDefault("id"))
var appRouter = newHttpRouter()
appRouter.registerRoute("/hello", HttpGet, helloHandler)
appRouter.registerRoute("/users/{id:id}", HttpGet, usersHandler)
proc onRequest(req: var Request) =
{.gcsafe.}:
var res = Response(headers: newHttpHeaders())
let rc = appRouter.checkExists(req.getUriPath(), req.getHttpMethod())
if rc.exists:
req.routeParams = rc.params
rc.route.callback(req, res)
if not req.responseSent:
req.resp(res.getCode(), res.getBody(), res.getHeaders())
else:
req.resp(Http404, "not found")
var server = newWebServer()
server.start(onRequest) # default 8080Each handler uses the proc(req: var Request, res: var Response) {.nimcall, gcsafe.} signature. Use registerRoute with middlewares = @[...] or afterwares = @[...] when needed, and resolve them with resolveMiddleware and resolveAfterware before and after the callback.
🔗WebSocket upgrade example
You can tell Supranim to upgrade an incoming HTTP request to a WebSocket connection if it matches a certain route. Low-level callbacks registered with registerCallback receive the powpow HttpRequest and HttpResponse directly:
import pkg/powpow as pw
import supranim/network/webserver
server.registerCallback("/ws",
proc (req: pw.HttpRequest, res: pw.HttpResponse) {.gcsafe.} =
discard pw.websocketUpgrade(res, req,
onOpen = proc(ws: pw.WsConnection) = echo "open!",
onMessage = proc(ws: pw.WsConnection, kind: pw.WsFrameKind, data: openArray[byte]) =
ws.sendText(cast[string](@data)),
)
)