Search code examples
httpgomux

How do I handle optional query parameters for a Go using Mux properly?


I'm making an API server using GoLang and I am using Mux as the HTTP router. I have one endpoint in my app, /tasks. When I hit that endpoint, I get back an array of results, which is as expected. Now, I want to build upon that and add an optional query parameter into the URL to only return N results, like so: /tasks?num=5 which would only return 5 results. I have accomplished this using the handler below:

    vars := r.URL.Query()
    t := task{}
    if numOfTasksParam, ok := vars["num"]; ok {
        fmt.Printf("%+v", numOfTasksParam[0])
        numOfTasks, err := strconv.Atoi(vars.Get("num"))
        //return only n number of results
    } else {
        //return the entire result set
    }

I devised this solution because I discovered that URL.Query() returns a map of the query parameters and therefore, I can just check to see if that map contained the key of "num". If so, the client wants N number of results. If not, the client must want the whole result set.

The main issue I have with this approach is that when I go to check if the keys exists, I make a temporary variable called numOfTasksParam which holds the query parameter value, but it holds the value as a string and I need a int. Therefore, I must use the numOfTasksParam somehow and then create another variable to convert that to an integer value.

Is there more succinct or convenient way of checking if a query parameter exists in the request URL?


Solution

  • This is probably the most succinct, and works because Get returns an empty string if the parameter isn't set, which Atoi will fail to parse:

    vars := r.URL.Query()
    t := task{}
    if numOfTasks, err := strconv.Atoi(vars.Get("num")); err == nil {
        //return only numOfTasks number of results
    } else {
        //return the entire result set
    }
    

    The price you pay for having less code is that if a user passes an invalid value like ?num=taco, it will be treated as if they passed nothing, rather than telling the user they passed something unusable. This may or may not be what you want. It is also slightly less efficient, because it will run Atoi even if the value is known to be empty.