Bring Type Safety of Swift to HTTP endpoints, file paths, and more.
Instead of this:
let url = URL(string: "https://ptx.transportdata.tw/MOTC/v2/Bike/Availability/Tainan")!Write this:
let motcV2 = PathBuilder(path: url, modelType: MOTCV2.self)
let endpoint: URL = motcV2.bike.availability.city(.tainan)Autocomplete fully supported!
For an endpoint like https://ptx.transportdata.tw/MOTC/v2/Bike/Availability/Tainan, define a root type first:
struct MOTCV2 {
var bike: Bike
}Define a new type for every URL component:
struct Bike {
var availability: Availability
}
struct Availability {
var city: City
}For enums and string components, define a RawRepresentable type with String as RawValue:
enum City: String {
case tainan = "Tainan"
}Make the last type conform to Endpoint or DecodableEndpoint:
extension City: Endpoint { }Declare a builder:
let baseURL = URL(string: "https://ptx.transportdata.tw/MOTC/v2")!
let motcV2 = PathBuilder(path: baseURL, modelType: MOTCV2.self)Now you can create URL like this:
let url: URL = motcV2.bike.availability.city(.tainan)
// Or...
let sub = URLSession.shared
.dataTaskPublisher(for: motcV2.bike.availability.city(.tainan))
.map(\.data)
.sink { completion in
print(completion)
expectation.fulfill()
} receiveValue: { data in
print(data)
}If your endpoint is a DecodableEndpoint, you can create typed URLSessionDataTask and publishers like this:
extension City: DecodableEndpoint {
typealias Value = [ValueItem]
static var defaultDecoder: JSONDecoder {
return JSONDecoder()
}
}
let sub = URLSession.shared
.decodedDataTaskPublisher(for: motcV2.bike.availability.city(.tainan))
.sink { completion in
print(completion)
expectation.fulfill()
} receiveValue: { decodedValue in
print(decodedValue)
}PathBuilder will use the lowercased type name as its url component string. If you want to use other things, conform the type to PathComponentProviding:
struct Bike: PathComponentProviding {
static var pathComponent: String {
return "\(self)"
}
var availability: Availability
}