Cómo enviar una solicitud POST con BODY en Swift

97

Estoy tratando de hacer una solicitud de publicación con un cuerpo en Swift usando Alamofire.

mi cuerpo json se ve así:

{
    "IdQuiz" : 102,
    "IdUser" : "iosclient",
    "User" : "iosclient",
    "List":[
        {
        "IdQuestion" : 5,
        "IdProposition": 2,
        "Time" : 32
        },
        {
        "IdQuestion" : 4,
        "IdProposition": 3,
        "Time" : 9
        }
    ]
}

Estoy tratando de hacer let listcon NSDictionnary que se parece a:

[[Time: 30, IdQuestion: 6510, idProposition: 10], [Time: 30, IdQuestion: 8284, idProposition: 10]]

y mi solicitud usando Alamofire se ve así:

Alamofire.request(.POST, "http://myserver.com", parameters: ["IdQuiz":"102","IdUser":"iOSclient","User":"iOSClient","List":list ], encoding: .JSON)
            .response { request, response, data, error in
            let dataString = NSString(data: data!, encoding:NSUTF8StringEncoding)
                println(dataString)
        }

La solicitud tiene un error y creo que el problema está en la lista del Diccionario, porque si hago una solicitud sin la lista, funciona bien, ¿alguna idea?


He probado la solución sugerida pero me enfrento al mismo problema:

 let json = ["List":list,"IdQuiz":"102","IdUser":"iOSclient","UserInformation":"iOSClient"]
        let data = NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions.PrettyPrinted,error:nil)
        let jsons = NSString(data: data!, encoding: NSUTF8StringEncoding)



    Alamofire.request(.POST, "http://myserver.com", parameters: [:], encoding: .Custom({
        (convertible, params) in
        var mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest
        mutableRequest.HTTPBody = jsons!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
        return (mutableRequest, nil)
    }))
        .response { request, response, data, error in
        let dataString = NSString(data: data!, encoding:NSUTF8StringEncoding)
           println(dataString)
    }
Extraño B.
fuente
3
posible duplicado de la solicitud POST con una cadena simple en el cuerpo con Alamofire
EI Captain v2.0
1
Gracias por tu comentario, pero la publicación que proporcionaste no ayuda, y no estoy tratando de pasar una cadena como cuerpo, así que puedes leer la publicación con atención
Stranger B.
@YasserB. Convierta su JSON en un NSString (hay un método para eso) y luego use el enlace de @Bhavin.
Larme
@Larme sería de gran ayuda si me dieras un ejemplo
Stranger B.
@Larme Probé la solución sugerida pero tengo el mismo problema, la solicitud no funciona a menos que elimine la lista del cuerpo del hijo
Extraño B.

Respuestas:

97

Estás cerca. El formato del diccionario de parámetros no parece correcto. Deberías probar lo siguiente:

let parameters: [String: AnyObject] = [
    "IdQuiz" : 102,
    "IdUser" : "iosclient",
    "User" : "iosclient",
    "List": [
        [
            "IdQuestion" : 5,
            "IdProposition": 2,
            "Time" : 32
        ],
        [
            "IdQuestion" : 4,
            "IdProposition": 3,
            "Time" : 9
        ]
    ]
]

Alamofire.request(.POST, "http://myserver.com", parameters: parameters, encoding: .JSON)
    .responseJSON { request, response, JSON, error in
        print(response)
        print(JSON)
        print(error)
    }

Con suerte, eso solucionó tu problema. Si no es así, responda y ajustaré mi respuesta en consecuencia.

por la tarde
fuente
¿Cómo se configura una propiedad de mi JSON a nula, ya que no puedo asignar nila AnyObject?
Amp Tanawat
3
@JaseemAbbas verifica tu versión de Alamofire, si estás en la v4.0 + mira mi respuesta a continuación
Gianni Carlo
cómo enviar este tipo de parámetro en caso de que la codificación sea .urlEncoding
Pramod Shukla
1
No se puede convertir el valor del tipo 'Int' al tipo de valor esperado del diccionario 'AnyObject'
myatmins
¿Cómo se hace si digamos que el valor del parámetro "Lista" tiene como 1000 elementos de lista?
Nishad Arora
175

Si está utilizando Alamofire v4.0 +, la respuesta aceptada se vería así:

let parameters: [String: Any] = [
    "IdQuiz" : 102,
    "IdUser" : "iosclient",
    "User" : "iosclient",
    "List": [
        [
            "IdQuestion" : 5,
            "IdProposition": 2,
            "Time" : 32
        ],
        [
            "IdQuestion" : 4,
            "IdProposition": 3,
            "Time" : 9
        ]
    ]
]

