Skip to content

Instantly share code, notes, and snippets.

@ts95
Last active February 24, 2018 18:03
Show Gist options
  • Save ts95/7d3928d266522511882c41bd2b941d6b to your computer and use it in GitHub Desktop.
Save ts95/7d3928d266522511882c41bd2b941d6b to your computer and use it in GitHub Desktop.
Extracting keys and values from a path in Swift
import Foundation
enum PathParamsError: Error {
case unbalanced
case nonExistentParam(key: String)
case invalidConversion(value: String, type: String)
var localizedDescription: String {
switch self {
case .unbalanced:
return "The number of keys didn't correspond with the number of values"
case .nonExistentParam(let key):
return "There is no value for the key \(key)"
case .invalidConversion(let value, let type):
return "Couldn't convert the value \(value) to the specified type \(type)"
}
}
}
/**
Used to extract path parameters from a path.
*/
struct PathParams {
private let params: [String : String]
init(path: String) throws {
let parts = path.split(separator: "/")
guard parts.count % 2 == 0 else { throw PathParamsError.unbalanced }
let values = stride(from: 0, to: parts.count, by: 2).map { (index) -> (String, String) in
(parts[index].lowercased(), "\(parts[index+1])")
}
params = Dictionary(uniqueKeysWithValues: values)
}
func optionalValue<T: LosslessStringConvertible>(forKey key: String, _ type: T.Type) throws -> T? {
guard let stringValue = params[key.lowercased()] else { return nil }
guard let value = T(stringValue) else {
throw PathParamsError.invalidConversion(value: stringValue, type: String(describing: T.self)) }
return value
}
func value<T: LosslessStringConvertible>(forKey key: String, _ type: T.Type) throws -> T {
guard let value = try optionalValue(forKey: key, type) else {
throw PathParamsError.nonExistentParam(key: key.lowercased()) }
return value
}
}
// Usage
do {
let params = try PathParams(path: "/customerid/8945834/receiptid/36235432/category/seafood")
let category = try params.value(forKey: "category", String.self)
let customerId = try params.value(forKey: "customerid", Int.self)
let receiptId = try params.value(forKey: "receiptid", Int.self)
let sauceType = try params.optionalValue(forKey: "sauce", String.self)
print("Category:", category)
print("Customer ID:", customerId)
print("Receipt ID:", receiptId)
if let sauceType = sauceType {
print("Sauce: \(sauceType)")
}
} catch {
if let error = error as? PathParamsError {
print(error.localizedDescription)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment