Search code examples
iosswiftalamofire

How to async await empty response using Alamofire


I have an API where I PUT stuff to. I need to make sure to wait until I get an http 200 response from the server, but I don't know how to await that using Alamofire because my response itself if empty. So it's just an http 200 with no content.

I only can find async functions that e.g. serialize a String or Data or a Decodable, but they don't work if my response is empty.

Is there a way to await something like that in Alamofire?


Solution

  • I know that your question is about async/await from Alamofire, but is good to know that the http status codes 204 and 205 are exactly for this. Which means that if you have access to the server code you could send the empty responses with the http status code 204 and 205 instead of 200 and then Alamofire would not generate any errors. But assuming you don't have access to the server code and you need to parse an empty response as correct then you could use the following code:

    func testRequestWithAlamofire() {
            let dataResponseSerializer = DataResponseSerializer(emptyResponseCodes: [200, 204, 205]) // Default is [204, 205] so add 200 too :P
            
            AF.request("http://www.mocky.io/v2/5aa696133100001335e716e0", method: .put).response(responseSerializer: dataResponseSerializer) { response in
                switch response.result {
                    case .failure(let error):
                        print(error)
                    case .success(let value):
                        print(value)
                }
            }
        }
    

    And for a real and complete example of how async/await from Alamofire or any other async context look this code:

    // This function get report from API and save to a local JSON to be readed by the app
        func updateReport() {
            Task {
                
                guard let session = self.sessionRepository.getSession(WithUser: Defaults.lastLoggedUsername!) else { return }
                guard let company = session.profile?.companies.first else { return }
                self.apiManager.configure(WithToken: session.accessToken)
                
                do {
                    let dateA = Date().dateAtStartOf(.year)
                    //let dateB = Date().dateAtEndOf(.month)
                    let dateB = Date() // Just now
                    
                    let report = try await self.apiManager.report(CompanyId: company._id, DateA: dateA, DateB: dateB, ChartPeriodicity: .month)
                    
                    self.currentReport = report
                    
                    // Save data to disk to be read later
                    self.reportManager.saveReportToDisk(report: report!, withProfileId: session.profile!._id)
                } catch {
                    print("Error getting report: \(error)")
                }
            }
        }
    
    // Get personal report from a given date range
        func report(CompanyId companyId: String, DateA dateA: Date, DateB dateB: Date, ChartPeriodicity chartPeriodicity: ChartPeriodicity) async throws -> CDReport? {
            try await withCheckedThrowingContinuation { continuation in
                self.contappApi.request(.report(companyId: companyId, dateA: dateA, dateB: dateB, chartPeriodicity: chartPeriodicity)) { result in
                    switch result {
                    case let .success(response):
                        // Check status code
                        guard response.statusCode == 200 else {
                            continuation.resume(throwing: ContappNetworkError.unexpected(code: response.statusCode))
                            return
                        }
                        
                        // Decode data
                        do {
                            //let report = try JSONDecoder().decode(CDReport.self, from: response.data)
                            let report = try CDReport(data: response.data)
                            continuation.resume(returning: report)
                        } catch {
                            continuation.resume(throwing: ContappNetworkError.cantDecodeDataFromNetwork)
                        }
                        
                    case .failure(_):
                        continuation.resume(throwing: ContappNetworkError.networkError)
                    }
                }
            }
        }