Skip to content

yesleon/PathBuilder

Repository files navigation

PathBuilder

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!

Usage

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
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages