0

As part of a network layer for a specific API call, we have a function which builds a required URL. As part of this we have an array of query items e.g.:

component?.queryItems = [
                URLQueryItem(name: "name", value: name),
                URLQueryItem(name: "age", value: age),
                URLQueryItem(name: "gender", value: gender),
                URLQueryItem(name: "nextOfKin", value: nextOfKin)
            ]

These items are always present and non optional. We then have a bunch of optional items which we unwrap and spend to the query array if they are present and not empty. For example:

if let urlQuery, !urlQuery.isEmpty {
                component?.appendQueryItem(param: "url", value: urlQuery)
            }

            if let searchText, !searchText.isEmpty {
                component?.appendQueryItem(param: "text", value: searchText)
            }
          
            if let filterTerm, !filterTerm.isEmpty {
                component?.appendQueryItem(param: "filter", value: filterTerm)
            }

Here is the appendQueryItem method which is part of an extension to URLComponents:

mutating public func appendQueryItem(param: String, value: String) {
        var queryItems: [URLQueryItem] = self.queryItems ?? [URLQueryItem]()
        queryItems.append(URLQueryItem(name: param, value: value))
        self.queryItems = queryItems
    }

However, we have a predefined order in which we want params to be added to the url:

urlQuery searchText name age filterTerm gender nextOfKin

With this in mind, I'm wondering what would be the cleanest way to approach this to ensure the correct order is followed.

I had considered something like:

component?.queryItems = [
                    URLQueryItem(name: "urlQuery", value: urlQuery?.isEmpty == false ? urlQuery : nil),
                    URLQueryItem(name: "searchText", value: searchText?.isEmpty == false ? searchText : nil),
                    URLQueryItem(name: "name", value: name),
                    URLQueryItem(name: "age", value: age),
                    URLQueryItem(name: "filterTerm", value: filterterm?.isEmpty == false ? filterTerm : nil),
                    URLQueryItem(name: "gender", value: gender),
                    URLQueryItem(name: "nextOfKin", value: nextOfKin)
                ].compactMap { $0 }

This works, but it is quite messy and we also try to avoid conditionally unwrapping bools like this i.e. we would preferably have:

if let searchText, !searchText.isEmpty {}

I'd also like to avoid inserting these at a specified index as this will easily break in the future if any further params are added.

DevB1
  • 1,235
  • 3
  • 17
  • 43
  • Why is this order important? In a GET request the query of an URL is treated as dictionary, the values are retrieved by key. – vadian Feb 08 '23 at 17:17
  • It's a specific request regarding increasing our cache hit rate. It seems that the structure of the url and order of the params has an impact – DevB1 Feb 08 '23 at 17:20
  • `let order = ["urlQuery", "searchText", etc]`, and sort the items against it ? See https://stackoverflow.com/questions/43056807/sorting-a-swift-array-by-ordering-from-another-array – Larme Feb 08 '23 at 17:30
  • @Larme this looks interesting - thanks I'll give it a whirl and let you know if it does the job – DevB1 Feb 08 '23 at 17:32

0 Answers0