[RESOLU] Alamofire : problème avec des paramètres optionnel

Bonjour à tous,

lors d’une requête Alamofire je charge les paramètres avec des variables optionnelles et ça pose problème à Alamofire…

let Params: Parameters = [
    "MODE" : "AddData",
    "Valeur" : " "
]

func requete() {
Alamofire.request(URL, method: .post, parameters: Params).responseDecodableObject(decoder: decoder)
                    { (response: DataResponse<RESPONSE_JSON>) in
                        

                    // reste du code

                    }
}

Alors que lorsque j’ai des variable non-optionnelles ça ne pose aucun souci…

Et même en forçant les optionnels avec var a = myVar! et un « if let » avant ça ne marche pas

Voici l’erreur dans la console :

FAILURE: dataCorrupted(Swift.DecodingError.Context(codingPath: , debugDescription: « The given data was not valid JSON. », underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 « No value. » UserInfo={NSDebugDescription=No value.})))

Une idée?

Je ne vois pas les variables optionnelles dans le code que tu as donné mais il semble plutôt que le problème soit le JSON retourné par ton serveur.
Comme tu lui demande de le décoder en objet, si le format n’est pas correct tu as cette erreur.
Tu devrais commencer par utiliser un responseString pour voir ce que te retourne le serveur et vérifier que le JSON est correct. Une fois que tu es certain d’avoir du JSON parfait, tu pourras voir pour le transformer en objet.

Les optionnelles sont insérées (de façon controlé : avec des « if let » et des !) dans les paramètres citer ci-dessous depuis un autre ViewController (depuis une tableview avec des données realm pour être exact)

j’ai synthétisé l’exemple pour être plus clair au niveau des paramètres mais si je passe des variables non optionnelles tout se passe bien coté serveur (il y a écriture sur ma base de donnée SQL) alors que si les variables transmisent sont optionnelles la requête échoue.

J’avais déjà rencontré le problème il m’avait suffit de transmettre des variables non optionnelles mais la pour données Realm c’est une autre histoire

Je viens de réussir à faire passer la requête mais je n’aime pas la façon de faire :

let urlEnDur = "http://www.url.fr/post?" + "Mode=AddData" + "&Valeur=" + "\(myVariable)" + ... + ...

func requete() {
Alamofire.request(urlEnDur, method: .post).responseDecodableObject(decoder: decoder)
                    { (response: DataResponse<RESPONSE_JSON>) in
                        

                    // reste du code

                    }
}

En faite je déclare une chaine de caractère concaténée avec mes paramètres et dans la fonction Alamofire je ne déclare pas de paramètres.

je préférerai garder le Dictionnary de type Parameters c’est plus lisible, enfin de mon point de vue…

Je suis d’accord avec toi, ça serait mieux d’utiliser les paramètres dans un tableau comme tu as tenté de le faire. Je n’arrive toujours pas à voir où sont les optionnels dans ton code, peux-tu me mettre le code exact avec les optionnels pour que j’arrive mieux à visualiser où est le problème ?

Ci dessous le le manager de mes objets Realm :

class ProdListManager {
    private static var s_instance: ProdListManager? = nil
    public static var shared: ProdListManager? {
        if s_instance == nil {
            s_instance = ProdListManager()
        }
        return s_instance!
    }
    
    private let _realmProd: Realm

    public var _FAM: String = ""
    public var _SOUSFAM: String = ""
    
    public let _famProdList: Results<FamProdData>
    public var _sousFamProdList: Results<FamProdData>
    public var _prodList: Results<ProdData>

    private init() {
        _realmProd = try! Realm()
        _famProdList = _realmProd.objects(FamProdData.self).filter("SousFamille == null AND Tfamille == 2") // Affichage des familles des PRODUITS
        _sousFamProdList = _realmPrestaProd.objects(FamPrestaProdData.self).filter("Tfamille == 2 AND Famille == '\(_FAM)' AND SousFamille != null") // Results = tri de la famille sélectionnée pour affichage des sous-familles des PRODUITS
        _prodList = _realmProd.objects(ProdData.self).filter("Tfamille == 2 AND Famille == '\(_FAM)' AND SousFamille == '\(_SOUSFAM)'") // Results = tri de la famille et de la sous-famille sélectionnée pour affichage des PRODUITS
    }

// -------- Retourne l'information PRODUITS en fonction de l'index --------
    public func getProdData(atIndex index: Int) -> ProdData? {
        guard index >= 0 && index < getProdCount() else {
            return nil
        }
        return _prodList[index]
    }

Fonction de la TableView qui déclenche la requête :

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath as IndexPath, animated: true)

        if let selectedProd = _prodManager?.getProdData(atIndex: indexPath.row), let userParams = _userParameters?.CodeU {
            let dateDay = Func().getDateDayForPost()
            let setParameters = PostTicket()
            
            setParameters.NEXT_NTIC_Parameters["DateD"] = dateDay // Chargement des paramètres NEXT_NTIC pour obtenir le numéro du prochain ticket dans la DB distante
        
            setParameters.ADDLIG_Parameters["Nart"] = "\(selectedArticle.Nart)"
            setParameters.ADDLIG_Parameters["Nfamille"] = "\(selectedArticle.Nfamille)"
            setParameters.ADDLIG_Parameters["Famille"] = "\(selectedArticle.Famille!)"
            setParameters.ADDLIG_Parameters["SousFamille"] = "\(selectedArticle.SousFamille!)"
            setParameters.ADDLIG_Parameters["Tfamille"] = "\(selectedArticle.Tfamille)"
            setParameters.ADDLIG_Parameters["EAN13"] = "\(selectedArticle.EAN13)"
            setParameters.ADDLIG_Parameters["EAN13FOU"] = "\(selectedArticle.EAN13FOU)"
            setParameters.ADDLIG_Parameters["MtE"] = "\(selectedArticle.MtuE!)"
            setParameters.ADDLIG_Parameters["Tva"] = "\(selectedArticle.Tva)"
            setParameters.ADDLIG_Parameters["CodeU"] = "\(userParams)"

            setParameters.postNewTicket()   
        }
    }

