A batteries included HTTP/1.1 client in OCaml
at main 117 lines 3.4 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** HTTP Link header parsing per RFC 8288 7 8 This module parses Link headers commonly used for: 9 - API pagination (rel="next", "prev", "first", "last") 10 - Resource discovery 11 - Relationship navigation 12 13 Per Recommendation #19: Parse Link headers for pagination support. 14 15 {2 Example: Following Pagination} 16 {[ 17 let rec fetch_all_pages session url acc = 18 let response = Requests.get session url in 19 let data = Response.body response |> Eio.Flow.read_all in 20 let acc = data :: acc in 21 match Link.next_url (Response.headers response) with 22 | Some next -> fetch_all_pages session next acc 23 | None -> List.rev acc 24 ]} 25 26 {2 Example: Getting All Pagination URLs} 27 {[ 28 let response = Requests.get session "https://api.example.com/items" in 29 let (first, prev, next, last) = Link.pagination (Response.headers response) in 30 match next with 31 | Some url -> Printf.printf "Next page: %s\n" url 32 | None -> print_endline "No more pages" 33 ]} 34*) 35 36(** A parsed Link header entry *) 37type t 38 39(** {1 Constructors} *) 40 41val make : 42 uri:string -> 43 ?rel:string -> 44 ?title:string -> 45 ?media_type:string -> 46 ?hreflang:string -> 47 ?params:(string * string) list -> 48 unit -> t 49(** Create a link value *) 50 51(** {1 Accessors} *) 52 53val uri : t -> string 54(** The target URI *) 55 56val rel : t -> string option 57(** The relation type (e.g., "next", "prev", "last", "self") *) 58 59val title : t -> string option 60(** Human-readable title *) 61 62val media_type : t -> string option 63(** Media type hint (from "type" parameter) *) 64 65val hreflang : t -> string option 66(** Language hint *) 67 68val params : t -> (string * string) list 69(** Additional parameters not covered by standard accessors *) 70 71(** {1 Parsing} *) 72 73val parse : string -> t list 74(** Parse a Link header value into a list of links. 75 Handles multiple comma-separated links. *) 76 77val from_headers : Headers.t -> t list 78(** Extract and parse Link header from response headers. 79 Returns empty list if no Link header present. *) 80 81(** {1 Finding Links} *) 82 83val find_rel : string -> t list -> t option 84(** Find the first link with a specific relation type *) 85 86val filter_rel : string -> t list -> t list 87(** Find all links with a specific relation type *) 88 89(** {1 Pagination Helpers} *) 90 91val pagination : Headers.t -> string option * string option * string option * string option 92(** [pagination headers] extracts pagination links. 93 Returns [(first, prev, next, last)] where each is optional. 94 95 Looks for links with rel="first", rel="prev", rel="next", rel="last". *) 96 97val has_next : Headers.t -> bool 98(** Check if there are more pages (next link exists) *) 99 100val next_url : Headers.t -> string option 101(** Get the next page URL if available *) 102 103val prev_url : Headers.t -> string option 104(** Get the previous page URL if available *) 105 106(** {1 Formatting} *) 107 108val pp : Format.formatter -> t -> unit 109(** Pretty-print a link in Link header format *) 110 111val to_string : t -> string 112(** Convert link to string representation *) 113 114(** {1 Logging} *) 115 116val src : Logs.Src.t 117(** Log source for link parsing operations *)