RestKit didFailWithError always called, didLoadObjects never called - restkit

Well, the title pretty much says it all. I'm calling my server and when it suceeds or fails it calls my didFailWithError method, never calling my didLoadObjects method. I would have expected didFailWithError to be called when, say, I get a 401 back, and didLoadObjects to be called when I get a 200 back.
Here's how I set up my object mapping:
- (void)setupCreateAccountMapping
{
// mapping for CreateAccount
RKObjectMapping* createAccountSerializationMapping = [RKObjectMapping mappingForClass:[CreateAccount class]];
[createAccountSerializationMapping mapAttributes:#"email", #"pwd", #"uname", nil];
[[RKObjectManager sharedManager].mappingProvider setSerializationMapping:createAccountSerializationMapping forClass:[CreateAccount class]];
// mapping for CheckUserName
RKObjectMapping* checkUserNameSerializationMapping = [RKObjectMapping mappingForClass:[CheckUserName class]];
[checkUserNameSerializationMapping mapAttributes:#"uname", nil];
[[RKObjectManager sharedManager].mappingProvider setSerializationMapping:checkUserNameSerializationMapping forClass:[CheckUserName class]];
router = [RKObjectRouter new] ;
[router routeClass:[CheckUserName class] toResourcePath:#"/registration/rest/users/isavailable" forMethod:RKRequestMethodGET];
[router routeClass:[CreateAccount class] toResourcePath:#"/registration/rest/users/create_account" forMethod:RKRequestMethodPOST];
[RKObjectManager sharedManager].router = router;
}
and here is how I post to the server.
- (IBAction)submitPressed:(id)sender {
CreateAccount* user = [CreateAccount new];
user.email = [emailAddressTextField text];
user.uname = [usernameTextField text];
user.pwd = [passwordTextField text];
[[RKObjectManager sharedManager] postObject:user delegate:self];
}
In didFailWithError I check:
if ([response statusCode] >= 400) {
to see if I succeeded or not and that seems really, really, wrong.
What am I doing wrong here? When I run the sample code I do see didLoadObjects called.
Here is the log from 2 runs, the first unsuccessful and the second successful:
Here we can see me trying to create a user named "andrew" but one already exists. I get a 406 back and didFailWithError is called.
2011-12-14 10:52:33.376 Ferret[60007:f803] D restkit.network:RKClient.m:389 Reachability to host '127.0.0.1' determined for client <RKClient: 0x900c9d0>, unsuspending queue <RKRequestQueue: 0x900eee0 name=(null) suspended=YES requestCount=0 loadingCount=0/5>
Current language: auto; currently objective-c
2011-12-14 10:53:16.478 Ferret[60007:f803] D restkit.network:RKRequest.m:362 Sending asynchronous POST request to URL http://127.0.0.1:8080/registration/rest/users/create_account.
2011-12-14 10:53:16.478 Ferret[60007:f803] D restkit.network:RKObjectLoader.m:302 POST or PUT request for source object <CreateAccount: 0x6d1d8e0>, serializing to MIME Type application/x-www-form-urlencoded for transport...
2011-12-14 10:53:16.479 Ferret[60007:f803] D restkit.object_mapping:RKObjectMappingOperation.m:509 Starting mapping operation...
2011-12-14 10:53:16.479 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:510 Performing mapping operation: RKObjectMappingOperation for '__NSCFDictionary' object. Mapping values from object <CreateAccount: 0x6d1d8e0> to object {
} with object mapping RKObjectMapping class => CreateAccount: keyPath mappings => (
"RKObjectKeyPathMapping: pwd => pwd",
"RKObjectKeyPathMapping: uname => uname",
"RKObjectKeyPathMapping: email => email"
)
2011-12-14 10:53:16.479 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:263 Mapping attribute value keyPath 'pwd' to 'pwd'
2011-12-14 10:53:16.479 Ferret[60007:f803] D restkit.object_mapping:RKObjectPropertyInspector.m:107 Cached property names and types for Class 'CreateAccount': {
accessibilityHint = NSString;
accessibilityLabel = NSString;
accessibilityLanguage = NSString;
accessibilityValue = NSString;
email = NSString;
pwd = NSString;
uname = NSString;
}
2011-12-14 10:53:16.482 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:273 Mapped attribute value from keyPath 'pwd' to 'pwd'. Value: 123456
2011-12-14 10:53:16.483 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:263 Mapping attribute value keyPath 'uname' to 'uname'
2011-12-14 10:53:16.483 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:273 Mapped attribute value from keyPath 'uname' to 'uname'. Value: andrew
2011-12-14 10:53:16.483 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:263 Mapping attribute value keyPath 'email' to 'email'
2011-12-14 10:53:16.483 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:273 Mapped attribute value from keyPath 'email' to 'email'. Value: foo#example.com
2011-12-14 10:53:16.483 Ferret[60007:f803] D restkit.object_mapping:RKObjectMappingOperation.m:516 Finished mapping operation successfully...
2011-12-14 10:53:16.484 Ferret[60007:f803] T restkit.network:RKRequest.m:310 Prepared POST URLRequest '<NSMutableURLRequest http://127.0.0.1:8080/registration/rest/users/create_account>'. HTTP Headers: {
Accept = "application/json";
"Content-Type" = "application/x-www-form-urlencoded";
}. HTTP Body: pwd=123456&uname=andrew&email=foo%40example.com.
2011-12-14 10:53:16.572 Ferret[60007:f803] D restkit.network:RKResponse.m:196 NSHTTPURLResponse Status Code: 406
2011-12-14 10:53:16.573 Ferret[60007:f803] D restkit.network:RKResponse.m:197 Headers: {
"Content-Length" = 32;
"Content-Type" = "application/json";
Date = "Wed, 14 Dec 2011 15:53:14 GMT";
Server = "Apache-Coyote/1.1";
}
2011-12-14 10:53:16.573 Ferret[60007:f803] T restkit.network:RKResponse.m:202 Read response body: UserName or Email must be unique
2011-12-14 10:53:16.573 Ferret[60007:f803] E restkit.network:RKObjectLoader.m:289 Encountered an error while attempting to map server side errors from payload: Unexpected token, wanted '{', '}', '[', ']', ',', ':', 'true', 'false', 'null', '"STRING"', 'NUMBER'.
Here we can see me trying to create a user named "andrewA" and the user is created. I get a 22 back and didFailWithError is called, not didLoadObjects
2011-12-14 10:54:21.486 Ferret[60007:f803] D restkit.network:RKRequest.m:362 Sending asynchronous POST request to URL http://127.0.0.1:8080/registration/rest/users/create_account.
2011-12-14 10:54:21.486 Ferret[60007:f803] D restkit.network:RKObjectLoader.m:302 POST or PUT request for source object <CreateAccount: 0x9041300>, serializing to MIME Type application/x-www-form-urlencoded for transport...
2011-12-14 10:54:21.486 Ferret[60007:f803] D restkit.object_mapping:RKObjectMappingOperation.m:509 Starting mapping operation...
2011-12-14 10:54:21.486 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:510 Performing mapping operation: RKObjectMappingOperation for '__NSCFDictionary' object. Mapping values from object <CreateAccount: 0x9041300> to object {
} with object mapping RKObjectMapping class => CreateAccount: keyPath mappings => (
"RKObjectKeyPathMapping: pwd => pwd",
"RKObjectKeyPathMapping: uname => uname",
"RKObjectKeyPathMapping: email => email"
)
2011-12-14 10:54:21.486 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:263 Mapping attribute value keyPath 'pwd' to 'pwd'
2011-12-14 10:54:21.486 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:273 Mapped attribute value from keyPath 'pwd' to 'pwd'. Value: 123456
2011-12-14 10:54:21.494 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:263 Mapping attribute value keyPath 'uname' to 'uname'
2011-12-14 10:54:21.494 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:273 Mapped attribute value from keyPath 'uname' to 'uname'. Value: andrewA
2011-12-14 10:54:21.494 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:263 Mapping attribute value keyPath 'email' to 'email'
2011-12-14 10:54:21.494 Ferret[60007:f803] T restkit.object_mapping:RKObjectMappingOperation.m:273 Mapped attribute value from keyPath 'email' to 'email'. Value: fooA#example.com
2011-12-14 10:54:21.494 Ferret[60007:f803] D restkit.object_mapping:RKObjectMappingOperation.m:516 Finished mapping operation successfully...
2011-12-14 10:54:21.495 Ferret[60007:f803] T restkit.network:RKRequest.m:310 Prepared POST URLRequest '<NSMutableURLRequest http://127.0.0.1:8080/registration/rest/users/create_account>'. HTTP Headers: {
Accept = "application/json";
"Content-Type" = "application/x-www-form-urlencoded";
}. HTTP Body: pwd=123456&uname=andrewA&email=fooA%40example.com.
2011-12-14 10:54:23.004 Ferret[60007:f803] D restkit.network:RKResponse.m:196 NSHTTPURLResponse Status Code: 200
2011-12-14 10:54:23.004 Ferret[60007:f803] D restkit.network:RKResponse.m:197 Headers: {
"Content-Length" = 45;
"Content-Type" = "application/json";
Date = "Wed, 14 Dec 2011 15:54:20 GMT";
Server = "Apache-Coyote/1.1";
"X-Powered-By" = "Servlet/3.0; JBossAS-6";
}
2011-12-14 10:54:23.004 Ferret[60007:f803] T restkit.network:RKResponse.m:202 Read response body: 98a454470b8b1cf0d3e081f3e2ac2ca41323878059558
2011-12-14 10:54:23.016 Ferret[60007:1531b] D restkit.network:RKObjectLoader.m:214 No object mapping provider, using mapping provider from parent object manager to perform KVC mapping
Notice in both cases I'm getting a non-JSON response back from the server, but it is just a string, like the error message or the activation code.

You have your Content-type header set to "application/json" and the response is not a well-formed JSON. I believe the mapping process bails out due to the parsing problem. You can try modifying the server output eg.return a JSON or to set appropriate content type header.

Related

Zoho Creator Deluge InvokeUrl : How to pass form parameters to third party form?

How to pass form parameters to a third-party web form with Zoho-Creator-Deluge's InvokeUrl() function?
Here is the code I have tried:
Try-1
auth_url = "https://example-form.com"
header_data = Map();
header_data.put("Content-Type","multipart/form-data");
payload = Map();
payload.put("username",app.App_Username);
payload.put("password",app.App_Password);
response = invokeurl
[
url :auth_url
type :POST
parameters:payload
headers:header_data
detailed: true
];
// debug
info response;
Try-2
auth_url = "https://example-form.com"
header_data = Map();
header_data.put("Content-Type","multipart/form-data");
payload = List();
username = {"paramName":"username","content":app.App_Username,"stringPart":"true"};
password = {"paramName":"password","content":app.App_Password,"stringPart":"true"};
payload.add(username);
payload.add(password);
response = invokeurl
[
url :auth_url
type :POST
files :payload
headers:header_data
detailed: true
];
// debug
info response;
Both Try-1 and Try-2 result in the form-page being returned in response instead of the expected logged-in page. There isn't an error message, so it seems to be ignoring the parameters in payload.
Is there a different syntax that works?
Thanks
Okay I found the issue was that I needed to use the Content-Type of x-www-form-urlencoded in my request headers. Here is the Try-1 updated with the working Content-Type:
header_data = Map();
//------------------------------------------------------------------
// This line is the fix!
//------------------------------------------------------------------
header_data.put("Content-Type","application/x-www-form-urlencoded");
payload = Map();
payload.put("username",app.App_Username);
payload.put("password",app.App_Password);
response = invokeurl
[
url :auth_url
type :POST
parameters:payload
headers:header_data
detailed: true
];
// debug
info response;

How to modify headers of WebMVC.fn RouterFunction response?

I've defined a RouterFunction bean, with handler function returning a response with string body, which is a JSON. The builder however sets the content type to text/plain on passing a string to body
ServerResponse.ok().body(responseString).build() // Content type set to text/plain
#Bean
public RouterFunction<ServerResponse> infoRouter(MyHandler myHandler) {
return nest(
path("info"),
route().GET("definitions", __ -> myHandler.getDefinitions()).build()
).filter(HandlerFilterFunction.ofResponseProcessor((serverRequest, serverResponse) ->
// TODO: Set content type header to application/json
));
}
I tried to clone the response using ServerResponse::from but it doesn't include the response body. Is there another way to do this?

OData $batch from Postman

I am trying to post OData batch request in postman.
The url:
http://localhost:52484/$batch
Header:
Content-Type : multipart/mixed; boundary=batch_36522ad7-fc75-4b56-8c71-56071383e77b
Body (raw) :
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-Transfer-Encoding:binary
GET /Schools?$top=1
Host: host
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
But am getting the below error:
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:52484/%24batch'.",
"MessageDetail": "No route providing a controller name was found to match request URI 'http://localhost:52484/%24batch'"
}
Any idea about what is missing in the request?
Please check if you configure OData route and batchHandler correctly, something like the below:
ODataBatchHandler odataBatchHandler = new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer);
odataBatchHandler.MessageQuotas.MaxOperationsPerChangeset = 10;
odataBatchHandler.MessageQuotas.MaxPartsPerBatch = 10;
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel(),
batchHandler: odataBatchHandler
);

WebAPI OData v4 custom action without parameters can't be routed with error "No routing convention was found..."

I have very simple OData controller that successfully process standard actions (at least GET, POST, PUT and DELETE methods are working). I have followed this tutorial and added simple bound action. The method has parameters argument, but actually it does not required the parameters:
[HttpPost]
public IHttpActionResult Close([FromODataUri] int key, ODataActionParameters parameters) {
return Ok();
}
I have defined this action in OData EDM configuration as following:
builder.EntitySet<Ticket>("tickets");
builder.EntityType<Ticket>().Action("Close");
I am trying to call action from Postman:
POST /odata/tickets(2)/Default.Close HTTP/1.1
Host: localhost:50477
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: eef4c1f6-8c7f-f5eb-c22d-4397f3bda170
But receives the error message:
{
"error": {
"code": "",
"message": "No HTTP resource was found that matches the request URI 'http://localhost:50477/odata/tickets(2)/default.close'.",
"innererror": {
"message": "No routing convention was found to select an action for the OData path with template '~/entityset/key/unresolved'.",
"type": "",
"stacktrace": ""
}
}
}
I have read the whole internet and all related articles on SO but can't fix this issue. Please help me because I have no any fresh idea how to fight this.
My controller:
public class TicketsController : ODataController
{
[HttpPost]
public IHttpActionResult Close([FromODataUri] int key, ODataActionParameters parameters)
{
return Ok();
}
}
My request:
string requestUri = "http://localhost/odata/tickets(2)/Default.Close";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUri);
request.Content = new StringContent("",
Encoding.UTF8,
"application/json");
HttpResponseMessage response = _client.SendAsync(request).Result;
Or remove the ODataActionParameters parameters in the close method and call with:
string requestUri = "http://localhost/odata/tickets(2)/Default.Close";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUri);
HttpResponseMessage response = _client.SendAsync(request).Result;
My EdmModel is use your model.

