3

Given a short URL https://itun.es/us/JB7h_, How do you expand it into the full URL? e.g. https://music.apple.com/us/album/blackstar/1059043043

Alexander
  • 59,041
  • 12
  • 98
  • 151
Zelko
  • 3,793
  • 3
  • 34
  • 40
  • 2
    You should probably add some clarification that this is a Q&A style question so that it doesn't get closed as too broad – Jojodmo Jan 10 '16 at 20:50

2 Answers2

9

Extension

extension URL {
   func getExpandedURL() async throws -> Result<URL, Error> {
       var request = URLRequest(url: self)
       request.httpMethod = "HEAD"
       
       let (_, response) = try await URLSession.shared.data(for: request)
       
       guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
           throw URLError.unableToExpand
       }
       
       if let expandedURL = response.url {
           return .success(expandedURL)
       } else {
           throw URLError.unableToExpand
       }
   }
    
    enum URLError: Error {
        case unableToExpand
    }
}

Crude Demo

struct ContentView: View {
    let shortURL = URL(string: "https://itun.es/us/JB7h_")
    @State var expandedURLResult: Result<URL, Error>?
    
    var body: some View {
        Form {
            Section("Short URL") {
                Text(shortURL?.description ?? "")
            }
            
            Section("Long URL") {
                switch expandedURLResult {
                    case .some(.success(let expandedURL)):
                        Text(expandedURL.description)
                    case .none:
                        Text("Waiting")
                    case .some(.failure(let error)):
                        Text(error.localizedDescription)
                }
            }
        }
        .task {
            do {
                expandedURLResult = try await shortURL?.getExpandedURL()
            } catch {
                expandedURLResult = .failure(error)
            }
        }
    }
}

enter image description here

Zelko
  • 3,793
  • 3
  • 34
  • 40
8

The final resolved URL will be returned to you in the NSURLResponse: response.URL.

You should also make sure to use the HTTP HEAD method to avoid downloading unnecessary data (since you don't care about the resource body).

Swift 4.2 Updated :

extension URL {
func resolveWithCompletionHandler(completion: @escaping (URL) -> Void) {
    let originalURL = self
    var req = URLRequest(url: originalURL)
    req.httpMethod = "HEAD"

    URLSession.shared.dataTask(with: req) { body, response, error in
        completion(response?.url ?? originalURL)
        }.resume()
}

Older Swift Versions:

extension NSURL
{
    func resolveWithCompletionHandler(completion: NSURL -> Void)
    {
        let originalURL = self
        let req = NSMutableURLRequest(URL: originalURL)
        req.HTTPMethod = "HEAD"

        NSURLSession.sharedSession().dataTaskWithRequest(req) { body, response, error in
            completion(response?.URL ?? originalURL)
        }.resume()
    }
}

// Example:
NSURL(string: "https://itun.es/us/JB7h_")!.resolveWithCompletionHandler {
    print("resolved to \($0)")  // prints https://itunes.apple.com/us/album/blackstar/id1059043043
}
jtbandes
  • 115,675
  • 35
  • 233
  • 266