Number : 003, Date: 2025-01-20

2025.01.14 ~ 2025.01.19

🛜 Precautions for Query Parameter Arrays and Task Usage


I worked on adding two new APIs to an existing project. During this process, I learned two important points to keep in mind.

Query Parameter

The HTTP method used was GET, and one of the parameters was received as an array.While designing the API request using the async & await syntax, I passed an array type directly to the URLQueryItem value in Swift. However, it didn’t return an appropriate response due to brackets in the URL.

It turns out that if the server can recognize brackets, it works fine, but if not, the issue can be resolved by using a comma-separated value or by passing the same key multiple times.In the Alamofire library, this conversion is either automated or can be adjusted through additional encoding settings.

❎
let nameList = ["James", "Tom"]
let queryParam = URLQueryItem(name: "nameList", value: nameList)

🅾️
let nameList = ["James", "Tom"]
let commaFormatNameList = nameList.joined(separator: ",")
let queryParam = URLQueryItem(name: "nameList", value: commaFormatNameList)

🅾️
let nameList = ["James", "Tom"]
let queryParam = nameList.map { URLQueryItem(name: "nameList", value: $0) }

Although the server’s API documentation specifies data types like Number and Array, ultimately all query parameters are received as Strings.The KakaoSDK includes an extension function that converts a [String: Any] type to [URLQueryItem]. This function converts all values to Strings for the same reason.

//  Copyright 2019 Kakao Corp.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
extension Dictionary {
    public var queryParameters: String {
        var parts: [String] = []
        for (key, value) in self {
            let part = String(format: "%@=%@",
                              // ! optional unwrapping [ ]
                              String(describing: key).addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!,
                              // ! optional unwrapping [ ]
                              String(describing: value).addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)
            parts.append(part as String)
        }
        return parts.joined(separator: "&")
    }
    
    public var urlQueryItems: [URLQueryItem]? {        
        let queryItems = self.map { (key, value) in
            URLQueryItem(name: String(describing: key),
                         value: String(describing: value))
        }
        return queryItems
    }
}

Task

While working on APIs using the async & await syntax, I made a mistake where the code to execute after the asynchronous Task was placed outside the Task block, causing it to not function correctly.

As expected, extra caution is necessary when using Task.

// Correct Behavior:  
// `requestMember` is called -> `requestMemberDetail` is called  

❎
// `requestMemberDetail` is called -> `requestMember` is called  
Task {
		let response = await requestMember()
		print(response)
}

requestMemberDetail()

🅾️
// `requestMember` is called -> `requestMemberDetail` is called  
Task {
		let response = await requestMember()
		print(response)
		requestMemberDetail()
}

🙋🏻‍♂️ Other Notes


  1. I came across OnyX, an open-source program for maintaining and optimizing the OS. After installing and using it, I noticed that someone had contributed a Korean translation, and it is well-localized in Korean. When cleaning, it’s important to carefully review the options as many of them are enabled by default and could delete unintended files.