ResponseHTTP response handling per RFC 9110
This module represents HTTP responses and provides functions to access status codes, headers, and response bodies. Responses support streaming to efficiently handle large payloads.
Caching semantics follow RFC 9111 (HTTP Caching).
(* Check response status *)
if Response.ok response then
Printf.printf "Success!\n"
else
Printf.printf "Error: %d\n" (Response.status_code response);
(* Access headers *)
match Response.content_type response with
| Some mime -> Printf.printf "Type: %s\n" (Mime.to_string mime)
| None -> ()
(* Stream response body *)
let body = Response.body response in
Eio.Flow.copy body (Eio.Flow.buffer_sink buffer)
(* Response automatically closes when the switch is released *)Note: Responses are automatically closed when the switch they were created with is released. Manual cleanup is not necessary.
val src : Logs.Src.tLog source for response operations
val make :
sw:Eio.Switch.t ->
status:int ->
headers:Headers.t ->
body:Eio.Flow.source_ty Eio.Resource.t ->
url:string ->
elapsed:float ->
tmake ~sw ~status ~headers ~body ~url ~elapsed creates a response. Internal function primarily used for caching.
val status_code : t -> intstatus_code response returns the HTTP status code as an integer (e.g., 200, 404).
val ok : t -> boolok response returns true if the status code is in the 2xx success range. This is an alias for Status.is_success.
val header : Header_name.t -> t -> string optionheader name response returns the value of a specific header, or None if not present. Header names are case-insensitive.
Example: header `Content_type response
val header_string : string -> t -> string optionheader_string name response returns the value of a header by string name. Use this when header names come from external sources (e.g., wire format). Header names are case-insensitive.
content_type response returns the parsed Content-Type header as a MIME type, or None if the header is not present or cannot be parsed.
val content_length : t -> int64 optioncontent_length response returns the Content-Length in bytes, or None if not specified or chunked encoding is used.
val location : t -> string optionlocation response returns the Location header value, typically used in redirects. Returns None if the header is not present.
Per Recommendation #19: Conditional Request Helpers (ETag/Last-Modified) RFC 9110 Section 8.8.2-8.8.3
val etag : t -> string optionetag response returns the ETag header value, which is an opaque identifier for a specific version of a resource. Use with Headers.if_none_match for conditional requests. Example: "\"abc123\"" or W/"abc123" (weak validator)
val last_modified : t -> string optionlast_modified response returns the Last-Modified header as a raw string. Format: HTTP-date (e.g., "Sun, 06 Nov 1994 08:49:37 GMT")
val parse_http_date : string -> Ptime.t optionparse_http_date s parses an HTTP-date string (RFC 9110 Section 5.6.7) to Ptime.t. Supports RFC 1123, RFC 850, and ANSI C asctime() formats. Returns None if parsing fails.
This is exposed for use by other modules that need to parse HTTP dates.
last_modified_ptime response parses the Last-Modified header as a Ptime.t. Returns None if the header is not present or cannot be parsed.
val date : t -> string optiondate response returns the Date header (time response was generated).
val expires : t -> string optionexpires response returns the Expires header (HTTP/1.0 cache control). Prefer using cache_control for RFC 9111 compliant caching.
expires_ptime response parses the Expires header as a Ptime.t.
val age : t -> int optionage response returns the Age header value in seconds. The Age header indicates how long the response has been in a cache.
Per Recommendation #17: Response Caching with RFC 7234/9111 Compliance
val cache_control : t -> Cache_control.response optioncache_control response parses and returns the Cache-Control header directives. Returns None if the header is not present.
Example:
match Response.cache_control response with
| Some cc when cc.Cache_control.no_store -> "Do not cache"
| Some cc -> Printf.sprintf "Max age: %d" (Option.get cc.max_age)
| None -> "No cache directives"val cache_control_raw : t -> string optioncache_control_raw response returns the raw Cache-Control header string without parsing. Useful for debugging or custom parsing.
val is_cacheable : t -> boolis_cacheable response returns true if the response may be cached based on its status code and Cache-Control directives. A response is cacheable if no-store is not present and either:
val freshness_lifetime : t -> int optionfreshness_lifetime response calculates how long the response is fresh in seconds, based on Cache-Control max-age or Expires header. Returns None if freshness cannot be determined.
val must_revalidate : t -> boolmust_revalidate response returns true if cached copies must be revalidated with the origin server before use (must-revalidate, proxy-revalidate, or no-cache directive present).
is_stale ~now response returns true if the response's freshness lifetime has expired. Requires the current time as now. Returns false if staleness cannot be determined.
val is_not_modified : t -> boolis_not_modified response returns true if this is a 304 Not Modified response, indicating the cached version is still valid.
val vary : t -> string optionvary response returns the Vary header, which lists request headers that affect the response (for cache key construction).
val vary_headers : t -> string listvary_headers response parses the Vary header into a list of header names. Returns an empty list if Vary is not present.
val url : t -> stringurl response returns the final URL after following any redirects. This may differ from the originally requested URL.
val elapsed : t -> floatelapsed response returns the time taken for the request in seconds, including connection establishment, sending the request, and receiving headers.
val body : t -> Eio.Flow.source_ty Eio.Resource.tbody response returns the response body as an Eio flow for streaming. This allows efficient processing of large responses without loading them entirely into memory.
Example:
let body = Response.body response in
let buffer = Buffer.create 4096 in
Eio.Flow.copy body (Eio.Flow.buffer_sink buffer);
Buffer.contents bufferval text : t -> stringtext response reads and returns the entire response body as a string. The response body is fully consumed by this operation.
val json : t -> Jsont.jsonjson response parses the response body as JSON. The response body is fully consumed by this operation.
Example:
let json = Response.json response in
process_json jsonjsonv codec response parses the response body as JSON and decodes it to a typed value using the provided codec. The response body is fully consumed by this operation.
This is the preferred way to decode JSON responses into typed OCaml values, as it provides type safety and works with custom record types.
Example:
(* Define a codec for your type *)
type user = { name : string; age : int }
let user_codec =
Jsont.Obj.map ~kind:"user" (fun name age -> { name; age })
|> Jsont.Obj.mem "name" Jsont.string ~enc:(fun u -> u.name)
|> Jsont.Obj.mem "age" Jsont.int ~enc:(fun u -> u.age)
|> Jsont.Obj.finish
(* Decode the response to a typed value *)
let user = Response.jsonv user_codec response in
Printf.printf "User: %s, age %d\n" user.name user.ageraise_for_status response raises Eio.Io with Error.Http_error if the response status code indicates an error (>= 400). Returns the response unchanged if the status indicates success (< 400).
This is useful for failing fast on HTTP errors:
let response = Requests.get req url |> Response.raise_for_status in
(* Only reaches here if status < 400 *)
process_success responseval check_status : t -> (t, Error.error) resultcheck_status response returns Ok response if the status code is < 400, or Error error if the status code indicates an error (>= 400).
This provides functional error handling without exceptions, complementing raise_for_status for different coding styles.
Example:
match Response.check_status response with
| Ok resp -> process_success resp
| Error err -> handle_error errPer Recommendation #21: Provides a Result-based alternative to raise_for_status.
val pp : Format.formatter -> t -> unitPretty print a response summary
val pp_detailed : Format.formatter -> t -> unitPretty print a response with full headers
module Private : sig ... endInternal functions exposed for use by other modules in the library. These are not part of the public API and may change between versions.