Alamofire.request("http://myserver.com", method: .post, parameters: parameters, encoding: JSONEncoding.default)
    .responseJSON { response in
        print(response)
    }
Gianni Carlo
fuente
6
¡Excelente! ¡Cambie la respuesta aceptada a esta por favor! :) o combinar con el actual para las soluciones Alamofire 3 y 4.
Tom van Zummeren
1
De acuerdo, es la declaración explícita de JSONEncodingdesambiguar al tipo que lo hizo por mí.
Thomas Verbeek
@Gianni Carlo Usé lo mismo que tu respuesta, pero en mi respuesta de éxito recibo errores.
Ramakrishna
@Ramakrishna que podría estar relacionado con la API que está consumiendo. Para analizar la respuesta, generalmente uso la biblioteca SwiftyJSON, hágamelo saber qué tipo de errores está recibiendo
Gianni Carlo
Gracias por su respuesta. Tengo la solucion.
Ramakrishna
34

No me gusta ninguna de las otras respuestas hasta el momento (excepto quizás el uno por SwiftDeveloper), ya sea porque requieren que deserializar su JSON, sólo para que pueda ser serializado de nuevo, o la atención acerca de la estructura de la propia JSON.

La respuesta correcta ha sido publicada por afrodev en otra pregunta. Deberías ir y votarlo.

A continuación se muestra solo mi adaptación, con algunos cambios menores (principalmente juego de caracteres UTF-8 explícito).

let urlString = "https://example.org/some/api"
let json = "{\"What\":\"Ever\"}"

let url = URL(string: urlString)!
let jsonData = json.data(using: .utf8, allowLossyConversion: false)!

var request = URLRequest(url: url)
request.httpMethod = HTTPMethod.post.rawValue
request.setValue("application/json; charset=UTF-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData

Alamofire.request(request).responseJSON {
    (response) in

    print(response)
}
Costa del mar del Tíbet
fuente
Estoy de acuerdo en que la respuesta de @ SwiftDeveloper es mejor y (en mi opinión) más completa que la 'correcta' que mencionas. Pero yo diría dos puntos. Uno, que la 'respuesta correcta' que mencionas tiene la falla de que toJSONStringno es un método nativo, por lo que básicamente es una caja negra que debes implementar. Dos, la respuesta que da, proporciona una var jsonque comienza como una cadena json, de manera realista, nadie tiene los parámetros de esa manera, a menos que los esté convirtiendo y almacenando localmente de esa manera.
Gianni Carlo
@GianniCarlo 1) no hay toJSONStringen mi respuesta, 2) "de manera realista, nadie tiene los parámetros de esa manera" - eso es hacer muchas suposiciones; el JSON puede provenir de partes bastante diferentes de la aplicación, no relacionadas con la realización de la solicitud, y de las cuales el código de red no sabe nada.
Sea Coast of Tibet
¡¡¡Gracias por hacerme la vida más fácil !!! 1 Estoy usando Alamofire con Flask Backend. Desde Postman todo funcionó bien, pero desde Alamofire no funciona. Parámetros de URL y cuerpo HTTP y cómo configurarlos. Gracias de nuevo.
Vineel
8

Xcode 8.X, Swift 3.X

Fácil uso;

    let params:NSMutableDictionary? = [
    "IdQuiz" : 102,
    "IdUser" : "iosclient",
    "User" : "iosclient",
    "List": [
        [
            "IdQuestion" : 5,
            "IdProposition": 2,
            "Time" : 32
        ],
        [
            "IdQuestion" : 4,
            "IdProposition": 3,
            "Time" : 9
        ]
    ]
];
            let ulr =  NSURL(string:"http://myserver.com" as String)
            let request = NSMutableURLRequest(url: ulr! as URL)
            request.httpMethod = "POST"
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
            let data = try! JSONSerialization.data(withJSONObject: params!, options: JSONSerialization.WritingOptions.prettyPrinted)

            let json = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
            if let json = json {
                print(json)
            }
            request.httpBody = json!.data(using: String.Encoding.utf8.rawValue);


            Alamofire.request(request as! URLRequestConvertible)
                .responseJSON { response in
                    // do whatever you want here
                   print(response.request)  
                   print(response.response) 
                   print(response.data) 
                   print(response.result)

            }
Desarrollador rápido
fuente
7

