Commit9776bfb1Recorded29 Mar 2026Repositorysigil-twitch

Use shared API client helpers from (sigil http client)

Message

Replace local twitch-api-url, build-repeated-params, ensure-list, check-twitch-response, and check-twitch-response/raw with shared abstractions from (sigil http client) and (sigil http).

Changed
 src/twitch.sgl | 59 ++++++++++++++++-------------------------------------------
 1 file changed, 16 insertions(+), 43 deletions(-)
Diff
src/twitch.sglmodified
@@ -13,7 +13,8 @@
13
(sigil string)
14
(sigil struct)
15
(sigil json)
−16
(only (sigil http) url-encode-value build-query-string)
+16
(only (sigil http) url-encode-value build-query-string
+17
build-repeated-params ensure-list)
18
(sigil http client))
19
20
(export ;; Client
@@ -135,57 +136,29 @@
136
client-id: (twitch-client-client-id client) })
137
138
(define (twitch-api-url client . parts)
−138
(apply string-append (twitch-client-base-url client)
−139
(map (lambda (p) (string-append "/" p)) parts)))
+139
(apply build-api-url (twitch-client-base-url client) parts))
140
141
−142
;;; Build repeated query params for Twitch-style multi-value parameters.
−143
;;; e.g., (build-repeated-params "id" '("1" "2")) => "id=1&id=2"
−144
(define (build-repeated-params key values)
−145
(string-join
−146
(map (lambda (v) (string-append key "=" (url-encode-value v))) values)
−147
"&"))
−148
−149
;;; Normalize a value to a list — if already a list, return as-is;
−150
;;; if a string, wrap in a single-element list.
−151
(define (ensure-list v)
−152
(if (string? v) (list v) v))
+142
;;; Response checker with Twitch-specific error context.
+143
(define check-twitch-response
+144
(make-response-checker
+145
name: "Twitch API"
+146
handlers: (list
+147
(cons 401 "Access token may be expired or invalid.")
+148
(cons 403 "Insufficient permissions or missing scope.")
+149
(cons 429 "Check Ratelimit-Reset header and retry."))))
150
151
;;; Check an HTTP response for errors and return the raw body string.
−155
;;; Raises Twitch-specific errors for 401/403/429/4xx status codes.
+152
;;; Unlike check-twitch-response, returns unparsed body on success.
153
(define (check-twitch-response/raw response)
154
(if (not (http-response? response))
155
(error "Twitch API request failed: no response"))
156
(let ((status (http-response-status response))
157
(body (http-response-body response)))
−161
(cond
−162
((= status 401)
−163
(error (string-append
−164
"Twitch API 401 Unauthorized. "
−165
"Access token may be expired or invalid. "
−166
"Response: " (or body ""))))
−167
((= status 403)
−168
(error (string-append
−169
"Twitch API 403 Forbidden. "
−170
"Insufficient permissions or missing scope. "
−171
"Response: " (or body ""))))
−172
((= status 429)
−173
(error (string-append
−174
"Twitch API 429 rate limited. "
−175
"Check Ratelimit-Reset header and retry. "
−176
"Response: " (or body ""))))
−177
((>= status 400)
−178
(error (string-append
−179
"Twitch API error " (number->string status) ": "
−180
(or body ""))))
−181
(else body))))
−182
−183
;;; Check an HTTP response and return parsed JSON.
−184
(define (check-twitch-response response)
−185
(let ((body (check-twitch-response/raw response)))
−186
(if (and body (not (string=? body "")))
−187
(json-decode body)
−188
#t)))
+158
(if (>= status 400)
+159
;; Delegate to standard checker for error handling
+160
(check-twitch-response response)
+161
body)))
162
163
;;; Authenticated JSON GET request.
164
(define (twitch-get/json client url)