My goal is to chain multiple (two at this time) network calls with Combine, breaking chain if first call fails.
I have two object types: CategoryEntity
and SubcategoryEntity
. Every CategoryEntity
has a property called subcategoriesIDS
.
With first call I need to fetch all subcategories, with second I will fetch all categories and then I will create an array of CategoryEntityViewModel
.
CategoryEntityViewModel
contains an array of SubcategoryEntityViewModel
based on CategoryEntity
's subcategoriesIDS
.
Just to be clearer:
- Fetch subcategories
- Fetch categories
- Create a
SubcategoryEntityViewModel
for every fetched subcategory and store somewhere CategoryEntityViewModel
is created for every category fetched. This object will be initialized with aCategoryEntity
object and an array ofSubcategoryEntityViewModel
, found filtering matching ids betweensubcategoriesIDS
and storedSubcategoryEntityViewModel
array
My code right now is:
class CategoriesService: Service, ErrorManager {
static let shared = CategoriesService()
internal let decoder = JSONDecoder()
@Published var error: ServerError = .none
private init() {
decoder.dateDecodingStrategyFormatters = [ DateFormatter.yearMonthDay ]
}
func getAllCategories() -> AnyPublisher<[CategoryEntity], ServerError> {
let request = self.createRequest(withUrlString: "\(AppSettings.api_endpoint)/categories/all", forMethod: .get)
return URLSession.shared.dataTaskPublisher(for: request)
.receive(on: DispatchQueue.main)
.tryMap { data, response -> Data in
guard let httpResponse = response as? HTTPURLResponse, 200..<300 ~= httpResponse.statusCode else {
switch (response as! HTTPURLResponse).statusCode {
case (401):
throw ServerError.notAuthorized
default:
throw ServerError.unknown
}
}
return data
}
.map { $0 }
.decode(type: NetworkResponse<[CategoryEntity]>.self, decoder: self.decoder)
.map { $0.result}
.mapError { error -> ServerError in self.manageError(error: error)}
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}
func getAllSubcategories() -> AnyPublisher<[SubcategoryEntity], ServerError> {
let request = self.createRequest(withUrlString: "\(AppSettings.api_endpoint)/subcategories/all", forMethod: .get)
return URLSession.shared.dataTaskPublisher(for: request)
.receive(on: DispatchQueue.main)
.tryMap { data, response -> Data in
guard let httpResponse = response as? HTTPURLResponse, 200..<300 ~= httpResponse.statusCode else {
switch (response as! HTTPURLResponse).statusCode {
case (401):
throw ServerError.notAuthorized
default:
throw ServerError.unknown
}
}
return data
}
.map { $0 }
.decode(type: NetworkResponse<[SubcategoryEntity]>.self, decoder: self.decoder)
.map { $0.result }
.mapError { error -> ServerError in self.manageError(error: error)}
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}
}
These methods are working (sink
is called in another class, don't think it is useful so not copied here) but I cannot find the correct way to chain them.