-1

Trying to do an API call, and have used a data task before. Now I tried the DataPublisher instead with combine. I have developed an API that needs authorisation with a specific token. Sadly the auth header doesn't seem to be initialized when I run my app.

Swift file that executes the API call

final class TransactionListViewModel: ObservableObject {
@Published var transactions: [Transaction] = []

private var cancellables = Set<AnyCancellable>()

init() {
    getTransactions()
}

func getTransactions() {
    guard let url = URL(string: "THE_URL") else {
        print("Invalid URL")
        return
    }
    
    var request = URLRequest(url: url)
    
    // Setting the HTTP Method
    request.httpMethod = "GET"
    
    // Setting the HTTP Headers
    request.setValue("application/vnd.api+json", forHTTPHeaderField: "Content-Type")
    request.setValue("application/vnd.api+json", forHTTPHeaderField: "Accept")
    
    // Set the auth Berear token
    request.setValue("Bearer THE_TOKEN_HERE", forHTTPHeaderField: "Authorization")
    
    URLSession.shared.dataTaskPublisher(for: request)
        .tryMap { (data, response) -> Data in
            guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
                dump(response)
                throw URLError(.badServerResponse)
            }
            
            return data
        }
        .decode(type: [Transaction].self, decoder: JSONDecoder())
        .receive(on: DispatchQueue.main)
        .sink { completion in
            switch completion {
            case .failure(let error):
                print("Error fetching transactions: ", error)
            case .finished:
                print("Finished fetching transactions")
            }
        } receiveValue: { [weak self] result in
            self?.transactions = result
            dump(self?.transactions)
        }
        .store(in: &cancellables)
    }
}

The error in the console

<NSHTTPURLResponse: 0x600002d9c680> { URL: THE_URL } { Status Code: 401, Headers {
    "Access-Control-Allow-Origin" =     (
        "*"
    );
    "Alt-Svc" =     (
        "h3=\":443\"; ma=2592000, h3-29=\":443\"; ma=2592000, h3-Q050=\":443\"; ma=2592000, h3-Q046=\":443\"; ma=2592000, h3-Q043=\":443\"; ma=2592000, quic=\":443\"; ma=2592000; v=\"43,46\""
    );
    "Cache-Control" =     (
        "no-cache, private"
    );
    "Content-Encoding" =     (
        br
    );
    "Content-Length" =     (
        34
    );
    "Content-Type" =     (
        "application/json"
    );
    Date =     (
        "Sun, 12 Feb 2023 17:56:51 GMT"
    );
    Server =     (
        LiteSpeed
    );
    Vary =     (
        "Accept-Encoding"
    );
    "x-powered-by" =     (
        "PHP/8.1.15"
    );
} } #0
  - super: NSURLResponse
    - super: NSObject
Error fetching transactions:  Error Domain=NSURLErrorDomain Code=-1011 "(null)"
Message from debugger: Terminated due to signal 9

As seen non of my headers are in the console output.

I Have searched around the internet without any help. What am I doing wrong?

I tried to use addValue instead of setValue. It did not work. I Have not found any other solutions on the internet.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
Spirarn
  • 1
  • 3
  • `"Content-Length" = (34);"`, would you mind do `print("String(data: data, encoding: .utf8))` in the else of `guard let httpResponse = response`? I guess it will say also an error with the header, but it might give more infos. – Larme Feb 12 '23 at 18:48
  • @Larme the "print(String(data: data, encoding: .utf8)) ?? "Missing" " printed this out in the console {"message":"Unauthenticated."} – Spirarn Feb 12 '23 at 20:00
  • If it works with POSTMAN, could you share the cURL equivalent? Or ask for the Swift equivalent, not beautiful code, but you might be able to test it and if it works, maybe spot a difference. – Larme Feb 12 '23 at 20:02
  • @Larme I tried to check Apple's Developer Handbook for swift, Perhaps the dataTaskPublisher only accepts the URL not the REQUEST? – Spirarn Feb 12 '23 at 20:07

2 Answers2

1

The error you are seeing in the console is the response. You wouldn't expect it to contain your headers.

The response has a 401 HTTP code which means "not authorised". That probably means the bearer token you set is invalid. If it is literally Bearer THE_TOKEN_HERE that's probably what the issue is. I'd expect the bearer token to be a hash or a UUID.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • No, the token is not THE_TOKEN_HERE, that was just a placeholder for the acctual token. I send the same request with the same token with Postman. And the request sends back the data with status code 200. Do you have any suggestions of what I could change? – Spirarn Feb 12 '23 at 19:51
  • @Spirarn Probably want to dump the request as well as the response as a first step. – JeremyP Feb 12 '23 at 20:00
  • I dumped the request. I can see that the request contains the headers. For some reason i still get status 401. the token is exactly the same as the one used in postman – Spirarn Feb 12 '23 at 20:03
  • Are all the headers in the request the same as in Postman? Also, the response body has JSON in it. It would be worth converting it to a string and dumping that too. It might give more information. – JeremyP Feb 12 '23 at 20:10
  • I think it's solved. Really weird but was the URL... – Spirarn Feb 12 '23 at 20:11
0

Found the solution. The actual URL it self was wrong. Had to remove the last / from the URL and the status code 401 was now removed and I get 200 OK

Before (not working) https:/www.url.com/api/task/

Now (working) https:/www.url.com/api/task

Spirarn
  • 1
  • 3
  • That is not surprising. with the `/` the server might think you are trying to get a directory as opposed to get a resource. This is often banned on web servers. – JeremyP Feb 13 '23 at 09:32
  • After a certain amount of time, you should be able to accept this answer, which you should do, otherwise people might think the problem is not yet resolved. – JeremyP Feb 13 '23 at 09:33
  • @JeremyP Sorry, went to sleep. New to StackOverflow. The url with an / at the end worked in postman. That’s why it was suprising to me. – Spirarn Feb 13 '23 at 13:16