Request
The Request is an immutable case class that carries all information about an incoming HTTP request.
Properties
Section titled “Properties”case class Request( method: String, // HTTP method (GET, POST, etc.) url: String, // Full URL including query string path: String, // URL path only headers: Map[String, String], // Request headers (lowercase keys) params: Map[String, String], // Path parameters from route query: Map[String, String], // Query string parameters context: Map[String, Any], // Extensible context for middleware data rawRequest: ServerRequest, // Underlying Node.js request object basePath: String, // Accumulated base path from subrouters finalizers: List[Finalizer], // Response transformers (LIFO) cookies: Map[String, String], // Parsed cookies)Path Parameters
Section titled “Path Parameters”Extract named segments from the route pattern:
server.get("/users/:id/posts/:postId", request => { val userId = request.params("id") val postId = request.params("postId") s"User $userId, Post $postId".asText})Query Parameters
Section titled “Query Parameters”Access query string values:
// GET /search?q=scala&page=2server.get("/search", request => { val query = request.query.getOrElse("q", "") val page = request.query.getOrElse("page", "1").toInt s"Searching '$query' page $page".asText})Headers
Section titled “Headers”Headers are stored with lowercase keys for case-insensitive access:
val token = request.header("authorization") .filter(_.startsWith("Bearer ")) .map(_.substring(7))
val contentType = request.header("content-type")Body Parsing
Section titled “Body Parsing”Request body is read lazily as a stream. Four methods are available:
Raw Body
Section titled “Raw Body”request.body.flatMap { buffer: Buffer => // Process binary data buffer.asBinary}Text Body
Section titled “Text Body”Handles charset detection from the Content-Type header:
request.text.flatMap { text: String => s"Received: $text".asText}JSON Body
Section titled “JSON Body”Type-safe parsing with zio-json. Define your types with derives:
case class User(name: String, email: String) derives JsonDecoder
request.json[User].flatMap { case Some(user) => user.asJson(201) case None => "Invalid JSON".asText(400)}Form Data
Section titled “Form Data”URL-encoded form bodies (application/x-www-form-urlencoded):
request.form.flatMap { formData: Map[String, String] => val username = formData.getOrElse("username", "") val password = formData.getOrElse("password", "") processLogin(username, password)}Body Limits
Section titled “Body Limits”Configure maximum body size and read timeout:
// Global defaultsRequest.maxBodySize = 50 * 1024 * 1024 // 50 MB (default)Request.bodyTimeout = 30000 // 30 seconds (default)For per-route limits, use BodyLimitMiddleware:
server.post("/upload", BodyLimitMiddleware(10 * 1024 * 1024), uploadHandler)Connection Info
Section titled “Connection Info”request.ip // Remote IP address (String)request.hostname // Host header value (Option[String])request.port // Remote port (Option[Int])request.protocol // "http" or "https" (String)request.secure // true if HTTPS (Boolean)request.httpVersion // HTTP version stringrequest.complete // Whether the request has been fully receivedrequest.aborted // Whether the client aborted the connectionCookies
Section titled “Cookies”// Access a cookie by namerequest.cookie("session") // Option[String]
// All cookiesrequest.cookies // Map[String, String]With CookieMiddleware enabled, additional methods are available:
request.getSignedCookie("auth") // Verified signed cookierequest.getJsonCookie[Settings]("prefs") // Parse JSON cookieContext
Section titled “Context”The context is a Map[String, Any] used by middleware to pass data to downstream handlers:
// Middleware adds dataval withUser: Handler = request => { val user = lookupUser(request.params("id")) Future.successful(Continue( request.copy(context = request.context + ("user" -> user)) ))}
// Handler reads itval handler: Handler = request => { request.context.get("user") match { case Some(user: User) => user.asJson case _ => failNotFound("User not found") }}The AuthMiddleware stores an Auth object in context under the "auth" key:
request.context.get("auth") match { case Some(auth: AuthMiddleware.Auth) => println(s"User: ${auth.user}, Roles: ${auth.roles}") case _ => // Not authenticated}Adding Finalizers
Section titled “Adding Finalizers”Attach response transformers that run after a Complete result:
val modifiedRequest = request.addFinalizer { (req, response) => Future.successful(response.copy( headers = response.headers.add("X-Custom", "value") ))}Finalizers execute in LIFO order — the last one added runs first.