In my app, I am using the Combine framework to make network requests and it works fine for GET requests. But I am running into this issue with POST requests.
The following code (without Combine) works fine:
let data = ["statusTime": DateFormatter.iso8601Full.string(from: Date())]
let requestBody = try? JSONSerialization.data(withJSONObject: data, options: [])
let baseURL = "my-api.amazonaws.com"
let endpoint = "/my/endpoint"
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = baseURL
urlComponents.path = endpoint
let url = urlComponents.url!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = requestBody
request.addValue(authorizationToken, forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print("error: \(error)")
return
}
print("Response: \((response as! HTTPURLResponse).statusCode)")
}
task.resume()
I get a 200 response code from the above code.
The same code with Combine:
let data = ["statusTime": DateFormatter.iso8601Full.string(from: Date())]
let requestBody = try? JSONSerialization.data(withJSONObject: data, options: [])
let baseURL = "my-api.amazonaws.com"
let endpoint = "/my/endpoint"
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = baseURL
urlComponents.path = endpoint
let url = urlComponents.url!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = requestBody
request.addValue(authorizationToken, forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let cancellable = URLSession.shared
.dataTaskPublisher(for: request)
.print()
.sink(receiveCompletion: {
if let error = $0.error {
print("Failure: \(error)")
}
}, receiveValue: {
print("\($0)")
})
Here is the output I receive:
receive subscription: (DataTaskPublisher)
request unlimited
receive cancel
Seems like the request with the Combine framework is somehow getting cancelled? I used a network tracing app and I can see the first request (without Combine), but not the second request.
I have looked at numerous posts and documentation, but can't see what's wrong with my code. What am I missing? Thanks in advance.
I see you are creating the cancellable
, but are you keeping a strong reference to it? It looks like you are creating the request, and then the cancellable goes out of scope and is deallocated, which cancels the request.
Declare something like this in your class:
var cancellables = Set<AnyCancellable>()
and then you implicitly store the cancellable as:
URLSession.shared // You don't hold on to the returned cancellable here
.dataTaskPublisher(for: request)
.print()
.sink(receiveCompletion: {
if let error = $0.error {
print("Failure: \(error)")
}
}, receiveValue: {
print("\($0)")
})
.store(in: &cancellables) // This puts the cancellable into the variables so it stays in scope