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)