I'm struggling with making badge requests with Alamofire
and I need help.
I have some ids and with them I need to struct parameters (Dictionary String) and send a GET request with Alamofire
. Everything is fine, but I need to cover the case when ids are above 200, because when they are more than 200, API returns 414 code status (too long URL). So when ids are more than 200 they are separated in chunks. With each chunk I'm making a new request to API. The problem is that I return only the first 200 ids when I call my method. Here is an example:
func request (_ idsDict: [String: [String]], _ idSchema: String, _ completion: @escaping Result<SomeModel, Error>) -> Void {
let chunks = transformEntitiesIdsToChunks(idsDict)
let decoder = JSONDecoder()
chunks.forEach {chunk in
let parameters = constructQueryParams(idsDict, chunk, idSchema, apiKey, clientId)
AF.request(baseURL, parameters: parameters).response { response in
switch response.result {
case .success(let data):
// some error handling for decoding and no data
completion(.success(data.data))
case .failure(let error):
return completion(.failure(error.localizedDescription))
}
}
}
}
// Method wraps AF request in a continuation block and makes sure that the closure from request method returned data or throwed error.
// That way fetching from API becomes async/await and can be used in do/try/catch block.
func getIdsEntities (_ idsDict: [String: [String]], _ idSchema: String) async throws -> [SomeModel] {
return try await withUnsafeThrowingContinuation { continuation in
request(idsDict, idSchema) { result in
switch result {
case .success(let data):
continuation.resume(returning: data)
return
case .failure(let error):
continuation.resume(throwing: error)
return
}
}
}
}
I have tried with recursive functions and with DispatchGroup
but none of them worked. Any help will be appriciated. Thank you in advance.
Thanks to Larme's
comment I was able to find my mistake. When making request to API I was passing the decoded response to the completion closure. To fix this I had to declare an array of model let responses:[SomeModel] = []
and append the decoded result to it. I used let group = DispatchGroup()
so I can wait the requests to execute and have my final array of results and then I used group.notify(queue: .main, execute: {completion(.success(responses))})
to return to the main queue and have my array of completed fetched data. This is now how my code looks like:
private func request (_ idsDict: [String: [String]], _ idSchema: String, _ completion: @escaping APIListResponseClosure<SomeModel>) -> Void {
var responses: [SomeModel] = []
let group = DispatchGroup()
let chunks = transformEntitiesIdsToChunks(idsDict)
let decoder = JSONDecoder()
chunks.forEach {chunk in
group.enter()
let parameters = constructQueryParams(idsDict, chunk, idSchema, apiKey, clientId)
AF.request(baseURL, parameters: parameters).response { response in
switch response.result {
case .success(let data):
// some error handling for decoding and no data
responses.append(data.data)
group.leave()
case .failure(let error):
return completion(.failure(.APIError(error.localizedDescription)))
}
}
}
group.notify(queue: .main, execute: {
print("Ids are fetched")
completion(.success(responses))
})
}
Thanks again to Larme
and I hope I helped someone else with this case.