This is the fourth tutorial of Pico tutorial series, in this tutorial, I will show you how to integrate Pico with eBay Shopping Web Service, if you are not familar with this service, just have a quick reivew on its official site, basically, eBay Shopping service allows you to search for eBay items, products and reviews, user info, and popular items and searches. In previous tutorials, I showed you how to integrate Pico with SOAP based services, while in this tutorial, I will show you how to interate Pico with XML based service, the eBay Shopping service just support XML message format.
Depends on the network speed, you may need to wait a few moments to let the code generator download the wsdl and generate code, you may also download the wsdl and run the code generator with a local wsdl.
A few comments about the codegen options:
The code generator will throw many warnings, say that the wsdl violates some schema rule, just ignore them, it’s ok as long as the final code is generated correctly.
I have added a prefix Shopping_ as codegen option, such that all interfaces/types generated will be prefixed with Shopping_. Adding prefix to Objective-C types is a recommended best practice to avoid possible type name conflict with code generated from other services, for example, eBay has a couple of services, and they share a few commons types, without prefixing, you may get conflict if you use two or more eBay services in one application.
I have added a special -ebayshopping codegen option, this is because eBay Shopping service needs a per-call operation name HTTP header(eBay Finding service also needs a similar but different header), I added this special flag in the code generator to let it generate the header for me, since I don’t want to add this header everytime I call an eBay Shopping service, so this is just a special flag for eBay Shopping services and for demo only, or a hidden feature, not a generic codegen option.
Step 2 - Create New iOS Project, Add Pico Library and Generated Proxy into Your Project
Create a new simple iOS single view application named “HelloeBayShopping”, don’t choose ARC since Pico does not support ARC yet.
In this tutorial, we will reference Pico as a static library, suppose you have downloaded Pico source project from github site, then:
Drag the Pico xcodeproj into your project,
In the Build Phases of the target, add libPico.a and libxml2.dylib to “Link Binary With Libraries” section.
In the Build Setting of the target, add [your path to Pico source] to “User Header Search Paths” setting, choose “recursive” seach path.
Build the project to ensure that it can build successfully.
Now drag the proxy generated in step 1 into the project, choose “Copy items to destination group’s folder” and “add to targets” when prompted.
Build the project again to ensure that it can build successfully.
The code generation will genenrate both SOAP and XML based interfaces from eBay Shopping wsdl for us,
since we will use XML based interface in this tutorial, you may now review the generated eBay Shopping service XML interface to learn what kinds of functions are provided by eBay Shopping service, and what kinds of parameters are needed to call the serivce, the interface is posted below:
// Generated by wsdl compiler for ios/objective-c// DO NOT CHANGE!#import <Foundation/Foundation.h>#import "PicoXMLClient.h"#import "Shopping_GetCategoryInfoResponseType.h"#import "Shopping_GetSingleItemResponseType.h"#import "Shopping_GetMultipleItemsResponseType.h"#import "Shopping_FindProductsRequestType.h"#import "Shopping_GetMultipleItemsRequestType.h"#import "Shopping_FindReviewsAndGuidesResponseType.h"#import "Shopping_FindHalfProductsRequestType.h"#import "Shopping_FindPopularSearchesResponseType.h"#import "Shopping_FindProductsResponseType.h"#import "Shopping_GetCategoryInfoRequestType.h"#import "Shopping_GetUserProfileRequestType.h"#import "Shopping_GeteBayTimeResponseType.h"#import "Shopping_GetShippingCostsRequestType.h"#import "Shopping_GetItemStatusResponseType.h"#import "Shopping_GetUserProfileResponseType.h"#import "Shopping_FindHalfProductsResponseType.h"#import "Shopping_GetItemStatusRequestType.h"#import "Shopping_FindPopularSearchesRequestType.h"#import "Shopping_GetShippingCostsResponseType.h"#import "Shopping_FindReviewsAndGuidesRequestType.h"#import "Shopping_FindPopularItemsResponseType.h"#import "Shopping_GetSingleItemRequestType.h"#import "Shopping_GeteBayTimeRequestType.h"#import "Shopping_FindPopularItemsRequestType.h"/** This class is the XML client to the ShoppingInterface Web Service.*/@interfaceShoppingInterface_XMLClient : PicoXMLClient{}/** public method*/-(void)findHalfProducts:(Shopping_FindHalfProductsRequestType*)requestObjectsuccess:(void(^)(Shopping_FindHalfProductsResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)findPopularItems:(Shopping_FindPopularItemsRequestType*)requestObjectsuccess:(void(^)(Shopping_FindPopularItemsResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)findPopularSearches:(Shopping_FindPopularSearchesRequestType*)requestObjectsuccess:(void(^)(Shopping_FindPopularSearchesResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)findProducts:(Shopping_FindProductsRequestType*)requestObjectsuccess:(void(^)(Shopping_FindProductsResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)findReviewsAndGuides:(Shopping_FindReviewsAndGuidesRequestType*)requestObjectsuccess:(void(^)(Shopping_FindReviewsAndGuidesResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)getCategoryInfo:(Shopping_GetCategoryInfoRequestType*)requestObjectsuccess:(void(^)(Shopping_GetCategoryInfoResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)getItemStatus:(Shopping_GetItemStatusRequestType*)requestObjectsuccess:(void(^)(Shopping_GetItemStatusResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)getMultipleItems:(Shopping_GetMultipleItemsRequestType*)requestObjectsuccess:(void(^)(Shopping_GetMultipleItemsResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)getShippingCosts:(Shopping_GetShippingCostsRequestType*)requestObjectsuccess:(void(^)(Shopping_GetShippingCostsResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)getSingleItem:(Shopping_GetSingleItemRequestType*)requestObjectsuccess:(void(^)(Shopping_GetSingleItemResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)getUserProfile:(Shopping_GetUserProfileRequestType*)requestObjectsuccess:(void(^)(Shopping_GetUserProfileResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;/** public method*/-(void)geteBayTime:(Shopping_GeteBayTimeRequestType*)requestObjectsuccess:(void(^)(Shopping_GeteBayTimeResponseType*responseObject))successfailure:(void(^)(NSError*error))failure;@end
All the methods in the interface follow same calling paradigm - you call the service with required request object and register success callback(for success handling logic) and failure callback(for error handling logic) using Objective-C block.
You may also compare the XML interface with the SOAP interface, they are almost similar, except that SOAP interface will give you an additional SOAPFault object in the failure callback, this is obvious, since XML based service has no concept of SOAPFault, usually, the error is returned as response resident error(RRE) in the XML response message.
Step 3 - Implement Appliction Logic and UI, Call Proxy to Invoke Web Service as Needed.
Note, unlike shared clients created in previous tutorials, the EBayShoppingServiceClient extends ShoppingInterface_XMLClient, which means we are using XML service interface supported by Pico.
#import "EBayShoppingServiceClient.h"staticNSString*consteBayAppId=@"YOUR APPID HERE";// productionstaticNSString*consteBayShoppingServiceURLString=@"http://open.api.ebay.com/shopping?";// sandbox//static NSString *const eBayShoppingServiceURLString = @"http://open.api.sandbox.ebay.com/shopping";staticNSString*consttargetAPIVersion=@"809";/** for site id list, see http://developer.ebay.com/DevZone/shopping/docs/CallRef/types/SiteCodeType.html */staticNSString*consttargetSiteId=@"0";// 0 for US@implementationEBayShoppingServiceClient+(EBayShoppingServiceClient*)sharedClient{staticEBayShoppingServiceClient*_sharedClient=nil;staticdispatch_once_tonceToken;dispatch_once(&onceToken,^{_sharedClient=[[EBayShoppingServiceClientalloc]initWithEndpointURL:[NSURLURLWithString:eBayShoppingServiceURLString]];});return_sharedClient;}-(id)initWithEndpointURL:(NSURL*)URL{self=[superinitWithEndpointURL:URL];if(!self){returnnil;}[supersetDefaultHeader:@"X-EBAY-API-APP-ID"value:eBayAppId];[supersetDefaultHeader:@"X-EBAY-API-REQUEST-ENCODING"value:@"XML"];[supersetDefaultHeader:@"X-EBAY-API-VERSION"value:targetAPIVersion];[supersetDefaultHeader:@"X-EBAY-API-SITE-ID"value:targetSiteId];returnself;}@end
Like eBay Finding service, the eBay Shopping service needs a few HTTP headers set to work, let me give more comments:
eBay Shopping service needs to set a few HTTP headers to work, for a list of required headers, please refer to doc here.
One mandatory header for eBay Shopping service is eBayAppId, you need to register on eBay developer site as an eBay developer then get this id, before your can run this demo, you must fill in your own eBayAppId in the shared client.
Another mandatory header for eBay Shopping service is targetAPIVersion, aka the API version you want to use, usually, you use the latest one, at the time of this writing, the latest version is 809, you may update this according to your real needs.
We also set X-EBAY-API-REQUEST-ENCODING to XML, indicating we want to call XML service supported by eBay Shopping service.
Now the UI part, we will find one popular item from eBay by keywords, since this is a hello world like sample, we just need a UITextField for keyword input and UIButton to trigger eBay search by invoking method searchButtonPressed which will indirectly call eBay Shopping findPopularItems API through the proxy, fairly simple, see definition in header file ViewController.h and instantiation in implementation file ViewController.m.
Now implement the searchButtonPressed method by invoking service as below:
#import "ViewController.h"#import "Shopping_CommonTypes.h"#import "EBayShoppingServiceClient.h"#import "Toast+UIView.h"-(void)searchButtonPressed:(id)sender{// Hide the keyboard.[_searchTextresignFirstResponder];if(_searchText.text.length>0){// start progress activity[self.viewmakeToastActivity];// Get shared service clientEBayShoppingServiceClient*shoppingClient=[EBayShoppingServiceClientsharedClient];shoppingClient.debug=YES;// enable request/response message logging// Build request objectShopping_FindPopularItemsRequestType*request=[[[Shopping_FindPopularItemsRequestTypealloc]init]autorelease];request.queryKeywords=_searchText.text;// only need one item for demorequest.maxEntries=[NSNumbernumberWithInt:1];// make API call and register callbacks[shoppingClientfindPopularItems:requestsuccess:^(Shopping_FindPopularItemsResponseType*responseObject){// stop progress activity[self.viewhideToastActivity];if([Shopping_AckCodeType_SUCCESSisEqualToString:responseObject.ack]){if(responseObject.itemArray.item.count>0){// show the title of the first found itemShopping_SimpleItemType*item=[responseObject.itemArray.itemobjectAtIndex:0];// start image downloading progress activity[self.viewmakeToastActivity];// get gallery imageNSURL*imageURL=[NSURLURLWithString:item.galleryURL];NSData*imageData=[NSDatadataWithContentsOfURL:imageURL];// stop progress activity[self.viewhideToastActivity];UIImage*image=[UIImageimageWithData:imageData];[self.viewmakeToast:item.titleduration:3.0position:@"center"title:@"Success"image:image];}else{// no result[self.viewmakeToast:@"No result"duration:3.0position:@"center"];}}else{// response resident errorShopping_ErrorType*error=[responseObject.errorsobjectAtIndex:0];[self.viewmakeToast:error.shortMessageduration:3.0position:@"center"title:@"Error"];}}failure:^(NSError*error){[self.viewmakeToast:[errorlocalizedDescription]duration:3.0position:@"center"title:@"Error"];}];}}
More comments to the serivce call code:
I’ve added comments in the code so the whole service call flow should be easy to understand.
We used the eBay Shopping findPopularItems call, which takes a keyword as input, and will return a list of matched popular items on eBay, for demo, we just need one item to display, so we set maxEntries to 1.
In the success handling logic, we show the title and the image of the returned item, for demo, the image is downloaded synchronously, but in practice, you should download image asynchronously in order not to block main UI.
eBay Shopping service supports response resident error(RRE), so even we get a success response, we still need to check the response for resident error and handle it accordingly.
We used a thrid party library called “Toast” for producing toast like message, this is just for the convenience of demo, not necessary in your real project.
The maxEntries property of Shopping_FindPopularItemsRequestType is of type NSNumber, you may get confused what kind of number should be put in maxEntries, short, int or long? please just consult the source of Shopping_FindPopularItemsRequestType.h, it provides type hint as code comments, see [NSNumber type hint] below. Indeed, every type generated from wsdl has sufficient type hint to assist your development. Xsd annotations in wsdl/schema are also generated into corresponding interfaces/types, further facilitating your development.
Similarly, in response handling, the item property of Shopping_SimpleItemArrayType is of type NSMutableArray, you may get confused what is the actual entry type? please just consult the source of Shopping_SimpleItemArrayType.h for type hint, see [NSMuatableArray entry type hint] below.
Xsd enumeration is mapped to Objective-C NSString in Pico framework, for example, the ack property of Shopping_FindPopularItemsResponseType is of type NSString, in wsdl, it’s an xsd enumeration of type AckCodeType, the type hint in Shopping_AbstractResponseType.h(from which Shopping_FindPopularItemsResponseType.h extends) will tell you where to find the enum constants allowed by ack property, in this case, the allowed enum constants are in Shopping_AckCodeType.h, see [Enum type hint below] :
/**Specifies the maximum number of entries to return in a single call.type : NSNumber, wrapper for primitive int*/@property(nonatomic,retain)NSNumber*maxEntries;
/** Indicates whether the call was successfully processed by eBay. type: string constant in Shopping_AckCodeType.h */@property(nonatomic,retain)NSString*ack;
Please don’t forget to include the shared client header file, it’s a best practice to include the generated Shopping_CommonTypes.h file which can free you from writing many import statements required by request building and response handling.
Final Step - Run the Demo
Let’s run the demo in iPhone simulator, see a sceen shot below:
let’s also try a error case, for example, if you forget to fill in your eBayAppId in the shared client, then you will get:
This is just a bare minimum eBay Shopping service based application, for a demo with more functions, please see the eBayDemoApp sample in the Examples folder of Pico source, eBayDemoApp is a composite app which calls two eBay services behind, this app searches eBay by calling eBay Finding service, shows a list of matched items on UI, when an item is clicked, it will show item details by calling eBay Shopping service, see a screen shot below.
Now it’s your turn to create iOS applications based on eBay Shopping and eBay Finding web services, see your next great service based app.
Update 1
The eBay Shopping Service Proxy has been extracted as a standalone project, hosted here, and the corresponding appledoc is hosted here, the appledoc is a useful programming reference. By the way, the doc annotations in wsdl are not only generated into the proxy code, but into the appledoc, assisting your development.