jqGrid: displaying server error message

I have a jqGrid edit form that contains a date field. I want to implement exception handling so that error messages from the server will be displayed in the edit form. Example response:
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Date: Fri, 28 Jun 2013 15:47:21 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: close
11
"Bad Date format"
0
jqGrid only displays "error status:'Bad Request' Error Code: 400", at the top of the form. How can I have it also display the error message: "Bad Date format" ?
You should use errorTextFormat callback of form editing. As the parameter the callback get jqXHR object which is wrapper on XMLHTTPRequest object. It's responseText property represent the body of the response (11\n"Bad Date format"\n0 in your case). The status property gets you the HTTP status code (400 in your example). You can use getResponseHeader and getAllResponseHeaders to examine all HTTP headers.
By the way I find very strange that the response contains Content-Type: application/json, but the body of the response don't contains JSON string.
Assume that your response contains 2 fields: status (OK, ERROR,..) and message then you should write a function like this:
validateAfterSubmit = function(response, postdata){
var json = response.responseText; // response text is returned from server.
var result = JSON.parse(json); // convert json object into javascript object.
return [result.status == 'OK', result.message, null];
};
and specify in the edit/add options:
//edit options
{ url: '...',
afterSubmit: validateAfterSubmit
},
//add options
{ url: '...',
afterSubmit: validateAfterSubmit
},
hopefully this can help

Resources