I have been playing about with the PokeApi while doing some RxSwift practice. Pokeapi can be found here
Example of api I am working with
While searching through pokemon, you can set a limit of how many you want returned, then in the response, there is a next and previous param so you can continue going forward and backgrounds through the pokemon. Example of part of the response
https://pokeapi.co/api/v2/pokemon/?limit=20
{"count":964,"next":" https://pokeapi.co/api/v2/pokemon/?offset=20&limit=20 ","previous":null,"results":....
In my controller, there is text field where they can enter how many pokemon they want returned per page, and then when they hit search, results returned in table and they can hit next and previous to cycle through the pages. My Model looks like this
struct PokemonSearchData: Codable {
let next: String?
let previous: String?
let results: [PokemonResultsData]
}
struct PokemonResultsData: Codable {
let name: String
let url: String
}
Here is part of view model showing what I am doing atm
extension PokeListViewModel: ViewModelType {
struct Input {
let limitText: Observable<String>
let startRequest: PublishSubject<Void>
let nextTap: Observable<Void>
let previousTap: Observable<Void>
let selectedPokemon: Observable<PokemonResultsData>
}
struct Output {
let responseData: Observable<PokemonSearchData>
let errors: Driver<Error>
}
func transform(input: PokeListViewModel.Input) -> PokeListViewModel.Output {
let request = input.startRequest
.withLatestFrom(input.limitText)
.flatMap { text in
self.service.fetchPokemon(limit: text).materialize()
}.share()
let searchResponse = request.map{$0.element}.filterNil()
let searchError = request.map{$0.error}.asDriver(onErrorJustReturn: RxError.unknown).filterNil()
let nextURL = searchResponse.map{$0.next}.filterNil()
// handle next request and errors
let nextRequest = input.nextTap.withLatestFrom(nextURL).flatMap { nextURL in
self.service.cyclePokemon(stringURL: nextURL).materialize()
}.share()
let nextResponse = nextRequest.map{$0.element}.filterNil()
let nextError = nextRequest.map{$0.error}.asDriver(onErrorJustReturn: RxError.unknown).filterNil()
let mergedResponses = Observable.merge(searchResponse, nextResponse)
let mergedErrors = Driver.merge(searchError, nextError)
// do the same thing for previous response, just cut it out here so less code to paste, but the logic is the same
return Output(responseData: mergedResponses,
errors: mergedErrors)
}
The next request is dependent on the initial request, so when I hit next again, it is still based on the initial request so it just keeps returning the same data. I have seen other code samples doing pagination based on the api response having page numbers, but there is no page number here, it is all based on the previous request response.
Any help would be much appreciated
There is a an RXPager pod that will do this for you. Its useful to look at the code even if you want to do you own pagination logic. The idea is basically that you need to provide the pager with 2 functions:
1) A way to generate the next page from the current page (or nil if its the first page) 2) A has next function to determine if thee current page is the last page.
And and observable trigger that you can bind to the pager (such as your tableview's contentOffset.y distance from the bottom) that will trigger the next page load (if has next is true).
I'm not sure if your problem is RxSwift related. To my understanding, you need to use the offset
parameter when you make the call. For example, this request:
generates the following response:
{
"count": 964,
"next": "https://pokeapi.co/api/v2/pokemon/?offset=4&limit=4",
"previous": null,
"results": [
{
"name": "bulbasaur",
"url": "https://pokeapi.co/api/v2/pokemon/1/"
},
{
"name": "ivysaur",
"url": "https://pokeapi.co/api/v2/pokemon/2/"
},
{
"name": "venusaur",
"url": "https://pokeapi.co/api/v2/pokemon/3/"
},
{
"name": "charmander",
"url": "https://pokeapi.co/api/v2/pokemon/4/"
}
]
}
See how the value of the next
key is the URL you should hit next?
"next": "https://pokeapi.co/api/v2/pokemon/?offset=4&limit=4",
I believe if you keep track of the offset
value, you'll be able to receive the data you want.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.