简体   繁体   中英

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 eg 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?

Alamofire already supports this, you just need to choose a form. Your biggest issue will be accepting a 200 with no data, as that's technically invalid since only 204 or 205 are supposed to be empty.

All Alamofire responses require some sort of payload type, but Alamofire provides an Empty type to fill this role for Decodable . So the simplest way is to use the

await AF.request(...)
        .serializingDecodable(Empty.self, emptyResponseCodes: [200])
        .response

Note, if you already have an Empty type or are importing Combine in the same file as this code, you may need to disambiguate by using Alamofire.Empty .

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)
                }
            }
        }
    }

If Alamofire does not provide a method for your purpose, then you will have wrap the old Alamofire methods that uses closures as below:

    func myRequest() async throws {
        try await withUnsafeThrowingContinuation { continuation in
            myAlamofireRequest {
                continuation.resume()
            }
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM