Google Cloud Endpoints generated iOS Client not working - ios

I have a python webservice running locally using GAE Python SDK 1.8.3. After annotating the API and generating iOS client classes using Google Cloud Endpoints Service Generator I'm trying to call a remote procedure using it.
If I test my api using API Explorer, everything works just fine.
When I call using the iOS client, the call is received by the webservice, however the request cannot be decoded correctly. This is my first time using the Endpoints API so I don't know what is wrong.
What seems to be happening is that my request object is being wrapped in a "resource" key in the query JSON. Now, when my webservice tries to decode it, it yields a warning saying "No variant found for unrecognized field: resource". And, as my object is wrapped inside this key, it is skipped and never decoded to a message.
When the call is made using the API Explorer the object is not wrapped, so everything works.
This is what I'm doing in my webservice:
#endpoints.method(SearchRequest,
ContactListResponse,
path='search', http_method='post',
name='api.search')
def search(self, request):
user = request.user
number = request.number
This is how I call it from iOS:
GTLMyAPIMessagesSearchRequest * request = [[GTLMyAPIMessagesSearchRequest alloc] init];
request.user = #"+552199881234";
request.number = #"+5521717171";
GTLQueryMyAPI *query = [GTLQueryMyAPI queryForApiSearchWithObject:request];
[service executeQuery:query completionHandler:^(GTLServiceTicket *ticket,
GTLMyAPIMessagesContactListResponse* object,
NSError *error)
{
NSArray* contacts = object.contacts;
}
Am I doing anything incredibly wrong here?

This is an annoying bug from iOS to Endpoints for local testing. I hope they fix it soon. :)
BTW instead of modifying QGTQueryMyAPI.m (which is a generated file). I do Theo's fix just after I create the query instead. So all of my queries that send data look like this (and I set that one flag to switch from localhost to deployed in other places too).
GTLQueryMyApi *query = [GTLQueryMyApi queryForSearchWithObject:someGtlObject];
if (LOCAL_HOST_TESTING) {
[query setJSON:someGtlObject.JSON];
}

This is not a great solution but a patch for now. I have the same problem when doing iOS endpoints localhost testing. However when I use the deployed backend I remove this line and everything is fine.
auth.shouldAuthorizeAllRequests = YES;
The "resource" key wrapping issue only happens when I add the line above to use localhost. So this morning I'm not using localhost, just the deployed version. Let me know if you fix the issue. :) Obviously pointing to the deployed version is not preferred for testing.

Alright! user2697002's answer showed me that this works when the webservice is deployed.
For development to work correctly this is the workaround I did.
The generated API uses a template like this for all queries in GTLQueryMyAPI.m
+ (id)queryForSearchWithObject:(GTLMyAPIMessagesSearchRequest *)object {
if (object == nil) {
GTL_DEBUG_ASSERT(object != nil, #"%# got a nil object", NSStringFromSelector(_cmd));
return nil;
}
NSString *methodName = #"myapi.search";
GTLQueryMyAPI *query = [self queryWithMethodName:methodName];
query.bodyObject = object;
query.expectedObjectClass = [GTLMyAPIMessagesContactListResponse class];
return query;
}
For this to work on development server one could substitute all these lines
query.bodyObject = object;
With
query.JSON = object.JSON;
This stops from wrapping the JSON in a "resource" field. Somehow I believe this shouldn't be done on deployment release version.

I'm still experimenting but believe this is the proper way (swift) to set up for testing on localhost....
let _service = GTLServiceBackendAPI();
_service.allowInsecureQueries = true;
_service.isRESTDataWrapperRequired = false;
_service.retryEnabled = true;
_service.fetcherService.allowLocalhostRequest = true;
_service.rpcURL = NSURL(string: "http://localhost:8080/_ah/api/rpc?prettyPrint=true")

Related

Twilio iOS client not passing parmeters on connect

Yet another problem with Twilio for me. So, I'm trying to connect with another user with parametes. Here's my code:
-(void)connect:(CDVInvokedUrlCommand*)command {
NSLog(#"The content of dict is%#",[command.arguments objectAtIndex:0]);
NSDictionary *dict = [command.arguments objectAtIndex:0];
for(NSString *key in [dict allKeys]) {
NSLog(#"%#",key);
NSLog(#"%#",[dict objectForKey:key]);
}
[self.device connect:dict delegate:self];
}
Problem: no matter what I have in NSDictionary nothing gets passed to server. I have tryied with number of parameters, nothing gets passed. Not even To parameters, on non of other, custom ones. It works for every other platform, but not for iOS.
What em I missing here? According to docs it should work, connect method is taking NSDictionary as input,
-connect:(NSDictionary*)params delegate:(id<TCConnectionDelegate>)delegate, so where should I look?
PS. This is yet another big problem Twilio lib that I had in last few days. Im getting enough of it.
OK, the problem was that I was passing NSDictionary with key that had integer value. The -connect method accepts only <NSString NSString> NSDictionary.
Let's figure this out. It’s not entirely clear from your code sample what exactly you've passed in as arguments so forgive me if I suggest something you might've already tried.
What happens if you try something like this?
NSDictionary *params = #{#"To": "number_to_dial"};
_connection = [_phone connect:params delegate:self];
If this does not work, we can be certain the problem lies in the account, token, or app itself.
The iOS sample shows how to pass the dialing parameters, however it’s still the developer’s responsibility to create proper ​TwiML that contains the dialing command tags that Twilio recognizes.
If the call is hitting your server though without any parameters being passed in, there should be a Twilio CallSid available in the TCConnectionDelegate.connectionDidConnect: method. If that's the case, I would suggest contacting support with that Sid and we can dig more info from the server to see what parameters are being passed.
Here's how to retrieve the CallSid:
- (void)connectionDidConnect:(TCConnection *)connection {
NSString *callsid = [[connection parameters] objectForKey:#"CallSid"];
...
}
Could you see if you are able to see this callback method being called and try to provide the CallSid if possible?

Get NSString out of ENNoteContent with Evernote Cloud SDK 2.0

I am new to Evernote SDK development and am using the evernote cloud SDK 2.0 as recommended by Evernote.
However, I am having trouble to get the NSString content out of the ENNoteContent object. I have tried the followings from searching online but none seems to work with the cloud sdk as I guess they are all for the old version of Evernote SDK...
1 Using "convertENMLToHTML" method.
According to this and this, I could call convertENMLToHTML directly on an ENNoteContent object much like this convertENMLToHTML:note.content. However, in the cloud SDK, this resulted in an exception inside ENMLUtility that terminates the app because convertENMLToHTML is expecting an NSString as opposed to ENNoteContent and the first thing this function does is trying to call [enmlContent dataUsingEncoding:NSUTF8StringEncoding]] which caused the exception if enmlContent is a pointer to ENNoteContent but not a pointer to NSString.
2 Attempting to get _emml object out of the ENNoteContent object
This post has a quote of calling [note.content enml] but this again doesn't work with cloud sdk as object enml isn't defined in the interface.
Does anyone know how one can get an NSString out of ENNoteContent? I would expect this to be a very straightforward process but am surprised that I wasn't able to find anything that works for the Cloud SDK.
3 Using generateWebArchiveData method
Per Sash's answer below, I have also attempted to use the generateWebArchiveData method in the example from the cloud sdk. The code I have looks like this:
[[ENSession sharedSession] downloadNote:result.noteRef progress:^(CGFloat progress) {
} completion:^(ENNote *note, NSError *downloadNoteError) {
if (note) {
NSLog(#"%#", note.title);
[note generateWebArchiveData:^(NSData *data) {
NSString* strContent = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"test content %#", strContent);
}];
} else {
NSLog(#"Error downloading note contents %#", downloadNoteError);
}
}];
However, strContent outputs "null" for a note that I have verified with legitimate content.
As a temporary hack, we added #property (nonatomic, copy) NSString * emml;
in ENNoteContent.h and removed the same line in ENNoteContent.m to get around this for now.
You are close. Technique #1 above is what you want, but as you discovered the enml property is private in the "default" SDK. Import the "advanced" header and you'll have access to note.content.enml. That is a string, and you can send it to convertENMLtoHTML if you prefer an HTML representation.
Do note that there is no "plaintext" string content for an existing note. You'll always see it as markup, and if you want to get rid of the markup, doing so is beyond the scope of the SDK-- how to do that depends very much on what the content you're dealing with looks like.
You should check out their samples included with SDK, seems like
-[ENNote generateWebArchiveData:] will get you HTML NSData in the completion block
https://github.com/evernote/evernote-cloud-sdk-ios/blob/master/Getting_Started.md#downloading-and-displaying-an-existing-note might also help

IOS AWS Cognito Handlers not being called and wrong dataset value being returned

I'm having a two related issue.
Issue One: with getting the Conflict Resolution Handler and Dataset Merge Handler to work. I've read the through the documentation multiple times but I'm simply not seeing any success and the documentation is vague at best. It appears the block handlers never seem to get called.
If I authentic through facebook, it takes my previous Unauthenticated identity and merges it into the facebook identity. However, now I have two conflicting dataset entries showing for that facebook identity:
Here is an example of what I'm doing:
- (void)synchronizeCognito
{
// Initialize the Cognito Sync client
AWSCognito *syncClient = [AWSCognito defaultCognito];
AWSCognitoDataset *dataset = [syncClient openOrCreateDataset:#"testing"];
// Create a record in a dataset and synchronize with the server
[dataset setString:identifier forKey:#"test1"];
[dataset setString:token forKey:#"test2"];
syncClient.conflictHandler = ^AWSCognitoResolvedConflict* (NSString *datasetName, AWSCognitoConflict *conflict) {
NSLog(#"%#", dataset);
// always choose local changes
return [conflict resolveWithRemoteRecord];
};
dataset.conflictHandler = ^AWSCognitoResolvedConflict* (NSString *datasetName, AWSCognitoConflict *conflict) {
// override and always choose remote changes
return [conflict resolveWithRemoteRecord];
};
syncClient.datasetMergedHandler = ^(NSString *datasetName, NSArray *datasets) {
// Blindly delete the datasets
for (NSString *name in datasets) {
AWSCognitoDataset *merged = [[AWSCognito defaultCognito] openOrCreateDataset:name];
[merged clear];
[merged synchronize];
}
};
// synchronize the data
[dataset synchronize];
}
Issue Two:
Again, when I authenticate my unauthenticated identity with facebook and it merges the two. I see: identity changed from us-east-1:b0a5b4c4-8d7b-4564-9f92-5ea49bbfdcdc to us-east-1:f0bea5d1-a888-4f8f-8957-6589d9700c1e
but if I do something like:
- (NSString *)getTest
{
AWSCognitoDataset *dataset = [syncClient openOrCreateDataset:#"testing"];
return [dataset stringForKey:#"test1"];
}
It return's test1 value data from the OLD identity's datastore instead of the new facebook identity's datastore even though they have now switched. I suspect because no conflict or merge handling was called above.
Sorry for the confusion. Your conflict handler will never be called in this scenario. Conflicts in Amazon Cognito only occur if both the local and remote data change in between a synchronization. Because you are changing data and merging an identity at the same time, the merge flow occurs.
When an identity merge is detected, the Amazon Cognito library does the following:
renames all local datasets to "NAME.old_identity_id"
calls the merge handler (if defined).
This means that if you made a change but did not synchronize, then logged in and caused an identity merge, the local change would never be propagated to the remote sync store unless you used the second flow from the developer guide and copied the data as necessary. I suspect this is what is causing your second issue.
As to your first, are you sure the merge handler is not being called? Can you add some debugging to your handler to see if it is actually being called?

Not deleting file from ftp using CFURLDestroyResource method in iphone

I have performed upload,download file from ftp using FTPHelper class. It's working perfectly.The issue generated in delete operation. While I'm deleting file from ftp server, nothing happens!. I don't know where I'm getting wrong. I have refered stackoverflow link to solve delete file from ftp but unable to do that.Below is my code to delete file from ftp.
pragma mark ***** Delete File From FTP
+(void)deleteFileFromFTPforItem:(NSString *) anItem
{
[sharedInstance deleteFileFromFTPforItem:anItem];
}
-(void)deleteFileFromFTPforItem:(NSString *) anItem
{
if (!self.uname || !self.pword) COMPLAIN_AND_BAIL(#"Please set user name and password first");
if (!self.urlString) COMPLAIN_AND_BAIL(#"Please set URL string first");
NSString *baseDeleteURL = [NSString stringWithFormat:#"%#/",self.urlString];
NSString *deleteFilePath = [baseDeleteURL stringByAppendingString:anItem];
CFURLRef deleteURL = (CFURLRef)[[NSURL alloc] initWithString:deleteFilePath];
//SInt32 *errorCode = NULL;
//CFURLDestroyResource(deleteURL, errorCode);
DeleteFile(deleteURL);
CFRelease(deleteURL);
}
static Boolean DeleteFile(CFURLRef urlToDelete)
{
Boolean success = true;
CFURLRef deleteURL = urlToDelete;
SInt32 *errorCode = NULL;
success = CFURLDestroyResource(deleteURL, errorCode);
return success;
}
Please give me a proper solution where am I going wrong.I have surfed lot of things but unable to get proper way to delete file from ftp.I have referred link to upload and download file to/from ftp.Your help would be appreciable.Thanks in advanced
To make a long story short, FTP support in NSURL and CFURL should be considered download-only. I don't think it ever fully worked, and ftp is thoroughly deprecated for any purposes other than anonymous downloads anyway, so it is unlikely to ever be fixed.
You can use other FTP access frameworks, as described in this question:
CFURLDestroyResource is now deprecated in iOS7. Anyone know what to use instead?
but really, you should probably be asking yourself whether using FTP is really the right way to do whatever you're trying to do, as opposed to (for example) WebDAV.

OData4ObjC without using proxyclasses

I am using OData4ObjC, want to know is there a way to add/update/delete an entry in a table without using proxy classes. Just similar way the OData4j for Android does
e.g.,
OEntity havinaCola = c.getEntity("Products", 3).execute();
I am currently using proxy classes for the same as mentioned below,
proxy = [[serviceEntities alloc] initWithUri:#"sampleservices/producer.svc/" credential:nil];
QueryOperationResponse *response = [proxy execute:#"customers"];
NSMutableArray *array = [response getResult];
Thanks.
I have found one way to do the same i.e., as mentioned in the book written by Author 'Matthew Baxter-Reynolds' 'Multimobile Development (Building applications for the iPhone and Android Platform)' suggests method how to GET/UPDATE/DELETE/ADD entries.
Hope this is useful.
Thanks

Resources