GitHub - sky-uk/ReactiveAPI: Write clean, concise and declarative network code r...
source link: https://github.com/sky-uk/ReactiveAPI
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
README.md
ReactiveAPI
Reactive API library allows you to write clean, concise and declarative network code, with the power of RxSwift and URLSession!
Deployment Target
iOS 10.3
Setup in projects
Carthage is the dependency manager used. Add the following to your Cartfile:
github "sky-uk/ReactiveAPI" ~> version
where version
is one of the released versions (e.g. 1.0.0
). Check releases
Unauthenticated API Demo
To see ReactiveAPI in action we created a complete swapi.co client.
Clone this repository, open ReactiveAPIDemo
directory from your terminal and run:
carthage bootstrap --platform ios
After that completes, simply open ReactiveAPIDemo
project from Xcode and hit Run
.
Token Authenticated API Demo
Most of today REST APIs have a token authentication mechanism. We created a dedicated demo app, with a standalone node.js server to demostrate all the power of ReactiveAPI authentication handling. Check it here.
What your network code will look like with ReactiveAPI
We highly suggest to create a Network
group with two child groups: APIs
and Models
.
Example taken from ReactiveAPIDemo:
Network
|--> APIs
|--> StarWarsAPI.swift
|--> Models
|--> Film.swift
|--> PagedResponse.swift
|--> Person.swift
|--> Root.swift
|--> Planet.swift
|--> Specie.swift
|--> Vehicle.swift
|--> Starship.swift
Every API will look like StarWarsAPI.swift
(except the method parameters, which are specific to every API)
class StarWarsAPI: JSONReactiveAPI { func getRoot() -> Single<Root> { return request(url: absoluteURL("")) } func getPeople(url: URL) -> Single<PagedResponse<Person>> { return request(url: url) } func getFilms(url: URL) -> Single<PagedResponse<Film>> { return request(url: url) } func getPlanets(url: URL) -> Single<PagedResponse<Planet>> { return request(url: url) } func getSpecies(url: URL) -> Single<PagedResponse<Specie>> { return request(url: url) } func getVehicles(url: URL) -> Single<PagedResponse<Vehicle>> { return request(url: url) } func getStarships(url: URL) -> Single<PagedResponse<Starship>> { return request(url: url) } }
All the models, which represents the response payloads are Codable
and Hashable
structs, like Film.swift
:
struct Film: Codable, Hashable { let title: String let episode_id: Int let opening_crawl: String let director: String let producer: String let release_date: String let species: [URL] let starships: [URL] let vehicles: [URL] let characters: [URL] let planets: [URL] let url: URL }
This is how we suggest you to initialize an API you implemented using ReactiveAPI:
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { private static let baseURL = URL(string: "https://swapi.co/api/")! var window: UIWindow? var client: StarWarsAPI! func setupReactiveAPI() { let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String let sessionConfig = URLSessionConfiguration.default sessionConfig.httpAdditionalHeaders = ["User-Agent": "ReactiveAPIDemo/\(appVersion)"] client = StarWarsAPI(session: URLSession(configuration: sessionConfig).rx, decoder: JSONDecoder(), baseUrl: AppDelegate.baseURL) } func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { setupReactiveAPI() //your other initialization code. Simply inject client where you need it } }
A call to an API (with an example data transformation) looks like this:
client.getRoot() .map { root in return [ ViewModelData(title: "Films", subtitle: "All the films in the saga", url: root.films), ViewModelData(title: "People", subtitle: "Meet the characters", url: root.people), ViewModelData(title: "Planets", subtitle: "Discover new worlds", url: root.planets), ViewModelData(title: "Species", subtitle: "Extend your imagination", url: root.species), ViewModelData(title: "Vehicles", subtitle: "Take a ride", url: root.vehicles), ViewModelData(title: "Starships", subtitle: "Reach distant places fast", url: root.starships) ] } .asDriver(onErrorRecover: { error in print("Something bad happened: \(error)") return Driver.empty() }) .drive(onNext: { data in // populate UI with the data }) .disposed(by: disposeBag)
This is just a basic proof of concept of what you get. Of course, the library is capable of much more than this.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK