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?
I understand your confusion, because given the code you posted, a single call to
redirect-handlercan't possibly produce those log messages, no matter what value it receives as argument, and no matter what is returned bydb/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):
redirect-handler. Maybe some other function prints the map on line one, and then the second line is the only thing printed byredirect-handler.