Odinodin
Odinodin

Reputation: 2177

Parsing integers from strings when validating compojure requests in Clojure

I have compojure based app where I need to parse a request and retrieve parameters that can be numbers. I want to be able to verify that the parameters exist and that they are numbers before actually processing the request. This is what I have so far:

(defn get-int [str]
  "Returns nil if str is not a number"
  (try (Integer/parseInt str)
    (catch NumberFormatException _)))

(defn some-request [request]
    (let [some-number (get-int (get-in request [:route-params :some-number])
         other-number (get-int (get-in request [:route-params :other-number])]
    (if (every? identity [some-number other-number])
        (process-the-request)
        (bad-request "The request was malformed")))

Is there a better way to do string -> number conversion?

Is there a better way to do request validation?

Upvotes: 7

Views: 2204

Answers (2)

Nelo Mitranim
Nelo Mitranim

Reputation: 854

Use Long/parseLong instead of Integer/parseInteger. The latter supports only 32 bits, which is often insufficient; for instance, Datomic entity IDs don't fit into Integer.

Never use read-string for user input. In addition, you must sanitize user input, removing injected scripts and such. https://github.com/alxlit/autoclave is a good start, although the defaults are arguably too aggressive.

Upvotes: 0

raju-bitter
raju-bitter

Reputation: 8996

This question contains good examples for parsing numbers in Clojure. If you are not sure that the string contains a valid number, your approach looks good.

If you can pass the parameters as part of the query string, you could use a route with regex to retrieve the value, e.g.

(GET ["/user/:id", :id #"[0-9]+"] [id] 
  (let [num (read-string id)]
    (str "The number is: " num)))

The route would only match if the regex conditions are met, therefore you could skip the Integer/parseInt check.

Upvotes: 7

Related Questions