Cómo hacer una solicitud HTTP Post con JSON body en Swift

125

Estoy tratando de hacer una solicitud de publicación HTTP con un cuerpo JSON:

Cómo poder agregar un NSdictionnary al cuerpo de la solicitud HTTP.

Aquí está mi código, no parece funcionar correctamente.

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()
Extraño B.
fuente

Respuestas:

212

Prueba esto,

// 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()

o prueba de una manera conveniente Alamofire

nRewik
fuente
1
muy hermoso. versión agregada con la última sintaxis Swift (parece cambiar cada semana)
Fattie
1
@JoeBlow: publique su alternativa como una nueva respuesta. Es demasiado radicalmente diferente para editarlo.
ChrisF
6
@JoeBlow - No estoy seguro de que haya un consenso de la comunidad sobre esto, así que volví a revertir la edición y pregunté sobre esto en Meta.SO: meta.stackoverflow.com/questions/339024/…
Brad Larson
2
Para mí, agregar esto me ayudó: request.setValue("\(jsonData.length)", forHTTPHeaderField: "Content-Length") request.setValue("application/json", forHTTPHeaderField: "Content-Type") Ref
Mohammad Zaid Pathan
1
Esto es peligroso a menos que también establece el encabezado de tipo de contenido correctamente: request.addValue("application/json", forHTTPHeaderField: "Content-Type"). De lo contrario, hace el tipo de formularios. La configuración súper común de ExpressJS + bodyParser obtendrá resultados incorrectos para esto solo algunas veces, dependiendo del contenido . Entonces esto genera fracasos silenciosos.
sudo
46

HTTP Post en Swift capturando los errores

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)
}
Bernauer
fuente
es la solicitud de envío asíncrono
G. Abhisek
1
@Logan los documentos dicen que dataTaskWithRequest proporciona "una interfaz asincrónica cancelable simple para recibir datos". Así que supongo que esta llamada ya es asincrónica sin dispatch_async
David Schumann
44

Swift 4 y 5

HTTP POST requestusar URLSession APIen 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)")
    }
}

Usando Alamofire:

let parameters = ["name": "username", "password": "password123"]
Alamofire.request("https://www.myserver.com/api/login", method: .post, parameters: parameters, encoding: URLEncoding.httpBody)
Suhit Patil
fuente
Estuve buscando este "URLEncoding.httpBody" por un tiempo, gracias
Tiago Mendes
10

El siguiente código de Swift 5 Playground muestra una forma posible de resolver su problema usando JSONSerializationy 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()
Imanou Petit
fuente
Especificar "application / json" como ContentType es muy importante. de lo contrario, la solicitud se ejecutará como de forma habitual HTTP. buena respuesta.
heximal
5
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()
Hitesh Chauhan
fuente
4

Respuesta perfecta de nRewik actualizada a 2019:

Haz el diccionario:

let dic = [
    "username":u,
    "password":p,
    "gems":g ]

Móntelo así:

var jsonData:Data?
do {
    jsonData = try JSONSerialization.data(
      withJSONObject: dic,
      options: .prettyPrinted)
} catch {
    print(error.localizedDescription)
}

Cree la solicitud exactamente así, observe que es una "publicación"

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

Luego envíe, verificando si hay un error de red (por lo tanto, no hay ancho de banda, etc.) o una respuesta de error del servidor:

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)")

Afortunadamente ahora es así de fácil.

Fattie
fuente
3

puedes hacer algo como esto:

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);
}
Daniel Krom
fuente
3

SWIFT 5 personas aquí:

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()
Govani Dhruv Vijaykumar
fuente
Respuesta correcta. Esto funcionó en una forma de copiar y pegar para mí.
podcastfan88
1
var request = URLRequest(url: URL(string: "http://yogpande.apphb.com/api/my/posttblhouse")!)
        request.httpMethod = "POST"
        let postString = "[email protected]&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()
    }
Neel Shah
fuente
1

Swift4 - Solución de Apple "POST" y "Codificable"

Subir datos a un sitio web mediante request.httpmethod = "Publicar" y elementos codificables :

