A library of delightfully light extensions to simplify working with SwiftUI and Combine in real-world apps.
URL
is now ExpressibleByStringLiteral
, so we can conveniently express them like this:
let url: URL = "https://server.domain/path"
We've deliberately restricted this to literal strings, since it's reasonable to expect that they're as free of typos as your code. 😉
We've taught URL to deal with query parameters like a dictionary1:
url.parameters["query"] = "fondue"
Inspired by SwiftUI's extensive use of modifiers, we've given a few to URL and URLRequest:
let base: URL = "https://server.domain/api"
let url = base.with(parameters: ["query": "fondue"])
let request = url.request(.post, path: "path")
.adding(parameters: ["page": 1])
Getting a Combine publisher from URLRequest
or URL
couldn't be simpler:
let base: URL = "https://api.foo.com/api/employees"
func employee(id: String) -> AnyPublisher<Employee, Error> {
base.request(path: id).publisher()
}
The new modifiers let you fluently set HTTP method, headers and automatic body encoding, for example:
func createToken(email: String, password: String) -> AnyPublisher<TokenResponseBody, Error> {
base.request(.post, path: "UserProfiles/CreateToken")
.adding(header: "ApplicationToken", value: applicationToken)
.with(body: TokenRequestBody(email: email, password: password))
.publisher()
}
A convenient way to provide asynchronous data to a View. It publishes the output, busy and error states so that they can be bound to a View.
struct SomeView: View {
@StateObject var model = ObservableProcessor { SomeAPI.get() }
var body: some View {
List(model.output ?? []) { item in
:
}
}
}
Footnotes
-
Strictly speaking, URLs can have multiple parameters with the same name (e.g.
a=1&a=2
), and some server-side frameworks gather these into arrays. But in many real-life projects, we think of each parameter as uniquely-named. If this is also your case, you might find it more convenient to treat query parameters just like a dictionary. ↩