3

I implemented the following code, where I can pass in the name of the resource and it should give me the URL. I am using Xcode 14 Beta 3.

 static let baseUrl = "localhost:8080"
 static func resource(for resourceName: String) -> URL? {
            
            var components = URLComponents()
            components.scheme = "http"
            components.percentEncodedHost = baseUrl
            components.path = "/\(resourceName)"
            return components.url
            
        }

I am passing a resource name as 'my-pets' and it is supposed to be returning http://localhost:8080/my-pets but it keeps returning http://my-pets. I am not sure where I am making a mistake.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Mary Doe
  • 1,073
  • 1
  • 6
  • 22
  • I tested your code in Playgrounds and got `http://localhost:8080/my-pets` – Larme Jul 25 '22 at 13:21
  • Thanks! Maybe something to do with Xcode 14 Beta 3. – Mary Doe Jul 25 '22 at 13:22
  • `components.url` should return `nil`, since in your case the "host" is syntactically incorrect (see "3.2.2 "Host" in [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2)). For the scheme "http" a URI is invalid when it does not have a host. So, what URLComponents returns as URL is invalid. You may file a bug. :) – CouchDeveloper Jul 25 '22 at 17:50

1 Answers1

4

You're passing "localhost:8080" as a hostname. This isn't correct. The hostname is "localhost". 8080 goes in the port field.

You may want to use this approach instead:

let baseURL = URLComponents(string: "http://localhost:8080")!

func resource(for resourceName: String) -> URL? {
    var components = baseURL
    components.path = "/\(resourceName)"
    return components.url
}

You might also do it this way, if the problem is really this simple:

let baseURL = URL(string: "http://localhost:8080")!

func resource(for resourceName: String) -> URL? {
    baseURL.appending(path: resourceName)
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Is this something that recently got changed. Because the same exact code works in Xcode 13 and Xcode 14 Beta 1. But not on Xcode 14 Beta 3. – Mary Doe Jul 25 '22 at 13:35
  • 1
    I would say yes. I tested your code on Beta3 and reproduced the issue. But I'd say it was a bug in previous versions that Beta3 fixed rather than the other way around. – Rob Napier Jul 25 '22 at 13:37
  • IMHO, it's now worse than before. When given a syntactically incorrect host, URLComponents should not produce a URL, especially not a wrong one (a URL with a scheme "http" _requires_ a host). ;) – CouchDeveloper Jul 25 '22 at 17:56
  • @CouchDeveloper I don't know if that really makes sense given the rest of the API. Should a setter with an invalid value set the property (host) to nil or invalidate the entire object (think about what the implementation of that would look like across all properties)? It really kind of points to some awkwardness in the API itself, but "setting an invalid value nils that specific value" is not a wildly incorrect approach in a world before throwing setters. – Rob Napier Jul 25 '22 at 18:44
  • Rob, I agree, the usage seems a bit awkward and I wished there is a better API (using a resultBuilder may be). But luckily we discovered this subtlety and we learned again to be careful - as always :) – CouchDeveloper Jul 26 '22 at 09:44