SOAP sur iPhone : terrain glissant !

Sur un projet récent,  j’ai du me frotter à l’utilisation de SOAP pour communiquer avec une API, aussi efficace que mal documentée…

Tout d’abord, un grand merci aux créateurs de http://www.webutils.pl/

Ce site propose une panoplie d’outils en ligne de cryptage/décryptage/checksum, etc. Bref, tout ce qu’il faut pour s’y retrouver quand, par exemple, il faut transmettre dans un fichier XML une image codée en Base64 et signée par un CRC-32.

J’ai utilisé ces outils pour comparer mes envois avec un dump d’un envoi correct fourni par le service, jusqu’à ce que pour la même image (extraite du dump !) les codages et signatures soient les mêmes. Une adresse à retenir donc.

SOAP 1.1 sur iPhone/iPad/iOS

Ca commence par une recherche sur le web (et c’est peut être ce qui vous amène ici, hein ?!)
Peu de ressources disponibles, des exemples souvent incomplets, alors voici ma petite contribution en français !

J’utilise ASIHTTPRequest pour tous mes envois, c’est complet, pratique, synchrone ou non = un gain de temps considérable !
Suffit juste de prendre le temps DE LIRE LA DOC !

La première chose à faire, si on veut une communication asynchrone sera de rendre l’objet capable de gérer les delegate de ASIHTTP. Attention, j’utilise ASIHTTPRequest et non pas ASIFormDataRequest, qui a aussi ses delegate.

@interface votre_object : NSObject <ASIHTTPRequestDelegate> {

Ensuite, ben on y va pour une requête SOAP simple, par exemple pour lancer une session, pas de paramètres à envoyer, juste une action. Notez que dans l’exemple suivant il vous faudrait remplacer le texte SOAP_ACTION par votre propre action. Notez aussi que cette balise est une ‘singlette’, elle n’a pas de balise fermante et doit avoir un / avant le > . Avec les \ »,  / et autre \n  ça peut vite devenir un poil confus et celui-là on le rate assez facilement. Je pense que les \n sont en option, mais très utiles quand on veut lire les logs plus facilement.

-(void)startSession {
NSString *soapMessage = @"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
"<soap:Body>\n"
"<SOAP_ACTION xmlns=\"http://votreadresse.com/\" />\n"
"</soap:Body>\n"
"</soap:Envelope>";
NSString *soapMessageLength = [NSString stringWithFormat:@"%d", [soapMessage length]];
NSLog(@"%@",soapMessage);
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:serverURL]];
[request addRequestHeader:@"Content-Type" value:@"text/xml; charset=utf-8" ];
[request addRequestHeader:@"Content-Length" value:soapMessageLength];
[request addRequestHeader:@"SOAPAction" value:@"http://votreadresse.com/SOAP_ACTION"];
[request setPostBody:(NSMutableData*)[soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
[request setDidFinishSelector:@selector(startSessionDone:)];
[request setDelegate:self];
[request startAsynchronous];
}

Ce a quoi répondra la fonction startSessionDone au retour du serveur :

-(void)startSessionDone:(ASIHTTPRequest *)request {
NSLog(@"startSessionDone");
NSString *StartSessionResult = [request responseString];
//Et vous faites ce que vous voulez de la réponse ensuite...
}

Si maintenant on veut envoyer plus de paramètres, mettons une clé de session, ça va alors prendre cette forme ci-dessous. Notez comme SOAP_ACTION change, c’est maintenant une balise qui s’ouvre et se referme après les paramètres à envoyer.

-(void)queryWithParams {

NSString *soapMessage = [NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
"<soap:Body>\n"
"<SOAP_ACTION xmlns=\"http://votreadresse.com/\">\n"
"<sessionKey>%@</sessionKey>\n"
"</SOAP_ACTION>\n"
"</soap:Body>\n"
"</soap:Envelope>\n", sessionKey];
NSString *soapMessageLength = [NSString stringWithFormat:@"%d", [soapMessage length]];
NSLog(@"%@",soapMessage);
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:serverURL]];
[request addRequestHeader:@"Content-Type" value:@"text/xml; charset=utf-8" ];
[request addRequestHeader:@"Content-Length" value:soapMessageLength];
[request addRequestHeader:@"SOAPAction" value:@"http://votreadresse.com/SOAP_ACTION"];
[request setPostBody:(NSMutableData*)[soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
[request setDidFinishSelector:@selector(queryWithParamsDone:)];
[request setDelegate:self];
[request startAsynchronous];
}

Et la fonction de retour :

-(void) queryWithParamsDone:(ASIHTTPRequest *)request {
NSLog(@ »queryWithParamsDone« );
NSString * queryWithParamsResult = [request responseString];
//Et vous faites ce que vous voulez de la réponse ensuite...
}
Voilà, en espérant que cela pourra en aider quelques-uns. Pour ma part j’y ai passé quand même quelques heures avant d’arriver à mes fins et c’est en croisant un article en espagnol sur la 10 ou 12 ème page de résultats  de Google que j’ai trouvé une trace de code qui a débloqué la situation, la morale : des fois il faut s’obstiner dans ses recherches !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>