Classe de la requête Alamofire utilisant le pod ‘CodableAlamofire’:

class PostTicket {
    
private struct NEXT_NTIC_JSON: Decodable {
    var success: Bool
    var Ntic: Int
    
    private enum CodingKeys: String, CodingKey {
        case success
        case Ntic    
    }
}

private struct ADDLIG_JSON: Decodable {
    var success: Bool
    var Ntic: String
    
    private enum CodingKeys: String, CodingKey {
        case success
        case Ntic
        
    }
}

var NEXT_NTIC_Parameters: Parameters = [ 
    "Mode" : "NEXT_NTIC_RESA",
    "Ntic" : " ",
    "IndividuId" : "1", // valeur = 1 quand création ticket
    "DateD" : " "
]

var ADDLIG_Parameters: Parameters = [
    "Mode" : "ADDLIG",
    "Ntic" : " ",
    "Nart" : " ",
    "Nfamille" : " ",
    "Famille" : " ",
    "SousFamille" : " ",
    "Tfamille" : " ",
    "EAN13" : " ",
    "EAN13FOU" : " ",
    "Qte" : "1", 
    "MtrE" : " ",
    "MtE" : " ",
    "Tva" : " ",
    "CodeU" : " "
]*/


func postNewTicket() {
    
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .secondsSince1970


// 1ère requête pour récupéré le numéro du prochain ticket créé dans la base de donnée distante

Alamofire.request(https://www.xxx.xxx/xxx.php?, method: .post, parameters: NEXT_NTIC_Parameters).responseDecodableObject(decoder: decoder)
{ (response: DataResponse<NEXT_NTIC_JSON>) in

if let NEXT_NTIC_response = response.result.value {
        
            if NEXT_NTIC_response.success == true {
                print("NEXT NTIC success = true")
                self.ADDLIG_Parameters["Ntic"] = NEXT_NTIC_response.Ntic

                // 2ème requête pour ajouté la ligne au ticket créé dans la base de donnée distante
                
                Alamofire.request(https://www.xxx.xxx/xxx.php?, method: .post, parameters: ADDLIG_Parameters).responseDecodableObject(decoder: decoder)
                { (response: DataResponse<AJOLIG_JSON>) in
                    if let ADDLIG_response = response.result.value {
                        if ADDLIG_response.success == true {
                            print("ADDLIG success = true")
                            let _proxyTicket = ProxyTicket()
                            _proxyTickets.parametersSelectedTicket["Ntic"] = ADDLIG_response.Ntic
                            _proxyTickets.getSelectedTicket()
                        }
                    }
                }
            }
        }
    }
}
}

Désolé @mbritto ça fait beaucoup de code et encore j’en est vidangé …

Mais du coup tes paramètres, tu veux les envoyer en JSON dans le corps de la requête ? Ou encoder les paramètres dans l’URL comme tu l’as fait “en dur” dans ta précédente réponse ?

Le but était d’encoder l’url comme j’ai l’habitude de faire mais je ńetait jamais tombé sur des variables optionnelles pour charger les paramètres.

Pour les requêtes POST, par défaut, les paramètres sont encodés dans le body et non dans l’URL. Donc ton URL finale ne change pas et c’est le corps de ta requête qui possède tes paramètres. Ca doit être pour ça que ton serveur ne retourne pas un résultat valide :slight_smile:

Si tu veux que les paramètres soient encodés dans l’URL même en POST, tu peux utiliser le paramètre encoding : URLEncoding(destination: .queryString) avec Alamofire.
Voici le lien vers la doc pour plus d’infos : https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#parameter-encoding

J’avais oublié de répondre… Oui du coup depuis que j’utilise cette méthode je n’ai plus de souci. Merci encore !

1 « J'aime »