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)