-2

I have an API for my user to login to the database . I am using the following code to send the credentials to the API and if they are valid I am going to get some JSON typed data about the users information . Otherwise I get a string saying that the username or password is wrong . Here is my HTTTP Post request :

let url = URL(string: "http://128.199.199.17:3000/api/login")!
        var request = URLRequest(url: url)
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"
        let postString = "email=22222@gmail.com&password=123456"
        request.httpBody = postString.data(using: .utf8)
        let task = URLSession.shared.dataTask(with: request) { data, response, error in


            guard let data = data, error == nil else {
                print("error=\(String(describing: error))")
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("\(String(describing: response))")
            }

            let responseString = String(data: data, encoding: .utf8)
            print("responseString = \(responseString!)")
        }
        task.resume()

It works fine and I get the following information in the console :

{
  "user_id": 2,
  "email": "22222@gmail.com",
  "password": "123456",
  "user_name": "number 2 name",
  "full_name": "danial kosarifar",
  "sex": "male",
  "height": 0,
  "weight": 0,
  "number_of_meal_per_day": 3,
  "water_amount": 0,
  "calories": 0,
  "number_of_hours_to_sleep_per_day": 3,
  "createdAt": "2017-11-14T17:23:31.000Z",
  "updatedAt": "2017-11-14T17:25:37.000Z"
}

I've also created a decodable structure like so :

struct User : Decodable {

let user_id : Int
let email : String
let password : String
let username : String 
} 

my question is instead of decoding the data to string how can I decode them in such way that I can put them in the structure thats I've defined . I am completely new to this topic please bear with me if my question too of much of a beginner . Thanks

OverD
  • 2,612
  • 2
  • 14
  • 29
Danial Kosarifa
  • 1,044
  • 4
  • 18
  • 51

2 Answers2

3

Swift 4:

It's better for creating struct as Codable like below,

struct User:Codable { //Because enum CodingKeys: String, CodingKey {

    let userID : Int
    let email : String
    let password : String
    let userName : String
    let fullName:String
    let sex:String
    let height:Int
    let weight:Int
    let numberOfMealPerDay:Int
    let waterAmount:Int
    let calories:Int
    let numberOfHoursToSleppPerDay:Int
    let createdAt:String
    let updatedAt:String

    enum CodingKeys: String, CodingKey {
        case userID = "user_id"
        case email
        case password
        case userName = "user_name"
        case fullName = "full_name"
        case sex
        case height
        case weight
        case numberOfMealPerDay = "number_of_meal_per_day"
        case waterAmount = "water_amount"
        case calories
        case numberOfHoursToSleppPerDay = "number_of_hours_to_sleep_per_day"
        case createdAt
        case updatedAt
    }
}

By using JSONDecoder:

Then response data data inside the closure task can be parsed by using JSONDecoder. Here, user is the class variable. i.e.,var user:User?

if let json = try? JSONDecoder().decode(User.self, from: data!){

    self.user = json
}

Note: For better understanding, this is my video series about JSON parsing in swift 4

Rajamohan S
  • 7,229
  • 5
  • 36
  • 54
1

You can add a custom initializer to your user struct that takes the json data as a parameter and make it throws. You will need also to create a custom date formatter to parse your dates (you need to include the milliseconds to it). Note that if your json response may not include some keys/values you will need to make that property optional:

So for the date formatter you can use this custom date formatter from this answer:

extension Formatter {
    static let iso8601: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
        return formatter
    }()
}

Your user struct should look like this:

struct User: Codable {
    let id: Int
    let email: String
    let password: String
    let userName: String
    let fullName: String
    let sex: String
    let height: Int
    let weight: Int
    let mealsPerDay: Int
    let waterAmount: Int
    let calories: Int
    let hoursToSleepPerDay: Int
    let createdAt: Date
    let updatedAt: Date
    // you can provide different keys to your user struct properties
    private enum CodingKeys: String, CodingKey {
        case id = "user_id", email, password, userName = "user_name", fullName = "full_name", sex, height, weight, mealsPerDay = "number_of_meal_per_day", waterAmount = "water_amount", calories, hoursToSleepPerDay = "number_of_hours_to_sleep_per_day", createdAt, updatedAt
    }
    // custom initializer that takes the json data and throws in case of error
    init(data: Data) throws {
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .formatted(Formatter.iso8601)
        self = try decoder.decode(User.self, from: data)
    }
}

usage:

let data = Data("""
{
  "user_id": 2,
  "email": "22222@gmail.com",
  "password": "123456",
  "user_name": "number 2 name",
  "full_name": "danial kosarifar",
  "sex": "male",
  "height": 0,
  "weight": 0,
  "number_of_meal_per_day": 3,
  "water_amount": 0,
  "calories": 0,
  "number_of_hours_to_sleep_per_day": 3,
  "createdAt": "2017-11-14T17:23:31.000Z",
  "updatedAt": "2017-11-14T17:25:37.000Z"
}
""".utf8)

do {
    let user = try User(data: data)
    print(user)  // User(id: 2, email: "22222@gmail.com", password: "123456", userName: "number 2 name", fullName: "danial kosarifar", sex: "male", height: 0, weight: 0, mealsPerDay: 3, waterAmount: 0, calories: 0, hoursToSleepPerDay: 3, createdAt: 2017-11-14 17:23:31 +0000, updatedAt: 2017-11-14 17:25:37 +0000)\n"
} catch {
    print(error)
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571