qstatus/qStatus/Utilities/URLNormalizer.swift
Paweł Orzech 733334df9b
Deduplicate shared constants, MIME helper, and cache normalized URLs
- Extract OAuth UserDefaults keys into shared OAuthKeys enum
- Extract triplicated mimeTypeFor() into shared mimeTypeForImage()
- Cache normalized base URL at client init instead of per-request
2026-03-07 22:22:08 +01:00

49 lines
1.8 KiB
Swift

import Foundation
enum URLNormalizer {
static func normalizeBaseURL(_ input: String, fieldName: String = "URL") throws -> String {
let trimmed = input.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else {
throw PostingError(message: "\(fieldName) cannot be empty.")
}
let prefixed = if trimmed.hasPrefix("http://") || trimmed.hasPrefix("https://") {
trimmed
} else {
"https://\(trimmed)"
}
guard var components = URLComponents(string: prefixed),
let scheme = components.scheme?.lowercased(),
(scheme == "https" || scheme == "http"),
components.host != nil
else {
throw PostingError(message: "Invalid \(fieldName). Please provide a full domain, e.g. example.com.")
}
components.path = ""
components.query = nil
components.fragment = nil
guard let normalized = components.url?.absoluteString else {
throw PostingError(message: "Invalid \(fieldName).")
}
return normalized.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
}
static func endpointURL(baseURL: String, path: String, fieldName: String = "URL") throws -> URL {
let normalizedBase = try normalizeBaseURL(baseURL, fieldName: fieldName)
guard let url = URL(string: normalizedBase + path) else {
throw PostingError(message: "Failed to build API URL from \(fieldName).")
}
return url
}
static func endpointURL(base normalizedBase: String, path: String) throws -> URL {
guard let url = URL(string: normalizedBase + path) else {
throw PostingError(message: "Failed to build API URL.")
}
return url
}
}