Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by
retagged by

It's been a while since I've written Clojure, so I am rusty.

Basically, I'm trying to write code which does an HTTP GET on a REST API and converts that JSON array of objects into clojure data (list of Maps?). The JSON data looks like this:

        "id": 1,
        "category": "technical",
        "asin": "0131103628",
        "title": "C Programming Language, 2nd Edition",
        "publication_date": "1988-04-01T00:00:00Z",
        "review": "The C book.",
        "created_at": "2020-03-06T20:48:00Z"
        "id": 2,
        "category": "technical",
        "asin": "0387966080",
        "title": "The Science of Fractal Images",
        "publication_date": "1988-07-19T00:00:00Z",
        "review": "The book on fractal algorithms.  Sadly, no longer in print.  I had to search high and low for a used copied.",
        "created_at": "2020-03-06T20:48:00Z"
    // etc..

I'm using http-kit (I've also tried clj-http) to call the REST API and return the body. Later, I try converting the body to Clojure data. I've tried using both org.clojure/data.json and cheshire. However, I don't belive the data is being converted correctly.

(defn get-books-body
  (:body @(client/get books-url api-options)))

(defn get-books
  (parse-string get-books-body true))

When I try to display the type of the body, it shows up as an address instead of a string:

clojure-json-test.core=> (type get-books-body)

And I cannot look at the first record, after converting from JSON:

clojure-json-test.core=> (first get-books)
Execution error (IllegalArgumentException) at clojure-json-test.core/eval3169 (form-      init15378865171954877190.clj:1).
Don't know how to create ISeq from: clojure_json_test.core$get_books

Any idea what I am doing wrong?

1 Answer

0 votes
selected by
Best answer

In your examples you are applying type and first to the function objects get-books- body and get-books respectively, instead of invoking the functions.

The same problem exists in the get-books definition, where you are not passing a string to parse-string, but the function object referenced by the get-books-body var. Function objects are actually valid data in clojure, so this is all legal (which is why the type of the function is clojure_json_test.core$get_books_body (it's the class that implements the clojure function in this namespace), and why trying to apply first to the function object (instead of the hopefully parsed JSON sequence result invoking the function would yield), fails, since clojure functions do not implement sequence protocols.

I would change get-books to actually invoke the function to get the string result:

(defn get-books
 (parse-string (get-books-body) true))

and then similarly try the tests using function invocations:

(type  (get-books-body))
(first (get-books))
Thanks! I'm glad it was something simple.  I guess in my absence from Clojure, I forgot functions need to wrapped in parentheses.