Complete set of HTTP status codes with fluent response generation API. Each status code provides type-safe methods for creating responses with or without bodies, headers, and proper content negotiation.
All HTTP status codes follow a consistent pattern for response generation:
/**
* Base response generator trait
*/
trait ResponseGenerator {
def status: Status
}
/**
* Response generator for responses without body content
*/
trait EmptyResponseGenerator[F[_], G[_]] extends 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]]
}
/**
* Response generator for responses with optional body content
*/
trait EntityResponseGenerator[F[_], G[_]] extends ResponseGenerator {
def liftG: G ~> F
def apply()(implicit F: Applicative[F]): 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]]
}Informational status codes for ongoing request processing.
/**
* 100 Continue - Request headers received, client should send body
*/
val Continue: Status.Continue.type
/**
* 101 Switching Protocols - Server switching to different protocol
*/
val SwitchingProtocols: Status.SwitchingProtocols.type
/**
* 102 Processing - Server received request, still processing
*/
val Processing: Status.Processing.type
/**
* 103 Early Hints - Early metadata before final response
*/
val EarlyHints: Status.EarlyHints.typeUsage Examples:
val routes = HttpRoutes.of[IO] {
case GET -> Root / "status" =>
Continue()
case GET -> Root / "upgrade" =>
SwitchingProtocols()
}Success status codes indicating successful request processing.
/**
* 200 OK - Standard successful response
*/
val Ok: Status.Ok.type
/**
* 201 Created - Resource successfully created
*/
val Created: Status.Created.type
/**
* 202 Accepted - Request accepted for processing
*/
val Accepted: Status.Accepted.type
/**
* 203 Non-Authoritative Information - Successful but from cache/proxy
*/
val NonAuthoritativeInformation: Status.NonAuthoritativeInformation.type
/**
* 204 No Content - Successful request with no response body
*/
val NoContent: Status.NoContent.type
/**
* 205 Reset Content - Successful request, client should reset form
*/
val ResetContent: Status.ResetContent.type
/**
* 206 Partial Content - Partial resource delivered
*/
val PartialContent: Status.PartialContent.type
/**
* 207 Multi-Status - Multiple status codes for WebDAV
*/
val MultiStatus: Status.MultiStatus.type
/**
* 208 Already Reported - WebDAV already reported
*/
val AlreadyReported: Status.AlreadyReported.type
/**
* 226 IM Used - Instance manipulations applied
*/
val IMUsed: Status.IMUsed.typeUsage Examples:
val routes = HttpRoutes.of[IO] {
// Simple responses
case GET -> Root / "hello" =>
Ok("Hello, World!")
case POST -> Root / "users" =>
Created("User created successfully")
// With custom headers
case GET -> Root / "data" =>
Ok("response body", Header.Raw(ci"X-Custom-Header", "custom-value"))
// Empty responses
case DELETE -> Root / "users" / IntVar(id) =>
NoContent()
// JSON responses
case GET -> Root / "users" / IntVar(id) =>
Ok(User(id, "John Doe").asJson)
}Redirection status codes requiring additional client action.
/**
* 300 Multiple Choices - Multiple representation options
*/
val MultipleChoices: Status.MultipleChoices.type
/**
* 301 Moved Permanently - Resource permanently moved
*/
val MovedPermanently: Status.MovedPermanently.type
/**
* 302 Found - Resource temporarily moved
*/
val Found: Status.Found.type
/**
* 303 See Other - Response available at different URI
*/
val SeeOther: Status.SeeOther.type
/**
* 304 Not Modified - Resource not modified since last request
*/
val NotModified: Status.NotModified.type
/**
* 307 Temporary Redirect - Temporary redirect preserving method
*/
val TemporaryRedirect: Status.TemporaryRedirect.type
/**
* 308 Permanent Redirect - Permanent redirect preserving method
*/
val PermanentRedirect: Status.PermanentRedirect.typeUsage Examples:
import org.http4s.headers.Location
import org.http4s.Uri
val routes = HttpRoutes.of[IO] {
// Redirects with Location header
case GET -> Root / "old-path" =>
MovedPermanently(Location(Uri.unsafeFromString("/new-path")))
case POST -> Root / "login" =>
SeeOther(Location(Uri.unsafeFromString("/dashboard")))
// Conditional responses
case req @ GET -> Root / "resource" =>
req.headers.get[`If-Modified-Since`] match {
case Some(since) if !isModifiedSince(since) => NotModified()
case _ => Ok("Resource content")
}
}Client error status codes indicating issues with client requests.
/**
* 400 Bad Request - Invalid request syntax
*/
val BadRequest: Status.BadRequest.type
/**
* 401 Unauthorized - Authentication required
*/
val Unauthorized: Status.Unauthorized.type
/**
* 402 Payment Required - Payment required (reserved)
*/
val PaymentRequired: Status.PaymentRequired.type
/**
* 403 Forbidden - Access denied
*/
val Forbidden: Status.Forbidden.type
/**
* 404 Not Found - Resource not found
*/
val NotFound: Status.NotFound.type
/**
* 405 Method Not Allowed - HTTP method not supported
*/
val MethodNotAllowed: Status.MethodNotAllowed.type
/**
* 406 Not Acceptable - Response format not acceptable
*/
val NotAcceptable: Status.NotAcceptable.type
/**
* 407 Proxy Authentication Required - Proxy authentication needed
*/
val ProxyAuthenticationRequired: Status.ProxyAuthenticationRequired.type
/**
* 408 Request Timeout - Request timeout
*/
val RequestTimeout: Status.RequestTimeout.type
/**
* 409 Conflict - Request conflicts with current state
*/
val Conflict: Status.Conflict.type
/**
* 410 Gone - Resource permanently gone
*/
val Gone: Status.Gone.type
/**
* 411 Length Required - Content-Length header required
*/
val LengthRequired: Status.LengthRequired.type
/**
* 412 Precondition Failed - Precondition in headers failed
*/
val PreconditionFailed: Status.PreconditionFailed.type
/**
* 413 Payload Too Large - Request entity too large
*/
val PayloadTooLarge: Status.PayloadTooLarge.type
/**
* 414 URI Too Long - Request URI too long
*/
val UriTooLong: Status.UriTooLong.type
/**
* 415 Unsupported Media Type - Media type not supported
*/
val UnsupportedMediaType: Status.UnsupportedMediaType.type
/**
* 416 Range Not Satisfiable - Range header cannot be satisfied
*/
val RangeNotSatisfiable: Status.RangeNotSatisfiable.type
/**
* 417 Expectation Failed - Expect header cannot be satisfied
*/
val ExpectationFailed: Status.ExpectationFailed.type
/**
* 421 Misdirected Request - Request directed to wrong server
*/
val MisdirectedRequest: Status.MisdirectedRequest.type
/**
* 422 Unprocessable Entity - Request syntactically correct but semantically invalid
*/
val UnprocessableEntity: Status.UnprocessableEntity.type
/**
* 423 Locked - Resource locked
*/
val Locked: Status.Locked.type
/**
* 424 Failed Dependency - Request failed due to dependency failure
*/
val FailedDependency: Status.FailedDependency.type
/**
* 425 Too Early - Request sent too early
*/
val TooEarly: Status.TooEarly.type
/**
* 426 Upgrade Required - Client must upgrade protocol
*/
val UpgradeRequired: Status.UpgradeRequired.type
/**
* 428 Precondition Required - Precondition header required
*/
val PreconditionRequired: Status.PreconditionRequired.type
/**
* 429 Too Many Requests - Rate limit exceeded
*/
val TooManyRequests: Status.TooManyRequests.type
/**
* 431 Request Header Fields Too Large - Headers too large
*/
val RequestHeaderFieldsTooLarge: Status.RequestHeaderFieldsTooLarge.type
/**
* 451 Unavailable For Legal Reasons - Content blocked for legal reasons
*/
val UnavailableForLegalReasons: Status.UnavailableForLegalReasons.typeUsage Examples:
val routes = HttpRoutes.of[IO] {
// Error responses with messages
case POST -> Root / "users" =>
for {
user <- req.as[User].handleErrorWith(_ => BadRequest("Invalid user data").pure)
result <- createUser(user).handleErrorWith(_ => Conflict("User already exists").pure)
} yield result
// Authentication errors
case GET -> Root / "protected" =>
Unauthorized("""WWW-Authenticate: Bearer realm="api"""")
// Not found
case GET -> Root / "users" / IntVar(id) =>
findUser(id).flatMap {
case Some(user) => Ok(user.asJson)
case None => NotFound(s"User $id not found")
}
// Validation errors
case req @ POST -> Root / "validate" =>
req.as[Data].attempt.flatMap {
case Right(data) => Ok("Valid data")
case Left(_) => UnprocessableEntity("Invalid data format")
}
}Server error status codes indicating server-side issues.
/**
* 500 Internal Server Error - Generic server error
*/
val InternalServerError: Status.InternalServerError.type
/**
* 501 Not Implemented - Server doesn't support functionality
*/
val NotImplemented: Status.NotImplemented.type
/**
* 502 Bad Gateway - Invalid response from upstream server
*/
val BadGateway: Status.BadGateway.type
/**
* 503 Service Unavailable - Server temporarily unavailable
*/
val ServiceUnavailable: Status.ServiceUnavailable.type
/**
* 504 Gateway Timeout - Upstream server timeout
*/
val GatewayTimeout: Status.GatewayTimeout.type
/**
* 505 HTTP Version Not Supported - HTTP version not supported
*/
val HttpVersionNotSupported: Status.HttpVersionNotSupported.type
/**
* 506 Variant Also Negotiates - Content negotiation error
*/
val VariantAlsoNegotiates: Status.VariantAlsoNegotiates.type
/**
* 507 Insufficient Storage - Server out of storage
*/
val InsufficientStorage: Status.InsufficientStorage.type
/**
* 508 Loop Detected - Infinite loop detected
*/
val LoopDetected: Status.LoopDetected.type
/**
* 510 Not Extended - Further extensions required
*/
val NotExtended: Status.NotExtended.type
/**
* 511 Network Authentication Required - Network authentication required
*/
val NetworkAuthenticationRequired: Status.NetworkAuthenticationRequired.typeUsage Examples:
val routes = HttpRoutes.of[IO] {
case GET -> Root / "data" =>
fetchData().handleErrorWith { error =>
error match {
case _: DatabaseConnectionException => ServiceUnavailable("Database temporarily unavailable")
case _: TimeoutException => GatewayTimeout("Request timeout")
case _ => InternalServerError("An unexpected error occurred")
}
}
case GET -> Root / "unsupported" =>
NotImplemented("This endpoint is not yet implemented")
}Some status codes have specialized response generators with additional requirements:
/**
* 401 responses must include WWW-Authenticate header
*/
trait WwwAuthenticateResponseGenerator[F[_], G[_]] extends 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]]
}/**
* 405 responses must include Allow header
*/
trait AllowResponseGenerator[F[_], G[_]] extends 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]]
}/**
* 407 responses must include Proxy-Authenticate header
*/
trait ProxyAuthenticateResponseGenerator[F[_], G[_]] extends ResponseGenerator {
def apply(authenticate: `Proxy-Authenticate`, headers: Header.ToRaw*)(implicit F: Applicative[F]): F[Response[G]]
def apply[A](authenticate: `Proxy-Authenticate`, body: A, headers: Header.ToRaw*)(implicit F: Applicative[F], w: EntityEncoder[G, A]): F[Response[G]]
}/**
* Redirect responses should include Location header
*/
trait LocationResponseGenerator[F[_], G[_]] extends 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]]
}