Si está utilizando swift4y Alamofire v4.0el código aceptado se vería así:

            let parameters: Parameters = [ "username" : email.text!, "password" : password.text! ]
            let urlString = "https://api.harridev.com/api/v1/login"
            let url = URL.init(string: urlString)
            Alamofire.request(url!, method: .put, parameters: parameters, encoding: JSONEncoding.default, headers: nil).responseJSON { response in
                 switch response.result
                {
                case .success(let json):
                    let jsonData = json as! Any
                    print(jsonData)
                case .failure(let error):
                    self.errorFailer(error: error)
                }
            }
Mohammed Ali Khaled
fuente
5

Respuesta aceptada en Xcode 11 - Swift 5 - Alamofire 5.0

func postRequest() {
    let parameters: [String: Any] = [
        "IdQuiz" : 102,
        "IdUser" : "iosclient",
        "User" : "iosclient",
        "List": [
            [
                "IdQuestion" : 5,
                "IdProposition": 2,
                "Time" : 32
            ],
            [
                "IdQuestion" : 4,
                "IdProposition": 3,
                "Time" : 9
            ]
        ]
    ]
    AF.request("http://myserver.com", method:.post, parameters: parameters,encoding: JSONEncoding.default) .responseJSON { (response) in
        print(response)
    }
}
Hari R Krishna
fuente
4

He editado un poco la respuesta de SwiftDeveloper porque no me funcionaba. También agregué la validación de Alamofire.

let body: NSMutableDictionary? = [
    "name": "\(nameLabel.text!)",
    "phone": "\(phoneLabel.text!))"]

let url = NSURL(string: "http://server.com" as String)
var request = URLRequest(url: url! as URL)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let data = try! JSONSerialization.data(withJSONObject: body!, options: JSONSerialization.WritingOptions.prettyPrinted)

let json = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
if let json = json {
    print(json)
}
request.httpBody = json!.data(using: String.Encoding.utf8.rawValue)
let alamoRequest = Alamofire.request(request as URLRequestConvertible)
alamoRequest.validate(statusCode: 200..<300)
alamoRequest.responseString { response in

    switch response.result {
        case .success:
            ...
        case .failure(let error):
            ...
    }
}
effeKtSVK
fuente
1
Todavía funciona en Alamofire 4.9.1 y Swift 5.1. Muy apreciado
Abe
2

Hay algunos cambios que me gustaría notificar. Puede acceder a la solicitud, JSON, error del objeto de respuesta a partir de ahora.

        let urlstring = "Add URL String here"
        let parameters: [String: AnyObject] = [
            "IdQuiz" : 102,
            "IdUser" : "iosclient",
            "User" : "iosclient",
            "List": [
                [
                    "IdQuestion" : 5,
                    "IdProposition": 2,
                    "Time" : 32
                ],
                [
                    "IdQuestion" : 4,
                    "IdProposition": 3,
                    "Time" : 9
                ]
            ]
        ]

        Alamofire.request(.POST, urlstring, parameters: parameters, encoding: .JSON).responseJSON { response in
            print(response.request)  // original URL request
            print(response.response) // URL response
            print(response.data)     // server data
            print(response.result)   // result of response serialization

            if let JSON = response.result.value {
                print("JSON: \(JSON)")
            }
            response.result.error
        }
Kiran Jasvanee
fuente
2

Alamofire Fetch data con POST, parámetros y encabezados

func feedbackApi(){
    DispatchQueue.main.async {
        let headers = [
            "Content-Type": "application/x-www-form-urlencoded",
            "Authorization": "------"
        ]
        let url = URL(string: "---------")
        var parameters = [String:AnyObject]()
        parameters =  [
            "device_id":"-----" as AnyObject,
            "user_id":"----" as AnyObject,
            "cinema_id":"-----" as AnyObject,
            "session_id":"-----" as AnyObject,
        ]
       Alamofire.request(url!, method: .post, parameters: parameters,headers:headers).responseJSON { response in
                switch response.result{
                case.success(let data):
                    self.myResponse = JSON(data)
                    print(self.myResponse as Any)
                    let slide = self.myResponse!["sliders"]
                    print(slide)
                    print(slide.count)
                    for i in 0..<slide.count{
                        let single = Sliders(sliderJson: slide[i])
                        self.slidersArray.append(single)
                    }
                    DispatchQueue.main.async {
                        self.getSliderCollection.reloadData()
                    }
                case .failure(let error):
                    print("dddd",error)
                }

        }
    }

}
Tony Franzis
fuente
1

Así es como creé la solicitud Http POST con rapidez que necesita parámetros con codificación Json y con encabezados.

Se creó el cliente API BKCAPIClient como una instancia compartida que incluirá todo tipo de solicitudes como POST, GET, PUT, DELETE, etc.

