I am trying to save the user in UserDefaults from a struct that fetches the data from an API when a user logs in successfully.
Here is my Webservice class:
import Foundation
import UIKit
struct Resource<T: Codable> {
let url : URL
let httpMethod = HTTPMethod.post
var body : Data? = nil
}
extension Resource {
init(url: URL) {
self.url = url
}
}
enum HTTPMethod : String {
case get = "GET"
case post = "POST"
}
enum NetworkingError: Error {
case domainError
case badResponse
case encodingError
case decodingError
}
class Webservice {
func load<T>(resource: Resource<T>, caller: UIViewController ,completion: @escaping (Result<T, NetworkingError>) -> Void) {
var request = URLRequest(url: resource.url)
request.httpMethod = resource.httpMethod.rawValue
request.httpBody = resource.body
request.addValue("application/JSON", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
return completion(.failure(.domainError))
}
let json = try? JSONSerialization.jsonObject(with: data, options: [])
print(json)
do {
let result = try JSONDecoder().decode(T.self, from: data)
//save to UserDefaults
UserDefaults.standard.set(PropertyListEncoder().encode(T), forKey: "user")\\ here I am getting error that T.type does not conform to Encodable protocol.
completion(.success(result))
}catch {
do {
if let result = try? JSONDecoder().decode(LoginErrorResponse.self, from: data){
print(result.errors.msg)
DispatchQueue.main.async {
let alert = AlertService().alert(message: "\(result.errors.msg[0])")
caller.present(alert, animated: true)
}
completion(.failure(.decodingError))
}
if let result = try? JSONDecoder().decode(SignUpErrorResponse.self, from: data){
print(result.errors.msg)
DispatchQueue.main.async {
let alert = AlertService().alert(message: "\(result.errors.msg)")
caller.present(alert, animated: true)
}
completion(.failure(.decodingError))
}
}
}
}.resume()
}
}
Here is my model class:
import Foundation
struct User: Encodable, Decodable {
let name: String
let email: String
let password: String
let first_name: String
let last_name: String
}
extension User {
static var all : Resource<User> = {
guard let url = URL(string: "http://orderahead.gagzweblab.xyz:3001/login") else {
fatalError("url is incorrect")
}
return Resource<User>(url: url)
}()
static func create(vm : UserViewModel) -> Resource<UserResponseModel?> {
let user = User(vm)
guard let url = URL(string: "http://orderahead.gagzweblab.xyz:3001/register") else {
fatalError("url is incorrect")
}
guard let data = try? JSONEncoder().encode(user) else {
fatalError("error encoding user")
}
var resource = Resource<UserResponseModel?>(url: url)
resource.body = data
return resource
}
}
extension User {
init?(_ vm: UserViewModel) {
let email = vm.email
let password = vm.password
let first_name = vm.first_name
let last_name = vm.last_name
let name = vm.name
self.password = password
self.email = email
self.first_name = first_name
self.last_name = last_name
self.name = name
}
}
And here is my view model:
import Foundation
struct UserViewModel : Codable {
let user : User
}
extension UserViewModel {
var name : String {
return self.user.name
}
var email : String {
return self.user.email
}
var password : String {
self.user.password
}
var first_name: String {
self.user.first_name
}
var last_name: String {
self.user.last_name
}
}
This is how I am calling it:
let login = LoginUser(email: email, password: password)
let vm = UserViewModel(loginUser: login)
Webservice().load(resource: User.create(vm: vm), caller: self) { (result) in
My model and view model conform to Codable as well as my Resource is Codable too.
What is the reason of the error that T.type
does not conform to protocol Encodable? How to resolve it?
Is this approach to send and receive data appropriate?