I have prepared a Generic Service layer in my tutorial, where the responses differ from one API call to another and as i know generic is capable of handling this.
Yet i find it hard to call different APIs that has differnet responses.
For example the GetPosts --> Response[Array of Post Model] For Example Delete POst --> Response (Post Model)
Knowing that both calls reach the below in the service layer
else if let jsonArray = json as? [Any] {
let object = Mapper<T>().mapArray( JSONObject: jsonArray)
completion(.success(object!))
}
You can check the response of each call on this Page
Here below is the Service LAYER CLASS this works fine when i call the getPosts API since in the saervice layer i defined the completiuon as Array --> [T], an in the getPosts Function i expect response as [PostsModel]
But when i try to call the DeletePost i face some complications since the result should be PostModel and not an array of PostModel.
When i modify the Servicelayer to accept T and not [T] i face some complications..
Hope anyone can help
import Foundation
import ObjectMapper
import Alamofire
class ServiceLayer {
class func request<T: Mappable>(router: Router, completion: @escaping (Result<[T], Error>) -> ()) {
do {
AF.request(try router.asURLRequest()).validate().responseData { (data) in
print(data)
let result = data.result
switch result {
case .success(let data):
do {
//Response as Dictionary
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? Any {
if let jsonDict = json as? [String : Any] {
let object = Mapper<T>().map(JSON: jsonDict)
completion(.success(object as! [T]))
}
//Response as Array
else if let jsonArray = json as? [Any] {
let object = Mapper<T>().mapArray( JSONObject: jsonArray)
completion(.success(object!))
}
//Response as String
else if let _ = String(data: data, encoding: .utf8){
}
}
} catch {
print(error.localizedDescription)
completion(.failure(error))
}
break
case .failure(let error):
print(error.localizedDescription)
completion(.failure(error))
break
}
}
} catch {
print(error.localizedDescription)
}
}
}
Here is the call to the APIs from the ViewModel
func getPosts() {
self.isLoading.value = true
ServiceLayer.request(router: .getPosts(userId: 1)) { (result : Result<[PostsModel], Error>) in
self.isLoading.value = false
switch result {
case .success(let baseModel):
self.array = baseModel
self.fetchPostsSucceded.value = true
case .failure(let error):
print(error.localizedDescription)
}
}
}
func deletePosts(postid: Int) {
self.isLoading.value = true
ServiceLayer.request(router: .deletePosts(id: postid)) { (result : Result<PostsModel, Error>) in
self.isLoading.value = false
switch result {
case .success(let baseModel):
print("")
case .failure(let error):
print(error.localizedDescription)
}
}
}
This is the PostModel Response, Knwoing that when i modify the Service layer completion to T and not [T] i get this
Class method 'request(router:completion:)' requires that '[PostsModel]' conform to 'Mappable'
import Foundation
import ObjectMapper
class PostsModel: Mappable, Codable {
var userId : Int?
var id : Int?
var title : String?
var body : String?
required init?(map: Map) {
}
func mapping(map: Map) {
userId <- map["userId"]
id <- map["id"]
title <- map["title"]
body <- map["body"]
}
}
Hope someone can help me resolve this, The needed result is to keep only one service layer that accepts any call and in the API calls to specify the return value.