I now have a single module api.scm
for everything API related. It builds URIString
from base URI and fields, creates URI objects, creates HTTP requests and can execute them (error handling is still not implemented). It was all easy and good. The tests are still in the same file, and thus run automatically whenever the file is imported onto another module (Python has, for example, the
if __name__ == "__main__":
unittest.main()
pattern). This is easily solved by placing the tests in another file (although it goes a bit against the How To Design Programs workflow).
On the other module, record-info.scm
, I'll put all the logic to create record-info
objects from API requests data. Since I don't want to run the HTTP request at every single development test, I'll load a dummy JSON from a file.
(define TEST-JSON-FILE "test-api-response.json")
; if test-file doesn't exist, loads the json response into a variable
(if (not (file-exists? TEST-JSON-FILE))
[(save-obj-to-file snatched-response TEST-JSON-FILE)
(define snatched-response (get-response-from-endpoint SNATCHED-URI-WITH-FIELDS))
(display "Created the json-response file!\n")]
[(define snatched-response (read-json TEST-JSON-FILE))
(display "json-response file existed!\n")])
This conditional definition is not possible, because the definition is not being done at the top-level; but the solution is so simple, it embarasses me. 🤦
; if test-file doesn't exist, loads the json response into a variable
(define snatched-response
(if (not (file-exists? TEST-JSON-FILE))
[(display "Created the json-response file!\n")
(let ((snatched-response (get-response-from-endpoint SNATCHED-URI-WITH-FIELDS)))
(save-obj-to-file snatched-response TEST-JSON-FILE))]
[(display "json-response file existed!\n")
(get-response-from-endpoint SNATCHED-URI-WITH-FIELDS)]))
But there were more issues with how I defined the consecutive instructions; since [
is the same as (
, the if
is doing, say, a double call, and that is not good. It is solved by using the begin
syntax.
; if test-file doesn't exist, loads the json response into a variable
(define snatched-api-object
(if (not (file-exists? TEST-JSON-FILE))
(begin (display "test file created!\n")
(let ((snatched-response (get-response-from-endpoint SNATCHED-URI-WITH-FIELDS)))
(save-obj-to-file snatched-response TEST-JSON-FILE)))
(begin (display "test file loaded!\n")
(with-input-from-file TEST-JSON-FILE read-json))))
And even the above code has a mistake in the if/then/otherwise
block; the then
block needs to have snatched-response
as the final expression inside the let
; otherwise, the result of (save-obj-to-file snatched-response TEST-JSON-FILE)
would be evaluated. So, and with better formatting,
; if test-file doesn't exist, loads the json response into a variable
(define snatched-api-object
(if (not (file-exists? TEST-JSON-FILE))
(begin
(print "test file created!")
(let ((snatched-response (get-response-from-endpoint SNATCHED-URI-WITH-FIELDS)))
(save-obj-to-file snatched-response TEST-JSON-FILE)
snatched-response))
(begin
(print "test file loaded!\n")
(with-input-from-file TEST-JSON-FILE read-json))))
Oof! I've been at this for so long and it feels like nothing was done. But the file structure improved, I added some tests, and this second file is now working with data loaded from a json. This is nice; I'm still learning the language/syntax/procedures, so the slower pace is expected.
Of course, the code above can be abstracted to check for any file, and to retrieve the content from a given endpoint if the file is not found.
(define SNATCHED-URI-WITH-FIELDS
(build-uri-with-fields SNATCHED-URI
(list (list "id" (number->string USER-ID))
(list "type" "snatched")
(list "limit" (number->string NBR-OF-SNATCHES)))))
(define GROUP-URI-WITH-ID-1234
(build-uri-with-fields GROUP-URI
(list (list "id" (number->string 1234)))))
; if test-file doesn't exist, loads the json response from a route into a variable
; intarweb#uri -> intarweb#response
(define (load-or-create-test-file test-file api-route)
(if (not (file-exists? test-file))
(begin
(print "test file " test-file " created!")
(let ((api-response (get-response-from-endpoint api-route)))
(save-obj-to-file api-response test-file)
api-response))
(begin
(print "test file " test-file " loaded!")
(with-input-from-file test-file read-json))))
(define snatched-response (load-or-create-test-file TEST-SNATCHED-FILE SNATCHED-URI-WITH-FIELDS))
(define grouprecord-response (load-or-create-test-file TEST-GROUPRECORD-FILE GROUP-URI-WITH-ID-1234))