Content loss from JSON file when fetching it from server - ios

I have an API and I want to fetch some data from it as a JSON file using POST request.
The problem is :
data on the server look like this:
{
"countryID":"30"
"countryName":"Syria"
},
data I received from the http request -before parsing- is :
{
"countryID":"30"
"countryName":""
},
there is no value for every text field like countryName .
the http request is :
‫NSString * post =[NSString stringWithFormat:#"lang=%#",#"English"];
NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setTimeoutInterval:60];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];‬
the last thing I want to mention that the received JSON file contains a header before the JSON data like this :
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
My Question
Is there any mistake in the HTTP request causing this problem? or it's server side problem?
Edit
I forgot to mention that the server is a PHP server and the url format of the request is as look like :
https://website.com/api/data.php

It looks like the response you're getting has two problems: it doesn't have the content you expect, and its format is off - it sounds like the HTTP body of the response has both HTML and JSON in it.
The first problem is some sort of application-level issue; either you're not sending the right query, or the server isn't interpreting it correctly, or it has some sort of other bug. So it could be on either side.
The second problem, though, is probably a server-side issue; it's not returning a coherent response. That said, you might be able to prod the server to do the right thing by telling it explicitly that you want a JSON response:
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
Depends on the server, though. Good luck!

Are you getting any json errors in the debugger, like the Garbage At End error? Are you using NSJSONSerialization to handle the JSON on the iOS end? What happens if you use the NSJSONReadingAllowFragments option of NSJSONSerialization?
I'd have posted this as a comment but I'm underprivileged. :(

Related

Cannot get correct return message when consuming WCF web-service via NSURLConnection

I have a WCF web-service. If I just put the URL into the browser, I will get the error message: Forbidden. But if I post data through Fetcher(a HTTP Simulator in OS X), I can get the correct return value.
Now, I tried to use NSURLConnection to post data to the web-service and fetch the return value.
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:postURL];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d", postData.length] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLResponse * response = nil;
NSError * error = [[NSError alloc] init];
receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString * receivedStr = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
But all I get is just the html code of the error page I can see from the browser(that forbidden message).
Please help me figure it out. Thanks in advance.
EDIT:
I set up a PHP server and try to do the same thing. I works perfectly. Therefore, I highly doubt it is the WCF problem. Anyone has some good ideas?
if you use generated .svc service you need to :
change
[request setValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
to
[request addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-type"];
also you need to SOAPAction field according to operation you request
What is you postData?

"No Action header was found" error message while using SOAP webservice

Getting following error while consuming SOAP webservice in iOS App
"No Action header was found with namespace 'http://www.w3.org/2005/08/addressing' for the given message."
The same webservice working fine in SOAP UI Tool.
Following is the request format
NSString *data = #"<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:tem=\"http://tempuri.org/\">
<soap:Header></soap:Header>
<soap:Body><tem:GetEvaluators></tem:GetEvaluators></soap:Body>
</soap:Envelope>";
NSString *url = #"webservice url";
NSData *postData = [data dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
[request setTimeoutInterval:20.0];
[request setValue:#"application/soap+xml;charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"http://tempuri.org/IATCService/GetEvaluators" forHTTPHeaderField:#"SOAPAction"];
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
Complete error response received from webservice
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/fault</a:Action>
</s:Header>
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Sender</s:Value>
<s:Subcode>
<s:Value>a:MessageAddressingHeaderRequired</s:Value>
</s:Subcode>
</s:Code>
<s:Reason>
<s:Text xml:lang="en-US">No Action header was found with namespace 'http://www.w3.org/2005/08/addressing' for the given message.</s:Text>
</s:Reason>
<s:Detail>
<a:ProblemHeaderQName>a:Action</a:ProblemHeaderQName>
</s:Detail>
</s:Fault>
</s:Body>
Any help really appreciated.
We had the same problem with an ASP.NET-based server (error message when using python/suds, same query worked in SoapUi); after a lot of digging, we found that we need to add a SOAP header (as XML element) which contains the action; having the action in the Content-Type or SOAPAction headers was not enough (but does not hurt either). Here's an example of a successful query (from SoapUi):
<SOAP-ENV:Envelope xmlns:ns0="..." xmlns:ns1="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope">
<SOAP-ENV:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Action>http://www.foo.com/.../SomeJob/getParameters</wsa:Action></SOAP-ENV:Header>
<ns1:Body>
<ns0:getParameters>...</ns0:getParameters>
</ns1:Body>
</SOAP-ENV:Envelope>
With Python and SUDS, this is how we did it:
from suds.sax.element import Element
wsans = ('wsa', "http://www.w3.org/2005/08/addressing")
client.set_options(soapheaders = Element('Action', ns=wsans).setText(action))
The action can be queried from the method, i.e. if you want to call a method client.service.foo, use
action = client.service.foo.method.soap.action
We found this by looking at the SoapUi HTTP log. (We also tried Wireshark, but that would not work because we're trying to use an https server which we don't own.)
Include
[request setValue:#"application/xml" forHTTPHeaderField:#"Content-Type"];
Finally i able to solve this problem, the content-type and request format are totally different than what i am passing with request
Content-Type: application/soap+xml;charset=UTF-8;action="http://tempuri.org/IATCService/GetEvaluators"
So difference is i have to pass action with content type.
Also the request Soap Envelop is totally different with different namespaces
<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:a=\"http://www.w3.org/2005/08/addressing\">
**<s:Header>
<a:Action s:mustUnderstand=\"1\">http://tempuri.org/IATCService/GetEvaluators</a:Action> </s:Header>**
<s:Body>
<GetEvaluators xmlns=\"http://tempuri.org/\"/></s:Body>
</s:Envelope>
As the header information is also totally different we have to specify action over there.
Hope it will be helpful to someone, who is facing same problem.

Objective C: http POST request getting Unescaped

I am using a NSMutableURLRequest to send a (synchronous) POST request to a web service.
The request body contains a combination of XML and JSON. Something like :
<element>
<element 2>
<![CDATA[
{"jsondata1":{"datafield1":"data1"},
"jsondata2":"some data"
}
]]>
</element 2>
</element>
the JSON string has been escaped (Using escape() in Javascript)
When I receive the request at the other end I notice that all escaped characters have been unescaped!!
Can anyone tell me why this is happening? And how can I prevent this?
Here is the code that I'm using to send the request:
NSURL *url = [NSURL URLWithString:#"https://my-webservice.com/something.do"];
NSData *xmlResponseDataSave;
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
NSString *msgLength = [NSString stringWithFormat:#"%d",[xmlRequestString length]];
[req addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[req addValue:msgLength forHTTPHeaderField:#"Content-Length"];
[req setHTTPMethod:#"POST"];
NSData *saveData=[xmlRequestString dataUsingEncoding:NSUTF8StringEncoding];
[req setHTTPBody:saveData];
NSError *error=nil;
NSURLResponse *resp=[[NSURLResponse alloc] init];
xmlResponseData=[NSURLConnection sendSynchronousRequest:req returningResponse:&resp error:&error];
NSString *xmlResponseString=[[NSString alloc] initWithData:xmlResponseData encoding:NSUTF8StringEncoding];
Please note: I cannot make any change to the xml or the web service. I can only change the objective c code.
After a lot of trial and error the only solution that I could come up with is to string used in the request body before sending it (Since it's gonna get unescaped while being sent):
xmlRequestString=[xmlRequestString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *saveData=[xmlRequestString dataUsingEncoding:NSUTF8StringEncoding];
Though this is not a fix in the truest sense, just a work around. But it works for me (So far).
I'm still clue less about the root cause of the problem and I am still looking for a more elegant solution.

Timeout in NSURLConnection to WCF JSON REST server

I have a Windows based REST Server built using Microsoft-HTTPAPI (i.e. its not running under IIS)
If I send a JSON request to the service from a browser based REST tool (Firefox RESTClient) the server receives the request and processes it correctly as per the traces from the Microsoft Service Trace Viewer and the response from the service. I receive valid JSON back from the service.
I have an iOS application that uses a NSURLConnect to send the VERY SAME JSON request to the service, but it always times out. I've traced using WireShark, and the HTTP request is correctly formed and sent correctly to the server in both cases. I've traced using the MS Trace Viewer and it goes into "receive Bytes" but never returns. I get an exception when I eventually close the WCF Server.It never returns when I close the iOS app.
I have tried using NSURLConnection sendSynchronousRequest and asynchronously using the callbacks and asynchronously using completion blocks. If I make the timeout 0, the call (to sendSynchronousRequest) never returns. In all other cases, I get a timeout, and the WCF never completes the receive bytes part of the WCF invocation (a POST request)
I've checked
Here's my iOS Code:
dispatch_queue_t myQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(myQ, ^{ // First Queue the parsing
#try {
//Generate endpoint url
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/%#",appState.posPostingURL,serviceName]];
//Setup request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:10.0];
NSString *authStr = [NSString stringWithFormat:#"%#:%#", #"xxxx", #"xxxx"];
NSString *authData = [NSString base64StringFromString:authStr];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", authData];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
//Setup request headers
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"no-cache" forHTTPHeaderField:#"Cache-Control"];
[request setValue:[NSString stringWithFormat:#"%d", [dataBuffer length]] forHTTPHeaderField:#"Content-Length"];
// Put the request data in the request body
[request setHTTPBody: dataBuffer];
NSHTTPURLResponse *urlResponse = nil;
NSError *error = nil;
// and send to the server synchronously
serverData = [[NSURLConnection sendSynchronousRequest:request
returningResponse:&urlResponse
error:&error] mutableCopy];
// Now check the status and response
if (error) {
My WCF Code is as follows
namespace MyWebService{
[ServiceContract(Name = "MyServiceIntegrator", Namespace = "")]
public interface IMyIntegrator
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/Configure",
BodyStyle=WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
Result Configure(MyServerConfig config);
In the app.config file, the service endpoint is configured with
binding="webHttpBinding"
The Trace view is as follows:
Could there be any reason on either side that the server does not complete the read even though the JSON is valid.
I have also checked NSURLConnection JSON Submit to Server
and as far as I can see my code to send the request is correct.
Any ideas - Been pulling my hair out for 3 days now
What happens if you change this:
[request setValue:[NSString stringWithFormat:#"%d", [dataBuffer length]] forHTTPHeaderField:#"Content-Length"];
To this:
[request setValue:[NSString stringWithFormat:#"%i", [dataBuffer length]] forHTTPHeaderField:#"Content-Length"];
Probably won't make a difference, but the rest of your code looks fine so maybe worth a shot. (My thinking is the decimal is causing the server issues).
ferdil,I think you can try changing timeout period to 30.0 instead of 10.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:30.0];

YouTube-Api Comment on videos

I'm trying to comment on a youtube video via the youtube api. I have to send some XML to their server, but when i do it gives me nothing back, neither comments it on the video.
Heres the link to the api documentation!
POST /feeds/api/videos/VIDEO_ID/comments HTTP/1.1
Host: gdata.youtube.com
Content-Type: application/atom+xml
Content-Length: CONTENT_LENGTH
Authorization: Bearer ACCESS_TOKEN
GData-Version: 2
X-GData-Key: key=DEVELOPER_KEY
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:yt="http://gdata.youtube.com/schemas/2007">
<content>This is a crazy video.</content>
</entry>
I really appreciate all your help, because I'm stuck on this for days.
Thanks!
Here is my code:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *requestString = [NSString stringWithFormat:#"<?xml version=\"1.0\" encoding=\"UTF-8\"?><entry xmlns=\"http://www.w3.org/2005/Atom\"xmlns:yt=\"http://gdata.youtube.com/schemas/2007\"><content>%#</content></entry>", [textField text]];
NSData *postData = [requestString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"https://gdata.youtube.com/feeds/api/videos/4NE7Nmmt0R4/comments"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/atom+xml" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"key=%#", [defaults objectForKey:#"accessToken"]] forHTTPHeaderField:#"Authorization"];
[request setValue:#"key=AI39si4apF3QyQkXbH_C5IHIClkyP2mio2QJ3JBUUpvPbO2rhch7tpYjMavZgt5QzGaGrHBfom5mNpoUq_ZLRPPa35KO21O9Pw" forHTTPHeaderField:#"X-GData-Key"];
[request setValue:#"2" forHTTPHeaderField:#"GData-Version"];
[request setHTTPBody:postData];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
[conn start];
The YouTube API will always send an HTTP response whenever you make an HTTP request. Even if you make a completely invalid HTTP request, you'll get back an HTTP error response. Please double-check to see if you're getting any response back at all. If you're really not, then my guess is that you're not actually completing your HTTP request—perhaps it's never making it to the API servers due to some network problems, or perhaps you're not calculating CONTENT_LENGTH correctly (assuming you're attempting to calculate it by hand).
Also, I'd recommend using the GData Objective-C client library if you're not already.

Resources