jsonswiftgenericsurlsession

How to use Generics with JSON Encoder in swift


I'm using JSON Placeholder post api to make a HTTP POST request using Generics and Result Type in Swift. Here is my codable struct for request and response. For this API both response and request are same.

enum AddPostModel{
    struct AddPostRequest: Codable{
        let title: String
        let body: String
        let userId: String
        let id: String
    }
    struct AddPostResponse: Codable{
        let title: String
        let body: String
        let userId: String
        let id: String
    }
}

Here is my POST request code using URLSession async/await, generics and result type.

func sendPostRequest<T: Codable>(url: String,responseType: T.Type,params: T) async -> Result<T,Error>{
        do{
            let session = URLSession(configuration: .default)
            guard let url = URL(string: url) else{return .failure(HTTPError.invalidUrl) }
            var request = URLRequest(url: url)
            request.httpMethod = HTTPMethods.POST.method
            
            
            let jsonData = try JSONEncoder().encode(params)
            request.httpBody = jsonData
            
            let (data,response) = try await session.data(for: request)
            guard let urlResponse = response as? HTTPURLResponse , (200...299).contains(urlResponse.statusCode)
              else{ return .failure(HTTPError.failedResponse)}
            
            
            let jsonResponse = try JSONDecoder().decode(responseType.self, from: data)
            return .success(jsonResponse)
            
        }
        catch{
            return .failure(error)
        }
    }

Here I call the Post method

 func addPost(params: AddPostModel.AddPostRequest) async -> Result<AddPostModel.AddPostResponse,Error>{
        
        return await service.sendPostRequest(url: Constant.BASE_URL + "/" + HomeEndPoints.posts.path, responseType: AddPostModel.AddPostResponse.self, params: params)
    }

When I try to build I get the following error in the params parameter of the sendPostRequest method

Cannot convert value of type AddPostModel.AddPostRequest to expected argument type AddPostModel.AddPostResponse


Solution

  • You're using the same generic T for both request and response, that's impossible. Generic parameter mean a placeholder type with optional constraints that will be replaced at compile time, and they can't be two different types in the same context. Declaring another generic type like U for request parameters will fix this.

    func sendPostRequest<T: Codable, U: Codable>(url: String, responseType: T.Type, params: U) async -> Result<T, Error> {
        ...
    }