Comment envoyer une demande POST avec BODY dans Swift

97

J'essaie de faire une demande de publication avec un corps en rapide en utilisant Alamofire.

mon corps json ressemble à:

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

let listJ'essaye de faire avec NSDictionnary qui ressemble à:

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

et ma demande utilisant Alamofire ressemble à:

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 demande a une erreur et je pense que le problème vient de la liste des dictionnaires, car si je fais une demande sans la liste, cela fonctionne bien, alors une idée?


J'ai essayé la solution proposée mais je suis confronté au même problème:

 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)
    }
Étranger B.
la source
3
duplication possible de la requête POST avec une simple chaîne dans le corps avec Alamofire
EI Captain v2.0
1
Merci pour votre commentaire, mais le message que vous avez fourni n'aide pas, et je n'essaie pas de passer une chaîne comme corps, alors pouvez-vous s'il vous plaît lire le message attentivement
Stranger B.
@YasserB. Convertissez votre JSON en NSString (il existe une méthode pour cela), puis utilisez le lien @Bhavin?
Larme
@Larme, il serait vraiment utile que vous fournissiez un exemple
Stranger B.
@Larme j'ai essayé la solution proposée mais j'ai le même problème la demande ne fonctionne que si je supprime la liste du corps du fils
Stranger B.

Réponses:

97

Tu es proche. Le formatage du dictionnaire de paramètres ne semble pas correct. Vous devriez essayer ce qui suit:

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

J'espère que cela a résolu votre problème. Si ce n'est pas le cas, répondez et j'ajusterai ma réponse en conséquence.

cnoon
la source
Comment puis-je configurer une propriété de mon JSON null, puisque je ne peux pas céder nilà AnyObject?
Amp Tanawat
3
@JaseemAbbas vérifiez votre version d'Alamofire, si vous êtes sur v4.0 + consultez ma réponse ci
Gianni Carlo
comment envoyer ce type de paramètre dans le cas où l'encodage est .urlEncoding
Pramod Shukla
1
Impossible de convertir la valeur de type 'Int' en type de valeur de dictionnaire attendu 'AnyObject'
myatmins
comment faire si disons que la valeur du paramètre "List" a comme 1000 éléments de liste?
Nishad Arora
175

Si vous utilisez Alamofire v4.0 +, la réponse acceptée ressemblerait à ceci:

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
la source
6
Génial! Remplacez la réponse acceptée par celle-ci s'il vous plaît! :) ou combiner avec l'actuel pour les solutions Alamofire 3 et 4.
Tom van Zummeren
1
D'accord - c'est la déclaration explicite de JSONEncodinglever l'ambiguïté du type qui l'a fait pour moi.
Thomas Verbeek
@Gianni Carlo J'ai utilisé la même chose que votre réponse, mais dans ma réponse positive, je reçois des erreurs.
Ramakrishna
@Ramakrishna qui pourrait être lié à l'API que vous utilisez. Pour analyser la réponse, j'utilise habituellement la bibliothèque SwiftyJSON, faites-moi savoir quel type d'erreurs vous recevez
Gianni Carlo
Merci pour votre réponse. J'ai la solution.
Ramakrishna
34

Je n'aime aucune des autres réponses jusqu'à présent (sauf peut-être celle de SwiftDeveloper), car elles vous obligent soit à désérialiser votre JSON, uniquement pour qu'il soit à nouveau sérialisé, soit à se soucier de la structure du JSON lui-même.

La bonne réponse a été publiée par afrodev dans une autre question. Vous devriez aller voter pour.

Voici juste mon adaptation, avec quelques changements mineurs (principalement un jeu de caractères UTF-8 explicite).

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)
}
Côte maritime du Tibet
la source
Je conviens que la réponse de @ SwiftDeveloper est meilleure et (à mon avis) plus complète que la réponse «correcte» que vous mentionnez. Mais je soutiendrais deux points. Premièrement, la «bonne réponse» que vous mentionnez présente un défaut qui toJSONStringn'est pas une méthode native, c'est donc essentiellement une boîte noire que vous devez implémenter. Deuxièmement, la réponse que vous donnez, fournit un var jsonqui commence comme une chaîne json, en réalité personne n'a les paramètres de cette façon, à moins que vous ne les convertissiez et ne les stockiez localement de cette façon.
Gianni Carlo
@GianniCarlo 1) il n'y a pas toJSONStringde réponse dans ma réponse, 2) "en réalité, personne n'a les paramètres de cette façon" - cela fait beaucoup d'hypothèses; le JSON peut provenir de parties assez différentes de l'application, sans aucun rapport avec la demande, et dont le code réseau ne sait rien.
Côte de la mer du Tibet
Merci de m'avoir simplifié la vie !!! 1 J'utilise Alamofire avec Flask Backend. Chez Postman, tout a bien fonctionné, mais chez Alamofire, cela ne fonctionne pas. Corps HTTP et paramètres d'URL et comment les définir. Merci encore.
Vineel
8

Xcode 8.X, Swift 3.X

Utilisation facile;

    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)

            }
SwiftDeveloper
la source
7

Si vous utilisez swift4et que Alamofire v4.0le code accepté ressemblerait à ceci:

            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
la source
5

Réponse acceptée dans 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
la source
4

J'ai légèrement modifié la réponse de SwiftDeveloper , car cela ne fonctionnait pas pour moi. J'ai également ajouté la validation 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
la source
1
Fonctionne toujours dans Alamofire 4.9.1 et Swift 5.1. Très apprécié
Abe
2

Il y a quelques changements que je voudrais notifier. Vous pouvez désormais accéder à la requête, au JSON, à l'erreur à partir de l'objet de réponse.

        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
la source
2

Alamofire Fetch des données avec POST, paramètres et en-têtes

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
la source
1

Voici comment j'ai créé une requête Http POST avec swift qui nécessite des paramètres avec un encodage Json et avec des en-têtes.

Création du client API BKCAPIClient en tant qu'instance partagée qui inclura tous les types de requêtes telles que 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)
    }
}

Classe Operation créée qui contient toutes les données nécessaires pour une demande particulière et contient également une logique d'analyse à l'intérieur du bloc d'achèvement.

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
}

Appeler l'API dans n'importe quel contrôleur de vue où nous avons besoin de ces données

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

}}
vinodonkar
la source
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 ZestCerveaux
la source
1

Si quelqu'un se demande comment procéder avec les modèles et autres choses, voir ci-dessous

        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
la source
0

Alamofire ~ 5.2 et Swift 5

Vous pouvez structurer vos données de paramètres

Travailler avec de fausses API JSON

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
la source