My agentic slop goes here. Not intended for anyone else!
1(** JSON API Helpers for Requests *)
2
3(** {1 Response Helpers} *)
4
5let read_body response = Requests.Response.body response |> Eio.Flow.read_all
6
7let check_2xx response =
8 let status = Requests.Response.status_code response in
9 let body = read_body response in
10 if status >= 200 && status < 300 then Ok body
11 else Error (status, body)
12
13let check_ok response =
14 let status = Requests.Response.status_code response in
15 let body = read_body response in
16 if status = 200 then Ok body
17 else Error (status, body)
18
19(** {1 Request Helpers with Status Checking} *)
20
21let get_result session url =
22 try
23 let response = Requests.get session url in
24 check_2xx response
25 with exn ->
26 Error (0, Printexc.to_string exn)
27
28(** {1 JSON Helpers} *)
29
30let parse_json decoder body_str =
31 match Jsont_bytesrw.decode_string' decoder body_str with
32 | Ok v -> v
33 | Error e -> failwith (Fmt.str "JSON parse error: %s" (Jsont.Error.to_string e))
34
35let parse_json_result decoder body_str =
36 match Jsont_bytesrw.decode_string' decoder body_str with
37 | Ok v -> Ok v
38 | Error e -> Error (Jsont.Error.to_string e)
39
40let get_json_exn session url decoder =
41 let response = Requests.get session url in
42 let status = Requests.Response.status_code response in
43 if status < 200 || status >= 300 then
44 failwith (Printf.sprintf "HTTP %d" status);
45 read_body response |> parse_json decoder
46
47let get_json session url decoder =
48 match get_result session url with
49 | Ok body ->
50 (match parse_json_result decoder body with
51 | Ok result -> Ok result
52 | Error msg -> Error (`Json_error msg))
53 | Error (status, body) -> Error (`Http (status, body))
54
55let post_json session url jsont_codec value =
56 let body_str = match Jsont_bytesrw.encode_string' jsont_codec value with
57 | Ok s -> s
58 | Error e -> failwith (Fmt.str "JSON encoding error: %s" (Jsont.Error.to_string e))
59 in
60 let body = Requests.Body.of_string Requests.Mime.json body_str in
61 Requests.post session url ~body
62
63let post_json_exn session url jsont_codec value =
64 let response = post_json session url jsont_codec value in
65 let status = Requests.Response.status_code response in
66 if status < 200 || status >= 300 then
67 failwith (Printf.sprintf "HTTP %d" status);
68 read_body response
69
70let post_json_result session url jsont_codec value =
71 try
72 let response = post_json session url jsont_codec value in
73 check_2xx response
74 with exn ->
75 Error (0, Printexc.to_string exn)
76
77let post_json_decode_exn session url ~req req_value ~resp =
78 let response = post_json session url req req_value in
79 let status = Requests.Response.status_code response in
80 if status < 200 || status >= 300 then
81 failwith (Printf.sprintf "HTTP %d" status);
82 read_body response |> parse_json resp
83
84let post_json_decode session url ~req req_value ~resp =
85 try
86 let response = post_json session url req req_value in
87 match check_2xx response with
88 | Ok body ->
89 (match parse_json_result resp body with
90 | Ok result -> Ok result
91 | Error msg -> Error (`Json_error msg))
92 | Error (status, body) -> Error (`Http (status, body))
93 with exn ->
94 Error (`Http (0, Printexc.to_string exn))
95
96let put_json_exn session url jsont_codec value =
97 let body_str = match Jsont_bytesrw.encode_string' jsont_codec value with
98 | Ok s -> s
99 | Error e -> failwith (Fmt.str "JSON encoding error: %s" (Jsont.Error.to_string e))
100 in
101 let body = Requests.Body.of_string Requests.Mime.json body_str in
102 let response = Requests.put session url ~body in
103 let status = Requests.Response.status_code response in
104 if status < 200 || status >= 300 then
105 failwith (Printf.sprintf "HTTP %d" status);
106 read_body response
107
108let put_json_decode_exn session url ~req req_value ~resp =
109 let body_str = match Jsont_bytesrw.encode_string' req req_value with
110 | Ok s -> s
111 | Error e -> failwith (Fmt.str "JSON encoding error: %s" (Jsont.Error.to_string e))
112 in
113 let body = Requests.Body.of_string Requests.Mime.json body_str in
114 let response = Requests.put session url ~body in
115 let status = Requests.Response.status_code response in
116 if status < 200 || status >= 300 then
117 failwith (Printf.sprintf "HTTP %d" status);
118 read_body response |> parse_json resp
119
120let patch_json_exn session url jsont_codec value =
121 let body_str = match Jsont_bytesrw.encode_string' jsont_codec value with
122 | Ok s -> s
123 | Error e -> failwith (Fmt.str "JSON encoding error: %s" (Jsont.Error.to_string e))
124 in
125 let body = Requests.Body.of_string Requests.Mime.json body_str in
126 let response = Requests.patch session url ~body in
127 let status = Requests.Response.status_code response in
128 if status < 200 || status >= 300 then
129 failwith (Printf.sprintf "HTTP %d" status);
130 read_body response
131
132let delete_json_exn session url =
133 let response = Requests.delete session url in
134 let status = Requests.Response.status_code response in
135 if status < 200 || status >= 300 then
136 failwith (Printf.sprintf "HTTP %d" status);
137 read_body response
138
139(** {1 URL Helpers} *)
140
141let ( / ) base path =
142 (* Handle trailing slash in base and leading slash in path *)
143 let base = if String.ends_with ~suffix:"/" base then String.sub base 0 (String.length base - 1) else base in
144 let path = if String.starts_with ~prefix:"/" path then String.sub path 1 (String.length path - 1) else path in
145 base ^ "/" ^ path
146
147let make_url = ( / )
148
149(** {1 Let Syntax for Composition} *)
150
151module Syntax = struct
152 let ( let* ) x f = Result.bind x f
153 let ( let+ ) x f = Result.map f x
154 let ( and* ) a b = match a, b with
155 | Ok a, Ok b -> Ok (a, b)
156 | Error e, _ | _, Error e -> Error e
157 let ( and+ ) = ( and* )
158end
159
160(** {1 Convenience Combinators} *)
161
162let or_fail = function
163 | Ok x -> x
164 | Error (`Http (code, msg)) ->
165 failwith (Printf.sprintf "HTTP %d: %s" code msg)
166 | Error (`Json_error msg) ->
167 failwith (Printf.sprintf "JSON error: %s" msg)
168
169let or_fail_with prefix = function
170 | Ok x -> x
171 | Error (`Http (code, msg)) ->
172 failwith (Printf.sprintf "%s: HTTP %d: %s" prefix code msg)
173 | Error (`Json_error msg) ->
174 failwith (Printf.sprintf "%s: JSON error: %s" prefix msg)