[SOLVED] Clojure map returned by JDBC becomes null after inspection

Issue

This Content is from Stack Overflow. Question asked by Will Osborne

I’m writing a simple URL shortener in Clojure, using Ring, Compojure, clojure.java.jdbc and MySQL.

I’m seeing a very strange issue where some inputs seem to randomly become null midway through a function, causing my checks to fail.

My code:

(defn redirect-handler [slug]
  (if (not slug)
    (response/bad-request "Must provide slug."))
  (let [mapping (db/get-slug slug)]
    ;; this passes fine
    (if mapping
      (println (str mapping)))

    ;; this always calls the else case for some slugs, but not others
    (if mapping
      (response/redirect (:url mapping))
      (do
        (println "Not running. Mapping: " mapping)
        (response/not-found (str "Slug not found: " slug))))))

For certain inputs, it always returns 404 with “Slug not found: “. Logs reveal very strange behaviour:

{:slug "eel", :url "eel.com"}
Not running. Mapping:  nil

And the response is 404 with message Slug not found: eel.com – even stranger, since it seems to be returning the url instead of the slug in the response. It’s almost as though the data is being modified midway through the function.

I have already confirmed the data in the database is correct.

My DB code:

(def mysql-db (edn/read-string (slurp "env.edn")))

(def query-slug-sql "SELECT * FROM urls WHERE slug = ?")

(defn get-slug [slug]
  (first (j/query mysql-db [query-slug-sql slug])))

My HTTP routing code:

(defroutes app-routes
  (GET "/:slug" [slug] (redirect-handler slug))
  (GET "/" [] (response/not-found "Must provide slug."))
  (POST "/create" [slug url] (create-handler slug url)))

(def app
  (-> app-routes
      (json/wrap-json-params)
      (json/wrap-json-response)))

Any idea what is happening here?



Solution

I understand your confusion, because given the code you posted, a single call to redirect-handler can’t possibly produce those log messages, no matter what value it receives as argument, and no matter what is returned by db/get-slug. Local variables just can’t change value at all, and there’s no single value in Clojure that goes from truthy to falsey, ever.

I can think of two explanations (maybe there are others):

  1. The code you posted isn’t the code that’s running. Maybe you rewrote the function but didn’t reload it, for example.
  2. The log message isn’t exclusively coming from redirect-handler. Maybe some other function prints the map on line one, and then the second line is the only thing printed by redirect-handler.


This Question was asked in StackOverflow by Will Osborne and Answered by amalloy It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?