@see: Listado 2 Configurando una solicitud de URL

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 ...
andreas-supersmart
fuente
Esta respuesta no fue realmente buena; sin embargo, el enlace tenía un código utilizable reciente. 😃
Jonny
@Jonny: Es solo la configuración mínima para obtener un POST, pero tienes razón, no falta la parte codificable ... ¡culpa mía! Actualicé esto ahora.
andreas-supersmart
Sí, las estructuras codificables son el futuro 🚀
Jonny
¡Hola! Encontré esta respuesta, pero no puedo usarla para resolver mi pregunta, ¿podría alguien ayudarme aquí ?: stackoverflow.com/questions/53598917/…
biggreentree
1
    // 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()
Nikunj Patel
fuente
0
    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()
jignesh kasundra
fuente
0
func fucntion()
{

    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")
        }
    }
Jignesh ZestBrains
fuente
0

una combinación de varias respuestas encontradas en mi intento de no usar marcos de terceros como Alamofire.

    let body: [String: Any] = ["provider": "Google", "email": "[email protected]"]
    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()
Eric Stevenson
fuente
0
import UIKit

class ViewController: UIViewController {

    var getdata = NSMutableData()
    @IBOutlet weak var password_txt: UITextField!
    @IBOutlet weak var mobile_txt: UITextField!
    @IBOutlet weak var email_txt: UITextField!
    @IBOutlet weak var name_txt: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.

    }
    @IBAction func RegAction(_ sender: UIButton) {
        let url = URL(string: "https//.....")
        var requrl = URLRequest(url: url!)
        requrl.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "content_type")
        requrl.httpMethod = "post"
        let postString = "name=\(name_txt.text!)&email=\(email_txt.text!)&mobile=\(mobile_txt.text!)&password=\(password_txt.text!)"
        print("poststring-->>",postString)
        requrl.httpBody = postString.data(using: .utf8)
        let task = URLSession.shared.dataTask(with: requrl){(data,response,error) in
            let mydata = data
            do{
                print("mydata",mydata!)
                do{
                    self.getdata.append(mydata!)
                    let jsondata = try JSONSerialization.jsonObject(with: self.getdata as Data, options: [])
                    print("jsondata-->",jsondata)
                }
            }
            catch
            {
                print("error-->",error.localizedDescription)
            }
        };
        task.resume()

    }
}
`GET METHOD`
import UIKit

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
    var dataarray = [[String: Any]]()
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataarray.count
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 450.0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
        let  item = dataarray[indexPath.row]

        cell.name_txt.text = item["name"]as? String ?? ""
        cell.pname_txt.text = item["realname"]as? String ?? ""
        cell.team_txt.text = item["team"]as? String ?? ""
        cell.firstapp_txt.text = item["firstappearance"]as? String ?? ""
        cell.Createdby_txt.text = item["createdby"]as? String ?? ""
        cell.Publisher_txt.text = item["publisher"]as? String ?? ""

        if item["imageurl"]as? String ?? "" != ""{
            let url = URL(string: item["imageurl"]as? String ?? "")
            if url != nil{
                let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
                cell.imgvw.image = UIImage(data: data!)
            }
        }
        return cell
     }


    @IBOutlet weak var apiTable: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
    override func viewWillAppear(_ animated: Bool) {
        guard let url = URL(string: "https://www.simplifiedcoding.net/demos/marvel/")
            else {return}
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            guard let dataResponse = data,
                error == nil else {
                    print(error?.localizedDescription ?? "Response Error")
                    return }
            do{
                //here dataResponse received from a network request
                let jsonResponse = try JSONSerialization.jsonObject(with:
                    dataResponse, options: []) as? [[String:Any]] ?? [[:]]
                print("jsonResponse---->",jsonResponse) //Response result

                self.dataarray = jsonResponse
                DispatchQueue.main.async {



                    self.apiTable.reloadData()
                }
            } catch let parsingError {
                print("Error", parsingError)
            }
        }
        task.resume()
    }

}
Gleny rebelde
fuente
Es mejor incluir una descripción de su problema en lugar de simplemente pegar el código.
Calos