如何使用Moya调用含数组查询参数的GET API并解决URL编码问题?
To properly call your target API and resolve the URL encoding issue, we'll complete the MyApiTarget enum with the right parameter handling and encoding. Here's the step-by-step implementation:
1. Complete the MyApiTarget Enum
This implementation converts the types array to a JSON string (to match your API's expected format) and uses Moya's built-in URLEncoding to ensure proper URL encoding of the query parameters.
import Moya enum MyApiTarget: TargetType { case getInfo(contactID: Int, types: [String]) // Base URL (common for all endpoints, no need for switch) public var baseURL: URL { URL(string: "http://some.environment.com/some/api")! } // Path with contactID interpolated public var path: String { switch self { case .getInfo(let contactId, _): return "/some/contacts/\(contactId)" } } // HTTP method is GET for this endpoint public var method: Method { .get } // Task handling: Convert types array to JSON string and add as query parameter public var task: Task { switch self { case .getInfo(_, let types): // Serialize the types array into a JSON string guard let jsonData = try? JSONSerialization.data(withJSONObject: types), let typesParam = String(data: jsonData, encoding: .utf8) else { // Fallback if serialization fails (unlikely for string arrays) return .requestPlain } // Pass the JSON string as the value for the "types" query parameter return .requestParameters( parameters: ["types": typesParam], encoding: URLEncoding.queryString // Explicitly use query string encoding for GET ) } } // Optional headers (adjust based on your API requirements) public var headers: [String: String]? { ["Accept": "application/json"] } // Optional sample data for testing (can be customized) public var sampleData: Data { Data() } }
2. Why This Fixes the URL Encoding Issue
By default, Moya/Alamofire encodes arrays in query parameters as multiple key-value pairs (e.g., types[]=details&types[]=permissions), which doesn't match your API's expected format (types=["details", "permissions"]).
The key fix here is:
- We first convert the
typesarray into a JSON string usingJSONSerialization. - We then pass this string as a single parameter value, which
URLEncodingproperly encodes into a valid query string (e.g.,types=%5B%22details%22%2C%20%22permissions%22%5D), which is the URL-safe version of your target parameter.
3. Using the Target to Make the Request
Once the enum is defined, you can use a MoyaProvider to send the request:
// Initialize the provider let provider = MoyaProvider<MyApiTarget>() // Make the request provider.request(.getInfo(contactID: 81193, types: ["details", "permissions"])) { result in switch result { case .success(let response): // Handle successful response do { // Parse the response (adjust based on your API's response format) let jsonResponse = try response.mapJSON() print("Success: \(jsonResponse)") } catch { print("Failed to parse response: \(error)") } case .failure(let error): // Handle error (network issues, HTTP errors, etc.) print("Request failed: \(error.localizedDescription)") } }
Notes
- Error Handling: The JSON serialization step uses
try?for simplicity, but in production code, you might want to add proper error handling for edge cases (though serialization of a string array should always succeed). - Custom Headers: Adjust the
headersproperty to include any required headers (e.g., authorization tokens, content types) as per your API's documentation. - Non-Standard Encoding: If your API expects the unencoded JSON array in the query string (not recommended), you could create a custom
ParameterEncodingthat skips encoding the parameter value. However, this can lead to invalid URLs and is not standard practice.
内容的提问来源于stack exchange,提问作者sagarkothari

