1

I make a call to a food api that has a query based off user input.

How can I detect if a user enters a space in their search (ie. if they search for a word like "Whey Protein".

  func searchFood(userItem: String){
       //calls api search
        guard let url = URL(string: "https://api.nal.usda.gov/fdc/v1/foods/search?&api_key=bRbzV****y8cqG&query=\(userItem)") else {return}
        
        URLSession.shared.dataTask(with: url) { (data, _,_) in
            let searchResults = try! JSONDecoder().decode(APISearchResults.self, from: data!)
            
            DispatchQueue.main.async {
                for item in searchResults.foods ?? []{
                   self.foodDescription = item.lowercaseDescription?.firstCapitalized ?? "food not valid"
                    self.calories = String(Double(round(item.foodNutrients?[3].value! ?? 0.00)).removeZerosFromEnd())
                    self.brand = item.brandOwner ?? "General"
                   
                    }
               
                }
        }
        .resume()
    }
jnpdx
  • 45,847
  • 6
  • 64
  • 94
Swink
  • 353
  • 3
  • 26
  • 1
    You should percent escape them (ie replace them with "%20") or in special case depending on your API, they need to be plus sign. Same goes for all "strange" characters (where your `url` will be nil with them). – Larme Apr 17 '22 at 21:27
  • 2
    Side note, you can use `URLQueryItem` to construct your URL. – Larme Apr 17 '22 at 21:27

1 Answers1

1

As @Larme said in their comment, you should use URL encoding to add spaces in URL query items.

To convert an existing string to percent/url encoding, you can use the following snippet (obtained from this SO question):

yourString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)

They also stated that you should use URLQueryItem to construct your URLs and to add to this, I recommend you to use this extension to construct URLs easily.

extension URL {

    /// Adds a query item to a URL
    public func queryItem(_ queryItem: String, value: String?) -> URL {
        guard var urlComponents = URLComponents(string: absoluteString) else { return absoluteURL }
        var queryItems: [URLQueryItem] = urlComponents.queryItems ??  []
        let queryItem = URLQueryItem(name: queryItem, value: value)
        queryItems.append(queryItem)
        urlComponents.queryItems = queryItems
        return urlComponents.url!
    }
    
    /// Retrieves the query items of a URL
    public var queryParameters: [String: String]? {
        guard
            let components = URLComponents(url: self, resolvingAgainstBaseURL: true),
            let queryItems = components.queryItems else { return nil }
        return queryItems.reduce(into: [String: String]()) { (result, item) in
            result[item.name] = item.value
        }
    }

}

And, when constructing your URL, you can use this:

url = url.queryItem("key", value: "value")

References:

Percent-encoding. (2022, March 31). In Wikipedia. https://en.wikipedia.org/wiki/Percent-encoding

zaph & Oleander, L. (2014, July 3). Swift - encode URL. Stack Overflow. Retrieved April 18, 2022, from Swift - encode URL

amodrono
  • 1,900
  • 4
  • 24
  • 45
  • 1
    Thank you for the well thought out response. Quick question, what would the "key" in QueryItem pertain too? This is fairly new to me, so just want to wrap my head around it better. – Swink Apr 18 '22 at 20:18
  • 1
    @SirJames sorry for the late response. Your query parameter is `query=whatever`, so, in your case, the key would be `query`, and the value would be whatever the user has entered. – amodrono Apr 19 '22 at 18:48
  • 1
    gotcha, thank you! – Swink Apr 19 '22 at 19:19
  • @SirJamess no problem! :) – amodrono Apr 19 '22 at 20:07