func postRequest(url:String, params:Parameters?, headers:HTTPHeaders?, completion:@escaping (_ responseData:Result<Any>?, _ error:Error?)->Void){
    Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers).responseJSON {
        response in
        guard response.result.isSuccess,
            (response.result.value != nil) else {
                debugPrint("Error while fetching data: \(String(describing: response.result.error))")
                completion(nil,response.result.error)
                return
        }
        completion(response.result,nil)
    }
}

Clase de operación creada que contiene todos los datos necesarios para una solicitud particular y también contiene lógica de análisis dentro del bloque de finalización.

func requestAccountOperation(completion: @escaping ( (_ result:Any?, _ error:Error?) -> Void)){
    BKCApiClient.shared.postRequest(url: BKCConstants().bkcUrl, params: self.parametrs(), headers: self.headers()) { (result, error) in
        if(error != nil){
            //Parse and save to DB/Singletons.
        }
        completion(result, error)
    }
}
func parametrs()->Parameters{
    return ["userid”:”xnmtyrdx”,”bcode":"HDF"] as Parameters
}
func headers()->HTTPHeaders{
    return ["Authorization": "Basic bXl1c2VyOm15cGFzcw",
            "Content-Type": "application/json"] as HTTPHeaders
}

Llame a la API en cualquier controlador de vista donde necesitemos estos datos

func callToAPIOperation(){
let accOperation: AccountRequestOperation = AccountRequestOperation()
accOperation.requestAccountOperation{(result, error) in

}}
vinodonkar
fuente
1
func get_Contact_list()
{
    ApiUtillity.sharedInstance.showSVProgressHUD(text: "Loading..")
    let cont_nunber = contact_array as NSArray
    print(cont_nunber)

    let token = UserDefaults.standard.string(forKey: "vAuthToken")!
    let apiToken = "Bearer \(token)"


    let headers = [
        "Vauthtoken": apiToken,
        "content-type": "application/json"
    ]

    let myArray: [Any] = cont_nunber as! [Any]
    let jsonData: Data? = try? JSONSerialization.data(withJSONObject: myArray, options: .prettyPrinted)
    //        var jsonString: String = nil
    var jsonString = String()
    if let aData = jsonData {
        jsonString = String(data: aData, encoding: .utf8)!
    }

    let url1 = "URL"
    var request = URLRequest(url: URL(string: url1)!)
    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = jsonData as! Data

    //        let session = URLSession.shared

    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil else {
            print("error=\(String(describing: error))")
            ApiUtillity.sharedInstance.dismissSVProgressHUD()
            return
        }

        print("response = \(String(describing: response))")


        let responseString = String(data: data, encoding: .utf8)
        print("responseString = \(String(describing: responseString))")

        let json =  self.convertStringToDictionary(text: responseString!)! as NSDictionary
        print(json)

        let status = json.value(forKey: "status") as! Int

        if status == 200
        {

            let array = (json.value(forKey: "data") as! NSArray).mutableCopy() as! NSMutableArray


        }
        else if status == 401
        {
            ApiUtillity.sharedInstance.dismissSVProgressHUD()

        }
        else
        {
            ApiUtillity.sharedInstance.dismissSVProgressHUD()
        }


    }
    task.resume()
}

func convertStringToDictionary(text: String) -> [String:AnyObject]? {
    if let data = text.data(using: String.Encoding.utf8) {
        do {
            let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:AnyObject]
            return json
        } catch {
            print("Something went wrong")
        }
    }
    return nil
}
Jignesh ZestBrains
fuente
1

Si alguien se pregunta cómo proceder con los modelos y demás, consulte a continuación

        var itemArr: [Dictionary<String, String>] = []
        for model in models {
              let object = ["param1": model.param1,
                            "param2": model.param2]
              itemArr.append(object as! [String : String])
        }

        let param = ["field1": someValue,
                     "field2": someValue,
                     "field3": itemArr] as [String : Any]

        let url: URLConvertible = "http://------"

        Alamofire.request(url, method: .post, parameters: param, encoding: JSONEncoding.default)
            .responseJSON { response in
                self.isLoading = false
                switch response.result {
                case .success:
                    break
                case .failure:
                    break
                }
        }
Heshan Sandeepa
fuente
0

Alamofire ~ 5.2 y Swift 5

Puede estructurar los datos de sus parámetros

Trabajar con fake json api

struct Parameter: Encodable {
     let token: String = "xxxxxxxxxx"
     let data: Dictionary = [
        "id": "personNickname",
        "email": "internetEmail",
        "gender": "personGender",
     ]
}

 let parameters = Parameter()

 AF.request("https://app.fakejson.com/q", method: .post, parameters: parameters).responseJSON { response in
            print(response)
        }
Trần Hữu Hiền
fuente