I am really getting stuck on this.
I have created a JSON service, that returns data like this:
[
{
"docNameField": "Test",
"docNumField": 22832048,
"docVerField": 1,
"docDataBaseField": "Legal",
"docCheckedOutWhenField": "03/05/2020",
"whereCheckedOutField": "PC0X8J9RD"
}
]
This is Postman output.
No matter how I try, I cannot seem to be able to put together the correct combination og HTTP call, deserialization, types and so on to get a list of objects out in the end.
This func below outputs this:
JSON String: Optional("[{\"docNameField\":\"Test\",\"docNumField\":22832048,\"docVerField\":1,\"docDataBaseField\":\"Legal\",\"docCheckedOutWhenField\":\"03/05/2020\",\"whereCheckedOutField\":\"PC0X8J9RD\"}]")
func LoadLockedDocumentsByDocnum(docNum:Int32) {
let json: [String: Any] = ["action":"getCheckedOutDocuments","adminUserName":"\(APPuserName)","adminPassword":"\(APPuserPassword)","adminDomain":"\(APPuserDomain)","applicationKey":"19730905{testKey}","searchTerm":docNum]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
self.documentEntries.removeAll()
let url = URL(string: "https://{URL}//CheckOut")!
var request = URLRequest(url: url)
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") //Optional
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let session = URLSession.shared
let dataTask = session.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if let resultat = response as! HTTPURLResponse?{
if resultat.statusCode == 200{
if error != nil {
}
else {
print(data!)
if let nydata = data{
print("JSON String: \(String(data: data!, encoding: .utf8))")
}
}
}}
}
dataTask.resume()
}
You seem to have come pretty close. To get a list of objects out, you first need to declare that object:
struct MyResponseObject: Decodable { // please give this a better name
let docNameField: String
let docNumField: Int
let docVerField: Int
let docDataBaseField: String
let docCheckedOutWhenField: Date
let whereCheckedOutField: String
}
And then use a JSONDecoder to deserialise the JSON. Instead of:
print("JSON String: \(String(data: data!, encoding: .utf8))")
write:
let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"
decoder.dateDecodingStrategy = .formatted(formatter)
do {
// here's your list of objects!
let listOfObjects = try decoder.decode([MyResponseObject].self, from: data!)
} catch let error {
print(error) // an error occurred, you can do something about it here
}
I try to send an image to the MS Cognitive Services Visions API in a Swift Playground.
The message I get as response is:
Response ["requestId": …, "code": InternalServerError, "message": Internal server error.]
Here is the code I use
let image = #imageLiteral(resourceName: "paper.jpg")
let imageData = UIImageJPEGRepresentation(image, 1)!
let endpoint = ("https://westeurope.api.cognitive.microsoft.com/vision/v1.0/analyze?visualFeatures=Description,Categories,Tags&subscription-key=\(subscriptionKey)")
let requestURL = URL(string: endpoint)!
let session = URLSession(configuration: URLSessionConfiguration.default)
var request:URLRequest = URLRequest(url: requestURL)
request.httpMethod = "POST"
// Image
let boundary = UUID().uuidString
request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var body = NSMutableData()
body.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"image.jpg\"\\r\n".data(using: .utf8)!)
body.append("Content-Type: application/octet-stream\r\n\r\n".data(using: .utf8)!)
body.append(imageData)
body.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
request.httpBody = body as Data
let task = session.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
print("Response \(json)")
} catch let error as Error {
print("Error \(error)")
}
}
task.resume()
I suspect I am not sending the image correctly. Any ideas?
It's probably best to not bother with a multi-part MIME, especially when you consider that the other Cognitive Service properties (namely Face and Emotion) don't support it.
let subscriptionKey = "YOUR-KEY"
let image = #imageLiteral(resourceName:"monkey.jpg")
let imageData = UIImageJPEGRepresentation(image, 1.0)!
let endpoint = ("https://westus.api.cognitive.microsoft.com/vision/v1.0/analyze?visualFeatures=Description,Categories,Tags")
let requestURL = URL(string: endpoint)!
let session = URLSession(configuration: URLSessionConfiguration.default)
var request:URLRequest = URLRequest(url: requestURL)
request.httpMethod = "POST"
request.addValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
request.addValue(subscriptionKey, forHTTPHeaderField: "Ocp-Apim-Subscription-Key")
request.httpBody = imageData
var semaphore = DispatchSemaphore.init(value: 0);
let task = session.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
print("Response \(json)")
} catch let error as Error {
print("Error \(error)")
}
semaphore.signal()
}
task.resume()
semaphore.wait()
I'm trying to make an HTTP post request with a JSON body :
How to be able to add an NSdictionnary to the HTTP request body.
Here is my code, it doesn't seem to work properly.
var entry1 = Response(IdQuestion: 6510,IdProposition: 10,Time: 30)
var entry2 = Response(IdQuestion: 8284,IdProposition: 10,Time: 30)
Responses.append(entry1)
Responses.append(entry2)
let list = Responses.map { $0.asDictionary }
let json = ["List":list,"IdSurvey":"102","IdUser":"iOSclient","UserInformation":"iOSClient"]
let data: NSData = NSKeyedArchiver.archivedDataWithRootObject(json)
NSJSONSerialization.isValidJSONObject(json)
let myURL = NSURL(string: "http://www.myserver.com")!
let request = NSMutableURLRequest(URL: myURL)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.HTTPBody = data
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
println(response)
// Your completion handler code here
}
task.resume()
Try this,
// prepare json data
let json: [String: Any] = ["title": "ABC",
"dict": ["1":"First", "2":"Second"]]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// create post request
let url = URL(string: "http://httpbin.org/post")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
}
task.resume()
or try a convenient way Alamofire
Swift 4 and 5
HTTP POST request using URLSession API in Swift 4
func postRequest(username: String, password: String, completion: #escaping ([String: Any]?, Error?) -> Void) {
//declare parameter as a dictionary which contains string as key and value combination.
let parameters = ["name": username, "password": password]
//create the url with NSURL
let url = URL(string: "https://www.myserver.com/api/login")!
//create the session object
let session = URLSession.shared
//now create the Request object using the url object
var request = URLRequest(url: url)
request.httpMethod = "POST" //set http method as POST
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) // pass dictionary to data object and set it as request body
} catch let error {
print(error.localizedDescription)
completion(nil, error)
}
//HTTP Headers
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
//create dataTask using the session object to send data to the server
let task = session.dataTask(with: request, completionHandler: { data, response, error in
guard error == nil else {
completion(nil, error)
return
}
guard let data = data else {
completion(nil, NSError(domain: "dataNilError", code: -100001, userInfo: nil))
return
}
do {
//create json object from data
guard let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] else {
completion(nil, NSError(domain: "invalidJSONTypeError", code: -100009, userInfo: nil))
return
}
print(json)
completion(json, nil)
} catch let error {
print(error.localizedDescription)
completion(nil, error)
}
})
task.resume()
}
#objc func submitAction(_ sender: UIButton) {
//call postRequest with username and password parameters
postRequest(username: "username", password: "password") { (result, error) in
if let result = result {
print("success: \(result)")
} else if let error = error {
print("error: \(error.localizedDescription)")
}
}
Using Alamofire:
let parameters = ["name": "username", "password": "password123"]
Alamofire.request("https://www.myserver.com/api/login", method: .post, parameters: parameters, encoding: URLEncoding.httpBody)
HTTP Post in Swift capturing the errors
let json = [ Activity.KEY_IDSUBJECT : activity.idSubject, Activity.KEY_RECORDMODE : "3", Activity.KEY_LOCATION_LONGITUDE : "0",Activity.KEY_LOCATION_LATITUDE : "0", Activity.KEY_CHECKIN : String(activity.dateCheckIn), Activity.KEY_CHECKOUT : String(activity.dateCheckOut) ]
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(json, options: .PrettyPrinted)
// create post request
let url = NSURL(string: "https://...appspot.com/_ah/api/activityendpoint/v1/activity")!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
// insert json data to the request
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.HTTPBody = jsonData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data, response, error in
if error != nil{
print("Error -> \(error)")
return
}
do {
let result = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String:AnyObject]
print("Result -> \(result)")
} catch {
print("Error -> \(error)")
}
}
task.resume()
return task
} catch {
print(error)
}
Swift 5 answer:
let json: [String: Any] = ["key": "value"]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// create post request
let url = URL(string: "http://localhost:1337/postrequest/addData")! //PUT Your URL
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("\(String(describing: jsonData?.count))", forHTTPHeaderField: "Content-Length")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// insert json data to the request
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON) //Code after Successfull POST Request
}
}
task.resume()
The following Swift 5 Playground code shows a possible way to solve your problem using JSONSerialization and URLSession:
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let url = URL(string: "http://localhost:8080/new")!
let jsonDict = ["firstName": "Jane", "lastName": "Doe"]
let jsonData = try! JSONSerialization.data(withJSONObject: jsonDict, options: [])
var request = URLRequest(url: url)
request.httpMethod = "post"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print("error:", error)
return
}
do {
guard let data = data else { return }
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: AnyObject] else { return }
print("json:", json)
} catch {
print("error:", error)
}
}
task.resume()
let url = URL(string: "url")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.httpMethod = "POST"
let postString = "ChangeAccordingtoyourdata=\(paramOne)&ChangeAccordingtoyourdata2=\(paramTwo)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
SVProgressHUD.showError(withStatus: "Request has not submitted successfully.\nPlease try after some time")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
SVProgressHUD.showSuccess(withStatus: "Request has submitted successfully.\nPlease wait for a while")
DispatchQueue.main.async {
// enter code
}
}
task.resume()
Perfect nRewik answer updated to 2019:
Make the dictionary:
let dic = [
"username":u,
"password":p,
"gems":g ]
Assemble it like this:
var jsonData:Data?
do {
jsonData = try JSONSerialization.data(
withJSONObject: dic,
options: .prettyPrinted)
} catch {
print(error.localizedDescription)
}
Create the request exactly like this, notice it is a "post"
let url = URL(string: "https://blah.com/server/dudes/decide/this")!
var request = URLRequest(url: url)
request.setValue("application/json; charset=utf-8",
forHTTPHeaderField: "Content-Type")
request.setValue("application/json; charset=utf-8",
forHTTPHeaderField: "Accept")
request.httpMethod = "POST"
request.httpBody = jsonData
Then send, checking for either a networking error (so, no bandwidth etc) or an error response from the server:
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
// check for fundamental networking error
print("fundamental networking error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
// check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
Fortunately it's now that easy.
you can do something like this:
func HTTPPostJSON(url: String, data: NSData,
callback: (String, String?) -> Void) {
var request = NSMutableURLRequest(URL: NSURL(string: url)!)
request.HTTPMethod = "POST"
request.addValue("application/json",forHTTPHeaderField: "Content-Type")
request.addValue("application/json",forHTTPHeaderField: "Accept")
request.HTTPBody = data
HTTPsendRequest(request, callback: callback)
}
func HTTPsendRequest(request: NSMutableURLRequest,
callback: (String, String?) -> Void) {
let task = NSURLSession.sharedSession()
.dataTaskWithRequest(request) {
(data, response, error) -> Void in
if (error != nil) {
callback("", error.localizedDescription)
} else {
callback(NSString(data: data,
encoding: NSUTF8StringEncoding)! as String, nil)
}
}
task.resume()
}
//use
var data :Dictionary<String, AnyObject> = yourDictionaryData<--
var requestNSData:NSData = NSJSONSerialization.dataWithJSONObject(request, options:NSJSONWritingOptions(0), error: &err)!
HTTPPostJSON("http://yourPosturl..", data: requestNSData) { (response, error) -> Void in
if error != nil{
//error
return;
}
println(response);
}
Swift4 - Apple Solution "POST" and "Codable"
Uploading Data to a Website using request.httpmethod = "Post" and Codable Stucts:
#see: Listing 2 Configuring a URL request
let userlogin = User(username: username, password: password, deviceid:UIDevice.current.identifierForVendor!.uuidString)
guard let uploadData = try? JSONEncoder().encode(userlogin) else {
print("Error UploadData: ")
return
}
let urlUser = URL(string: APPURL.apiURL)!
var request = URLRequest(url: urlUser)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
var responseStatus = 0
let task = URLSession.shared.uploadTask(with: request, from: uploadData) { data, response, error in
if let error = error {
let code = (error as NSError).code
print("Error:\(code) : \(error.localizedDescription)")
completion(code)
return
}
guard let response = response as? HTTPURLResponse else {
print("Invalid response")
return
}
// do your response handling here ...
No library required, simply use URLSession
here is an example:
let sampleData = ["key": "Value"]
var urlRequest = URLRequest(url: URL(string: "https://REPLACE.ME")!)
let urlSession = URLSession = URLSession(configuration: .default)
let encoder = JSONEncoder()
// inside a throwing function or wrap it in a doCatch block
let jsonData = try encoder.encode(sampleData)
urlRequest.httpMethod = "POST"
urlRequest.addValue("application/json",forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = jsonData
let task = urlSession.dataTask(with: urlRequest) { data, response, error in
let statusCode = (response as? HTTPURLResponse)?.statusCode
print("💁🏻♂️ \(statusCode)")
}
task.resume()
A combination of several answers found in my attempt to not use 3rd party frameworks like Alamofire:
let body: [String: Any] = ["provider": "Google", "email": "emailaddress#gmail.com"]
let api_url = "https://erics.es/p/u"
let url = URL(string: api_url)!
var request = URLRequest(url: url)
do {
let jsonData = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
request.httpBody = jsonData
} catch let e {
print(e)
}
request.httpMethod = HTTPMethod.post.rawValue
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
}
task.resume()
var request = URLRequest(url: URL(string: "http://yogpande.apphb.com/api/my/posttblhouse")!)
request.httpMethod = "POST"
let postString = "email=testname#gmail.com&password=1234567"
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=(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
}
task.resume()
}
For a Codable / Encodable type in Swift 4+
Use a JSONEncoder to transform the object into Data:
let jsonObject = ... // Encodable or Codable
guard let jsonData = try? JSONEncoder().encode(jsonObject) else {
fatalError("encoding error")
}
Then set that encoded object as the httpBody of the URLRequest:
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
Swift 5.5
As of Swift 5.5, we now have another alternative using async/await:
// Form the POST request:
let url = URL(string: "http://example.com/login")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
// Use the async variant of URLSession to make an HTTP POST request:
let (data, response) = try await URLSession.shared.upload(for: request, from: requestData)
Complete example:
struct LoginResponse: Decodable {
let id: String
let name: String
}
func login(_ username: String, _ password: String) async throws -> LoginResponse {
struct RequestData: Encodable {
let username: String
let password: String
}
// Encode data to JSON to send in the POST request body:
let encoder = JSONEncoder()
let requestData = try encoder.encode(RequestData(username: username, password: password))
// Form the POST request:
let url = URL(string: "http://example.com/login")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
// Use the async variant of URLSession to make an HTTP POST request:
let (data, response) = try await URLSession.shared.upload(for: request, from: requestData)
print("HTTPURLResponse:", response)
print("The response body is:", String(decoding: data, as: UTF8.self))
// Parse the JSON response:
return try JSONDecoder().decode(LoginResponse.self, from: data)
}
Usage
You must call it in an async context (so you can await it). One way is using a Task:
Task {
do {
let loginResponse = try await login("user1", "mypassword")
print("Login successful for user with id:", loginResponse.id)
} catch {
print(error)
}
}
// prepare json data
let mapDict = [ "1":"First", "2":"Second"]
let json = [ "title":"ABC" , "dict": mapDict ] as [String : Any]
let jsonData : NSData = NSKeyedArchiver.archivedData(withRootObject: json) as NSData
// create post request
let url = NSURL(string: "http://httpbin.org/post")!
let request = NSMutableURLRequest(url: url as URL)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData as Data
let task = URLSession.shared.dataTask(with: request as URLRequest){ data,response,error in
if error != nil{
return
}
do {
let result = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
print("Result",result!)
} catch {
print("Error -> \(error)")
}
}
task.resume()
var request = URLRequest(url: URL(string: "your URL")!)
request.httpMethod = "POST"
let postString = String(format: "email=%#&lang=%#", arguments: [txt_emailVirify.text!, language!])
print(postString)
emailString = txt_emailVirify.text!
request.httpBody = postString.data(using: .utf8)
request.addValue("delta141forceSEAL8PARA9MARCOSBRAHMOS", forHTTPHeaderField: "Authorization")
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil
else
{
print("error=\(String(describing: error))")
return
}
do
{
let dictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! NSDictionary
print(dictionary)
let status = dictionary.value(forKey: "status") as! String
let sts = Int(status)
DispatchQueue.main.async()
{
if sts == 200
{
print(dictionary)
}
else
{
self.alertMessageOk(title: self.Alert!, message: dictionary.value(forKey: "message") as! String)
}
}
}
catch
{
print(error)
}
}
task.resume()
func function()
{
var parameters = [String:String]()
let apiToken = "Bearer \(ApiUtillity.sharedInstance.getUserData(key: "vAuthToken"))"
let headers = ["Vauthtoken":apiToken]
parameters = ["firstname":name,"lastname":last_name,"mobile":mobile_number,"email":emails_Address]
Alamofire.request(ApiUtillity.sharedInstance.API(Join: "user/edit_profile"), method: .post, parameters: parameters, encoding: URLEncoding.default,headers:headers).responseJSON { response in
debugPrint(response)
if let json = response.result.value {
let dict:NSDictionary = (json as? NSDictionary)!
print(dict)
// print(response)
let StatusCode = dict.value(forKey: "status") as! Int
if StatusCode==200
{
ApiUtillity.sharedInstance.dismissSVProgressHUDWithSuccess(success: "Success")
let UserData = dict.value(forKey: "data") as! NSDictionary
print(UserData)
}
else if StatusCode==401
{
let ErrorDic:NSDictionary = dict.value(forKey: "message") as! NSDictionary
let ErrorMessage = ErrorDic.value(forKey: "error") as! String
}
else
{
let ErrorDic:NSDictionary = dict.value(forKey: "message") as! NSDictionary
let ErrorMessage = ErrorDic.value(forKey: "error") as! String
}
}
else
{
ApiUtillity.sharedInstance.dismissSVProgressHUDWithError(error: "Something went wrong")
}
}