From 68f478625dbec55c5d78d5896d60016e140150a8 Mon Sep 17 00:00:00 2001
From: Arun Isaac
Date: Thu, 30 Dec 2021 16:43:57 +0530
Subject: kolam: Implement HTTP client.

* kolam/http.scm: Import (srfi srfi-26), (web client), (web
response) and (kolam utils).
(variables->alist, graphql-http-response): New functions.
(graphql-http-get, graphql-http-post): New public functions.
---
 kolam/http.scm | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/kolam/http.scm b/kolam/http.scm
index 2098ef1..9efbd60 100644
--- a/kolam/http.scm
+++ b/kolam/http.scm
@@ -19,13 +19,19 @@
 
 (define-module (kolam http)
   #:use-module (rnrs io ports)
+  #:use-module (srfi srfi-26)
   #:use-module (ice-9 match)
+  #:use-module (web client)
   #:use-module (web request)
+  #:use-module (web response)
   #:use-module (web uri)
   #:use-module (json)
   #:use-module (kolam graphql)
   #:use-module (kolam parse)
-  #:export (graphql-handler))
+  #:use-module (kolam utils)
+  #:export (graphql-handler
+            graphql-http-get
+            graphql-http-post))
 
 (define transcoder
   (make-transcoder (utf-8-codec) 'none 'raise))
@@ -62,3 +68,60 @@ run-server from guile's (web server)."
                                   "query"))
                  (('document operations ...)
                   `(("data" . ,(map evaluator operations))))))))))
+
+(define (variables->alist variables)
+  "Convert VARIABLES into an association list to be embedded into the
+GraphQL request."
+  (map (match-lambda
+         ((key . value)
+          (cons (keyword->symbol key)
+                value)))
+       (pairify variables)))
+
+(define (graphql-http-get uri document . variables)
+  "Send GraphQL query as specified in GraphQL DOCUMENT to graphql
+endpoint URI. The GET HTTP method is used. VARIABLES must be a list of
+variables to send with the query. It must be of the form (name value
+...) where NAME must be a keyword. For example, (#:spam 1 #:ham
+\"bacon\" #:eggs 2)."
+  (call-with-values
+      (cut http-get
+           (string-append uri
+                          "?query="
+                          (uri-encode (scm->graphql-string document))
+                          "&"
+                          "variables="
+                          (uri-encode (scm->json-string
+                                       (variables->alist variables))))
+           #:streaming? #t)
+    graphql-http-response))
+
+(define (graphql-http-post uri document . variables)
+  "Send GraphQL query as specified in GraphQL DOCUMENT to graphql
+endpoint URI. The POST HTTP method is used. VARIABLES must be a list
+of variables to send with the query. It must be of the form (name
+value ...) where NAME must be a keyword. For example, (#:spam 1 #:ham
+\"bacon\" #:eggs 2)."
+  (call-with-values
+      (cut http-post
+           uri
+           #:body (scm->json-string
+                   (cons (cons 'query (scm->graphql-string document))
+                         (match variables
+                           (() '())
+                           (_ (cons 'variables (variables->alist variables))))))
+           #:streaming? #t)
+    graphql-http-response))
+
+(define (graphql-http-response response port)
+  "Return GraphQL response data from HTTP RESPONSE and response body
+read from PORT. Raise errors, if any."
+  (unless (and (>= (response-code response) 200)
+               (< (response-code response) 300))
+    (error "GraphQL query failed with non-2xx status code:"
+           response (get-string-all port)))
+  (let ((response-alist (json->scm port)))
+    (cond
+     ((assoc-ref response-alist "errors")
+      => (cut error "GraphQL query failed with errors:" <>))
+     (else (assoc-ref response-alist "data")))))
-- 
cgit v1.2.3