Introduction | raywenderlich.com


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/10376245-networking-with-urlsession/lessons/33

Awesome examples using combine. I did not know that I could use compactMap the way you demonstrated. I also liked how you used Publishers.zip and flapMap. When I have used zip in the past, I would use something this this example.

let pubisher1 = URLSession…
let publisher2 = URLSession…

Then I would write: publisher1.zip(publisher1)…

Publishers.zip(publisher1, publisher2) just reads better.

Instead of flatMap, I had been using tryMap and adding the secondary call in there. I am so excited to see other examples of Combine methodologies to enhance my understanding to make better use of the Library.

1 Like

@fweissi Really glad you like it! Cheers! :]

Hi,
I just watched this lesson and have a question. At the begging of the video you said that authorization challenges are resolved in URLSessionDelegate in appropriate methods. However in the example you just manually inject authorization HTTP header value into the URLRequest. What is the reason for that? Additionally “authorization” header is listed by Apple as Reserved HTTP Header which shouldn’t be manually modified. So basically your example is against Apple’s recommendations.

The tutorials are well paced and detailed with good amount of code to practice on. I tried to modify one of example on authentication into code using Combine but am getting the error “Generic parameter T could not be inferred”.

Basically I am trying to use auth token output of one publisher and create another publisher to give out URLRequest like this:

let acronymrequestpublisher = tokenpublisher
.map { token in
var urlrequest = URLRequest(url:acronymurl)
return urlrequest
}

But this is giving the generic parameter T could not be found error. I do not see any error if I simply return created URLRequest in same line like this:
let acronymrequestpublisher = tokenpublisher
.map { token in
return URLRequest(url:acronymurl)
}

Any reason why Swift compiler is not able to infer T in first place?

Hey there,

If the Swift compiler is having issues with inferring the type, you can help it out by specifying the return value. Try this instead:

let acronymrequestpublisher = tokenpublisher
.map { token -> URLRequest in
  return URLRequest(url:acronymurl)
}

I hope that helps!

Thanks, that helped.

I am able to successfully re-create the authentication example code using Combine. Pasting part of code below for others:

guard let loginurl = loginEndpoint else {
fatalError()
}

guard let acronymurl = newEndpoint else {
fatalError()
}

let loginstring = “(user.email):(user.password)”
guard let logindata = loginstring.data(using: .utf8) else {
fatalError()
}

let encodedstring = logindata.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0))
var urlrequest = URLRequest(url: loginurl)
urlrequest.httpMethod = “POST”
urlrequest.allHTTPHeaderFields = [
“accept”:“application/json”,
“content-type”:“application/json”,
“authorization”:“Basic (encodedstring)”
]

//Create first publisher that requests token
let tokenpublisher = session.dataTaskPublisher(for: urlrequest)
.map(.data)
.decode(type: Auth.self, decoder: JSONDecoder())
.map(.token)
.mapError {
$0 as Error
}

//Create subsequent publisher that uses the token from tokenpublisher, create request to create new acronym
let acronym = Acronym(short: “PBS”, long: “Peanut Butter and Sandwich”)
let acronymrequestpublisher = tokenpublisher
.compactMap {urlRequestWithToken(token:$0, acronym:acronym)}
.flatMap { request in
session.dataTaskPublisher(for: request)
.mapError {$0 as Error }
}

var cancellables:Set = []

Publishers.Zip(tokenpublisher,acronymrequestpublisher)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
print(completion)
}) { token, response in
print(String(data: response.data, encoding: .ascii) )
}
.store(in: &cancellables)

func urlRequestWithToken(token:String, acronym:Acronym)->URLRequest? {
guard let acronymdata = try? encoder.encode(acronym) else {
return nil
}
guard let url = newEndpoint else {
return nil
}
var urlrequest = URLRequest(url: url)
urlrequest.httpMethod = “POST”
urlrequest.allHTTPHeaderFields = [
“accept”:“application/json”,
“content-type”:“application/json”,
“authorization”:“Bearer (token)”
]
urlrequest.httpBody = acronymdata
return urlrequest
}

1 Like

Awesome work there! Well done!

Hey what is the url to get a listing of entries in the app?

Im getting the same issue, the url address comes back with a status code of 200 but it looks like there is nothing there at that address anymore. When navigating to the url in Safari nothing is there. Any suggestions??