Complete HTTP status code constants and response builders for creating well-formed HTTP responses. The DSL provides fluent APIs for all standard HTTP status codes with appropriate response body and header handling.
Base traits for building HTTP responses with different characteristics.
/**
* Base trait for all response generators
*/
trait ResponseGenerator extends Any {
def status: Status
}
/**
* Generator for responses without body content
*/
trait EmptyResponseGenerator[F[_], G[_]] extends Any with ResponseGenerator {
def apply()(implicit F: Applicative[F]): F[Response[G]]
def headers(header: Header.ToRaw, _headers: Header.ToRaw*)(implicit F: Applicative[F]): F[Response[G]]
}
/**
* Generator for responses with optional body content
*/
trait EntityResponseGenerator[F[_], G[_]] extends Any with ResponseGenerator {
def liftG: FunctionK[G, F]
def apply()(implicit F: Applicative[F]): F[Response[G]]
def apply[A](body: G[A])(implicit F: Monad[F], w: EntityEncoder[G, A]): F[Response[G]]
def apply[A](body: A, headers: Header.ToRaw*)(implicit F: Applicative[F], w: EntityEncoder[G, A]): F[Response[G]]
def headers(header: Header.ToRaw, _headers: Header.ToRaw*)(implicit F: Applicative[F]): F[Response[G]]
}
/**
* Generator for redirect responses requiring Location header
*/
trait LocationResponseGenerator[F[_], G[_]] extends Any with EntityResponseGenerator[F, G] {
def apply(location: Location)(implicit F: Applicative[F]): F[Response[G]]
def apply[A](location: Location, body: A, headers: Header.ToRaw*)(implicit F: Applicative[F], w: EntityEncoder[G, A]): F[Response[G]]
}
/**
* Generator for 401 Unauthorized responses requiring WWW-Authenticate header
*/
trait WwwAuthenticateResponseGenerator[F[_], G[_]] extends Any with ResponseGenerator {
def apply(authenticate: `WWW-Authenticate`, headers: Header.ToRaw*)(implicit F: Applicative[F]): F[Response[G]]
def apply[A](authenticate: `WWW-Authenticate`, body: A, headers: Header.ToRaw*)(implicit F: Applicative[F], w: EntityEncoder[G, A]): F[Response[G]]
}
/**
* Generator for 405 Method Not Allowed responses requiring Allow header
*/
trait AllowResponseGenerator[F[_], G[_]] extends Any with ResponseGenerator {
def apply(allow: Allow, headers: Header.ToRaw*)(implicit F: Applicative[F]): F[Response[G]]
def apply[A](allow: Allow, body: A, headers: Header.ToRaw*)(implicit F: Applicative[F], w: EntityEncoder[G, A]): F[Response[G]]
}Status codes indicating successful request processing.
// 2xx Success Status Codes
val Ok: Status.Ok.type // 200
val Created: Status.Created.type // 201
val Accepted: Status.Accepted.type // 202
val NonAuthoritativeInformation: Status.NonAuthoritativeInformation.type // 203
val NoContent: Status.NoContent.type // 204
val ResetContent: Status.ResetContent.type // 205
val PartialContent: Status.PartialContent.type // 206
val MultiStatus: Status.MultiStatus.type // 207
val AlreadyReported: Status.AlreadyReported.type // 208
val IMUsed: Status.IMUsed.type // 226Usage Examples:
import org.http4s.dsl.io._
import cats.effect.IO
val routes = HttpRoutes.of[IO] {
// Simple OK response
case GET -> Root / "hello" =>
Ok("Hello, World!")
// Created with response body
case POST -> Root / "users" =>
Created("User created successfully")
// No content response
case DELETE -> Root / "users" / IntVar(id) =>
NoContent()
// Response with custom headers
case GET -> Root / "data" =>
Ok("Response data", Header("X-Custom", "value"))
// JSON response (with appropriate EntityEncoder)
case GET -> Root / "api" / "user" / IntVar(id) =>
val user = User(id, "John Doe")
Ok(user.asJson)
}Status codes for URL redirection with automatic Location header handling.
// 3xx Redirection Status Codes
val MultipleChoices: Status.MultipleChoices.type // 300
val MovedPermanently: Status.MovedPermanently.type // 301
val Found: Status.Found.type // 302
val SeeOther: Status.SeeOther.type // 303
val NotModified: Status.NotModified.type // 304
val TemporaryRedirect: Status.TemporaryRedirect.type // 307
val PermanentRedirect: Status.PermanentRedirect.type // 308Usage Examples:
import org.http4s.dsl.io._
import org.http4s.headers.Location
import org.http4s.Uri
val routes = HttpRoutes.of[IO] {
// Permanent redirect
case GET -> Root / "old-path" =>
MovedPermanently(Location(Uri.unsafeFromString("/new-path")))
// Temporary redirect with body
case GET -> Root / "temp" =>
Found(Location(Uri.unsafeFromString("/temporary-location")), "Redirecting...")
// Post-redirect-get pattern
case POST -> Root / "submit" =>
SeeOther(Location(Uri.unsafeFromString("/success")))
// Not modified (for caching)
case GET -> Root / "resource" if notModified =>
NotModified()
}Status codes indicating client-side errors with specialized response generators.
// 4xx Client Error Status Codes
val BadRequest: Status.BadRequest.type // 400
val Unauthorized: Status.Unauthorized.type // 401
val PaymentRequired: Status.PaymentRequired.type // 402
val Forbidden: Status.Forbidden.type // 403
val NotFound: Status.NotFound.type // 404
val MethodNotAllowed: Status.MethodNotAllowed.type // 405
val NotAcceptable: Status.NotAcceptable.type // 406
val ProxyAuthenticationRequired: Status.ProxyAuthenticationRequired.type // 407
val RequestTimeout: Status.RequestTimeout.type // 408
val Conflict: Status.Conflict.type // 409
val Gone: Status.Gone.type // 410
val LengthRequired: Status.LengthRequired.type // 411
val PreconditionFailed: Status.PreconditionFailed.type // 412
val PayloadTooLarge: Status.PayloadTooLarge.type // 413
val UriTooLong: Status.UriTooLong.type // 414
val UnsupportedMediaType: Status.UnsupportedMediaType.type // 415
val RangeNotSatisfiable: Status.RangeNotSatisfiable.type // 416
val ExpectationFailed: Status.ExpectationFailed.type // 417
val MisdirectedRequest: Status.MisdirectedRequest.type // 421
val UnprocessableEntity: Status.UnprocessableEntity.type // 422
val Locked: Status.Locked.type // 423
val FailedDependency: Status.FailedDependency.type // 424
val TooEarly: Status.TooEarly.type // 425
val UpgradeRequired: Status.UpgradeRequired.type // 426
val PreconditionRequired: Status.PreconditionRequired.type // 428
val TooManyRequests: Status.TooManyRequests.type // 429
val RequestHeaderFieldsTooLarge: Status.RequestHeaderFieldsTooLarge.type // 431
val UnavailableForLegalReasons: Status.UnavailableForLegalReasons.type // 451Usage Examples:
import org.http4s.dsl.io._
import org.http4s.headers.{`WWW-Authenticate`, Allow}
val routes = HttpRoutes.of[IO] {
// Bad request with validation errors
case POST -> Root / "users" =>
// Validation logic
if (invalidInput) {
BadRequest("Invalid user data provided")
} else {
Created("User created")
}
// Unauthorized with WWW-Authenticate header
case GET -> Root / "protected" =>
Unauthorized(`WWW-Authenticate`(Challenge("Bearer", "api")))
// Not found with helpful message
case GET -> Root / "users" / IntVar(id) =>
// Lookup user
userService.findById(id).flatMap {
case Some(user) => Ok(user.asJson)
case None => NotFound(s"User with ID $id not found")
}
// Method not allowed with Allow header
case req @ POST -> Root / "readonly" =>
MethodNotAllowed(Allow(Set(GET, HEAD)))
// Conflict for duplicate resources
case POST -> Root / "users" =>
// Check for existing user
if (userExists) {
Conflict("User already exists")
} else {
Created("User created")
}
}Status codes indicating server-side errors and service unavailability.
// 5xx Server Error Status Codes
val InternalServerError: Status.InternalServerError.type // 500
val NotImplemented: Status.NotImplemented.type // 501
val BadGateway: Status.BadGateway.type // 502
val ServiceUnavailable: Status.ServiceUnavailable.type // 503
val GatewayTimeout: Status.GatewayTimeout.type // 504
val HttpVersionNotSupported: Status.HttpVersionNotSupported.type // 505
val VariantAlsoNegotiates: Status.VariantAlsoNegotiates.type // 506
val InsufficientStorage: Status.InsufficientStorage.type // 507
val LoopDetected: Status.LoopDetected.type // 508
val NotExtended: Status.NotExtended.type // 510
val NetworkAuthenticationRequired: Status.NetworkAuthenticationRequired.type // 511Usage Examples:
import org.http4s.dsl.io._
val routes = HttpRoutes.of[IO] {
// Handle application errors
case GET -> Root / "data" =>
dataService.fetchData().attempt.flatMap {
case Right(data) => Ok(data.asJson)
case Left(error) =>
logger.error("Data fetch failed", error)
InternalServerError("Unable to fetch data")
}
// Service temporarily unavailable
case GET -> Root / "maintenance" =>
ServiceUnavailable("Service under maintenance")
// Not implemented features
case PUT -> Root / "beta-feature" =>
NotImplemented("Feature not yet implemented")
}Status codes for informational responses (less commonly used).
// 1xx Informational Status Codes
val Continue: Status.Continue.type // 100
val SwitchingProtocols: Status.SwitchingProtocols.type // 101
val Processing: Status.Processing.type // 102
val EarlyHints: Status.EarlyHints.type // 103Response generators automatically handle content types and encoding based on the EntityEncoder instances.
import org.http4s.dsl.io._
import org.http4s.circe._
import io.circe.generic.auto._
val routes = HttpRoutes.of[IO] {
// JSON response (with circe EntityEncoder)
case GET -> Root / "api" / "users" =>
val users = List(User("Alice", 25), User("Bob", 30))
Ok(users.asJson) // Content-Type: application/json
// Plain text response
case GET -> Root / "health" =>
Ok("OK") // Content-Type: text/plain
// HTML response
case GET -> Root =>
Ok("<html><body><h1>Welcome</h1></body></html>")
.map(_.withContentType(`Content-Type`(MediaType.text.html)))
}The DSL enables consistent error handling patterns:
import org.http4s.dsl.io._
val routes = HttpRoutes.of[IO] {
case GET -> Root / "users" / IntVar(id) =>
userService.findById(id).flatMap {
case Some(user) => Ok(user.asJson)
case None => NotFound(s"User $id not found")
}.handleErrorWith { error =>
logger.error(s"Error fetching user $id", error)
InternalServerError("Internal server error")
}
}F[_] and entity type information