-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgoogle_http.ml
75 lines (67 loc) · 2.2 KB
/
google_http.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
(*
Utilities to deal with HTTP response statuses obtained from
Google APIs.
*)
open Printf
open Lwt
let map (x : _ Google_auth.retriable) f : _ Google_auth.retriable =
match x with
| `Retry_unauthorized -> `Retry_unauthorized
| `Retry_later -> `Retry_later
| `Result y -> `Result (f y)
(*
General-purpose function to convert an HTTP response status
into either an instruction to retry (Retry_later, Retry_unauthorized)
or proceed further and produce a result or an exception.
*)
let retriable status continue : _ Google_auth.retriable Lwt.t =
match status with
| `Unauthorized (* 401 *) -> return `Retry_unauthorized
| `Too_many_requests (* 429 *)
| `Internal_server_error (* 500 *)
| `Bad_gateway (* 502 *)
| `Service_unavailable (* 503 *)
| `Gateway_timeout -> return `Retry_later
| _ ->
continue () >>= fun result ->
return (`Result result)
(*
Raise an appropriate exception based on the HTTP response status.
This is meant to be called very last when acceptable statuses
such as 200 OK or 404 Not Found have already been handled.
*)
let fail call_name status body =
let error_fun msg =
match status with
| `Bad_request (* 400 *) ->
Http_exn.internal_error msg
| `Forbidden (* 403 *) ->
(* TODO: inspect response and determine whether it's retriable;
Gmail API seems to be using code 429 rather than 403
for their rateLimitExceeded error. *)
Http_exn.forbidden `Google_access_forbidden msg
| `Not_found (* 404 *) ->
Http_exn.not_found `Google_not_found msg
| _ ->
Http_exn.internal_error msg
in
let message =
sprintf "%s: %s: %s"
call_name
(Cohttp.Code.string_of_status status)
body
in
error_fun message
(*
Run an HTTP request to Google, transparently retried
if one of the retriable response status is obtained.
This should always be used in place of Google_auth.request unless
no retries are desired.
*)
let request token_store user_key http_call_with_token =
Google_auth.request token_store user_key (fun token ->
http_call_with_token token >>= fun ((status, header, body) as result) ->
retriable status (fun () ->
return result
)
)