I struggle with Swift and I never had any experience with it. When I do POST request with text/string body to my api, I receive back JSON data, but I don't know how to extract that data from JSON to Swift. I tried writing the Codable but I was unsuccessful.
func loginCall() {
guard let url = URL(string: "http://192.168.0.50/api/v1/?op=ilogin") else {
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
let body = "email=myemail#gmail.com&password=jdsdsdsdf&ver=0.1";
request.httpBody = body.data(using: String.Encoding.utf8)
let session = URLSession.shared
let dataTask = session.dataTask(with: request) { (data, response, error) in
if error == nil && data != nil {
let decoder = JSONDecoder()
do {
let loginDetailsJSON = try JSONSerialization.jsonObject(with: data!)
print(loginDetailsJSON)
}
catch
{
print("Error JSON")
}
}
}
dataTask.resume()
}
The response from my api
{"error":false,"data":{"name":"Test Name","age":18,"active":true},"message":"LOGIN: Success!"}
My Codable
struct LoginUser: Codable
{
var error:Bool?
var data:[LoginUserData]?
var message:String?
}
struct LoginUserData: Codable
{
var name:String
var age:Int
var active:Bool?
}
Whenever I try to decode it with my Codable I get error and the app crashes... I need to save any data from API to/in my app.
Related
The JSON data is
[
{"id":0,"temperature":77,"humidity":0.22,"timeCaptured":"2020-09-25T19:33:27.9733333"},
{"id":0,"temperature":77,"humidity":0.22,"timeCaptured":"2020-09-25T20:38:53.3"},
{"id":0,"temperature":85,"humidity":0.25,"timeCaptured":"2020-09-25T20:38:53.3"},
{"id":0,"temperature":88,"humidity":0.22,"timeCaptured":"2020-09-28T15:30:00"},
// ...
]
My structs look like this
struct TemperatureDataModel: Codable{
let id: Int?
let temperature: Double?
let humidty: Double?
let timeCaptured: String?
}
My function looks like this
func getTemperData(){
//Create the URLs
let temperatureDataUrl = URL(string: "https://weatherstationapi.azurewebsites.net/api/TemperatureSensor/GetData")
// let WindDataUrl = URL(string: "https://weatherstationapi.azurewebsites.net/api/WindData/GetAllData")
guard let requestURLTemp = temperatureDataUrl else { fatalError() }
//Create URL request
var request = URLRequest(url: requestURLTemp)
//Specifiy HTTP Method to use
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiaWxpci50YWlyaUB0dHUuZWR1IiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiI4MjEzYzhhMy1iODgxLTQ4NmUtOGUyMC1mZmNlMDlmNGY0ZjgiLCJuYmYiOiIxNjAyNTI2NDI1IiwiZXhwIjoiMTYwNTExODQyNSJ9.t1qnYyXLpRRJ3YQfhgLrylBqL_pdKOnKVMgOfG9IuVc", forHTTPHeaderField: "Authorization")
//Send HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else {return}
print(data)
//Use parseJSON to convert data
let TemperatureData = parseJSON(data: data)
// for singleValue in TemperatureData {
// print(singleValue.temperautre)
// }
//read list
guard let TemperatureDataModel = TemperatureData else {return}
print("Temperature is : \(TemperatureDataModel.temperature)")
// Check if error took place
if let error = error {
print("Error took place \(error)")
return
}
//Read HTTP Response Status Code
// if let data = data, let dataString = String(data: data, encoding: .utf8) {
// print("Response data string:\n \(dataString)")
// }
}
task.resume()
}
and then my JSON decoder function looks like this
func parseJSON(data: Data) -> TemperatureDataModel? {
var returnValue: TemperatureDataModel?
do {
let returnValue = try JSONDecoder().decode([TemperatureDataModel].self, from: data)
} catch {
print("Error took place \(error).")
}
return returnValue
}
I've looked at 6+ stack overflow posts now and still cannot figure It out. Ive tried putting my model in [] for an array, moving where the function is called, changing the jsondecoder function and more and nothing works.
I think you have to give a format to the date before you parse the data
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
Your issue there is that you are creating another returnValue that is not being returned. You need also change the return type to [TemperatureDataModel]
func parseJSON(data: Data) -> [TemperatureDataModel]? {
do {
return try JSONDecoder().decode([TemperatureDataModel].self, from: data)
} catch {
print("Error took place \(error).")
return nil
}
}
I want the 'success' value in json object but the problem is I'm getting whole json data I want only 'success' value to print
Here is my json`
{
response = {
success = 1;
successmsg = "Successful Connection";
};
}`
Here is my code in swift 5
#IBAction func girisButtonTap(_ sender: Any) {
var txtusername: String
var txtpassword: String
txtusername = usercodeText.text!
txtpassword = passwordText.text!
let Url = String(format: "http://10.10.10.53:8080/sahambl/rest/sahamblsrv/userlogin")
guard let serviceUrl = URL(string: Url) else { return }
let parameters: [String: Any] = [
"request": [
"xusercode" : "\(txtusername)",
"xpassword": "\(txtpassword)"
]
]
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else {
return
}
request.httpBody = httpBody
request.timeoutInterval = 20
let session = URLSession.shared
struct ResponseJSON: Codable {
let response: Response
}
struct Response: Codable {
let success: Int
let successmsg: String
}
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONDecoder().decode(ResponseJSON.self, from: data)
print(json)
let successful = json.response.success == 1
} catch {
print(error)
}
}
}.resume()
}
}
I would be grateful for any progress.
Use a model struct and Codable for parsing:
struct ResponseJSON: Codable {
let response: Response
}
struct Response: Codable {
// depending on what your JSON actually looks like, this could also be
// let success: Bool
let success: Int
let successmsg: String
}
session.dataTask(with: request) { data, response, error in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONDecoder().decode(ResponseJSON.self, from: data)
print(json)
// access the success property:
let successful = json.response.success == 1
// leave off the "== 1" if it's a Bool
} catch {
print(error)
}
}
}.resume()
I'm a student and I am trying to get a Json Data from an Http Server, and after that save it using UserDefaults
I saw some examples and this code I made seemed to make sense even though it did not work
That is my struct I'm using to decode the json Data
struct UserLogged : Decodable {
var token: String
var userId: String
}
And this is the code I'm trying to use
guard let baseUrl = URL(string: "http://LOCALHOST:8080/auth/login") else {
return
}
var request = URLRequest(url: baseUrl);
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST";
request.httpBody = jsonData;
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print(data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
if let user : UserLogged = try JSONDecoder().decode(UserLogged.self, from: data) {
UserDefaults.standard.set(user, forKey: "userLogged")
}
} catch {
print(error)
}
}
}.resume()
You can parse that json with a decoder easily instead of JSONSerialization. It is better to save the token of user in UserDefaults instead of whole user, with a key that makes sense such as userToken:
if let data = data {
print(data)
let decoder = JSONDecoder()
do {
let user = try decoder.decode(UserLogged.self, from: data)
//now you parsed the json and get token and userId
UserDefaults.standard.set(user.token, forKey: "userToken")
} catch {
//Parsing error, couldnt parse user.
}
}
I am using the JSONEncoder that has been provided with Swift4.
I have a class called Customer that uses the Codable protocol. Inside of Customer there are four Strings.
class Customer: Codable {
var title: String
var firstName: String
var lastName: String
var email: String
}
Reading JSON with a GET Request works fine.
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
}
guard let data = data else { return }
do {
let customer = try JSONDecoder().decode(Customer.self, from: data)
DispatchQueue.main.async {
print("\(customer.title)")
print("\(customer.firstName)")
print("\(customer.lastName)")
print("\(customer.email)")
}
} catch let jsonError {
print(jsonError)
}
}.resume()
However when I start to do a POST request I am lost:
First set up the request object:
let urlString = "http://localhost:8000/customer"
guard let url = URL(string: urlString) else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
let customer = Customer()
customer.title = "Mr"
customer.firstName = "Chuck"
customer.lastName = "Norris"
customer.email = "chuck.norris#awsome.com"
let encodedData = try? JSONEncoder().encode(customer)
print(String(data: encodedData!, encoding: .utf8)!) //<- Looks as intended
// Output is {"firstName":"Chuck","lastName":"Norris","title":"MR","email":"chuck.norris#awesome.com "}
Now send it out
request.httpBody = encodedData //
URLSession.shared.dataTask(with: request, completionHandler: {(data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.data(withJSONObject: data, options: [])
print(json)
}catch {
print(error)
}
}
})
In return I receive the message "The given data was not valid JSON."
So, my assumption is that I simply can not just put the encoded JSON data into the http body of my request.
Browsing through some articles about URLSession and JSON I found that it seems that I need to serialize my encoded JSON:
var json: Any?
if let data = encodedData {
json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
}
Now, I don't know how to proceed. First I do not understand why I should serialize my JSON to something that can not simply put into a httpBody.
Because JSONSerialization.jsonObject produces Any? and not Data.
Update
Now, I was able to successfully send my data to my server. I am still trying to understand what was wrong - because I did not changed anything (except for the removal of the JSONSerialization call inside the completion Handler. I will investigate further...
...And .resume had been missing. :-)
I successfully get data from RSS feeds all the time but I am having a problem with this one and for the life of me I can't tell what the issue is.
Below code executes, returns 200 status code and no content
let urlTMC = URL(string: "https://teslamotorsclub.com/tmc/forums/model-s.73/index.rss")!
let urlRequest = NSMutableURLRequest(url: urlTMC as URL)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest as URLRequest, completionHandler: { data, response, error in
print(data)
print(response)
print(error)
if let response = response, let data = data {
do {
let jsonData = JSON(data: data)
print(jsonData)
} catch {
print("JSONSerial error")
}
}
else {
print(error!)
}
DispatchQueue.main.async(execute: {
print("DISPATCH")
})
})
task.resume()