Thursday, April 11, 2013

How to use SOAP WebService API - Objective-C iOS

http://www.w3schools.com/webservices/tempconvert.asmx

The above URL provides two SOAP web service

1. CelsiusToFahrenheit

Request Format:


POST /webservices/tempconvert.asmx HTTP/1.1
Host: www.w3schools.com
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/CelsiusToFahrenheit"

<?xml version="1.0" encoding="utf-8"?>
<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/">
  <soap:Body>
    <CelsiusToFahrenheit xmlns="http://tempuri.org/">
      <Celsius>string</Celsius>
    </CelsiusToFahrenheit>
  </soap:Body>
</soap:Envelope>
   
Response Format


HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<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/">
  <soap:Body>
    <CelsiusToFahrenheitResponse xmlns="http://tempuri.org/">
      <CelsiusToFahrenheitResult>string</CelsiusToFahrenheitResult>
    </CelsiusToFahrenheitResponse>
  </soap:Body>
</soap:Envelope>

2. FahrenheitToCelsius

Request Format:



POST /webservices/tempconvert.asmx HTTP/1.1
Host: www.w3schools.com
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/FahrenheitToCelsius"

<?xml version="1.0" encoding="utf-8"?>
<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/">
  <soap:Body>
    <FahrenheitToCelsius xmlns="http://tempuri.org/">
      <Fahrenheit>string</Fahrenheit>
    </FahrenheitToCelsius>
  </soap:Body>
</soap:Envelope>
Response Format:



HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<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/">
  <soap:Body>
    <FahrenheitToCelsiusResponse xmlns="http://tempuri.org/">
      <FahrenheitToCelsiusResult>string</FahrenheitToCelsiusResult>
    </FahrenheitToCelsiusResponse>
  </soap:Body>
</soap:Envelope>

iPhone application is going to consume these two service to convert Fahrenheit to Celsius and vice versa. 


#import <Foundation/Foundation.h>


@interface RequestResponseHandler : NSObject<NSURLConnectionDelegate, NSXMLParserDelegate>
{
    NSURLConnection *connection;
    NSMutableData *responseData;
    CallBack callback;
    
    NSMutableDictionary *model;
}

-(void) executeRequest:(NSURLRequest*) request completion:(CallBack) completionCallback;

+(RequestResponseHandler*) sharedInstance;

@end




#import "RequestResponseHandler.h"
#import "CelsiusToFahrenheitResponse.h"
#import "FahrenheitToCelsiusResponse.h"

static RequestResponseHandler *sharedInstance;

@implementation RequestResponseHandler

- (id)init
{
    self = [super init];
    if (self) {
        responseData = [[NSMutableData alloc] init];
    }
    return self;
}

+(RequestResponseHandler*) sharedInstance
{
    if  (sharedInstance == nil)
    {
        sharedInstance = [[self alloc] init];
    }
    
    return sharedInstance;

}

-(void) executeRequest:(NSURLRequest*) request completion:(CallBack)completionCallback
{
    callback = completionCallback;
    connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}


- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    responseData = [[NSMutableData alloc] init];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [responseData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    
    responseData = nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)aconnection {
    
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:responseData];
    parser.delegate = self;
    [parser parse];
}


-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
        
    if ([elementName isEqualToString:@"CelsiusToFahrenheitResult"])
    {
        model = [[NSMutableDictionary alloc] init];
        [model setObject:@"" forKey:@"CelsiusToFahrenheitResult"];
    }
    else if ([elementName isEqualToString:@"FahrenheitToCelsiusResult"])
    {
        model = [[NSMutableDictionary alloc] init];
        [model setObject:@"" forKey:@"FahrenheitToCelsiusResult"];
    }
 
}

//This method is to store the result between element (Result):
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
 
    NSArray *keys = [model allKeys];
    for (NSString *key in keys) {
        [model setValue:string forKey:key];
    }
        
}


-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
{
    if ([elementName isEqualToString:@"CelsiusToFahrenheitResult"] || [elementName isEqualToString:@"FahrenheitToCelsiusResult"]) {
        callback(model);
    }
}


@end

#import <Foundation/Foundation.h>


@interface SoapRequestFactory : NSObject

+(SoapRequestFactory*) defaultInstance;
-(NSURLRequest*) getRequestForType:(REQUEST_TYPE) requestType embeddingValue:(NSString*) value;

@end

#import "SoapRequestFactory.h"

static SoapRequestFactory *sharedInstance;

@implementation SoapRequestFactory


+(SoapRequestFactory*) defaultInstance
{
    if  (sharedInstance == nil)
    {
        sharedInstance = [[self alloc] init];
    }
    
    return sharedInstance;
}

-(NSURLRequest*) getRequestForType:(REQUEST_TYPE) requestType embeddingValue:(NSString*) value
{
    switch (requestType) {
        case CELSIUS_TO_FAHRENHEIT:
            return [self getCelsiusToFahrenheit:value];
            
        case FAHRENHEIT_TO_CELSIUS:
            return [self getFahrenheitToCelsius:value];

            
        default:
            break;
    }
}

-(NSURLRequest*) getCelsiusToFahrenheit:(NSString*) value
{
    
    NSString *soapMessage = @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
    "<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/\">"
    "<soap:Body>"
    "<CelsiusToFahrenheit xmlns=\"http://tempuri.org/\">"
    "<Celsius>%@</Celsius>"
    "</CelsiusToFahrenheit>"
    "</soap:Body>"
    "</soap:Envelope>";
    
    
    NSString *message = [NSString stringWithFormat:soapMessage, value];

    NSURL *url = [NSURL URLWithString:@"http://w3schools.com/webservices/tempconvert.asmx"];
    NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
    NSString *msgLength = [NSString stringWithFormat:@"%d", [message length]];
    
    [theRequest addValue: @"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    [theRequest addValue: @"http://tempuri.org/CelsiusToFahrenheit" forHTTPHeaderField:@"SOAPAction"];
    [theRequest addValue: msgLength forHTTPHeaderField:@"Content-Length"];
    [theRequest setHTTPMethod:@"POST"];
    [theRequest setHTTPBody: [message dataUsingEncoding:NSUTF8StringEncoding]];
    
    
    return theRequest;
}




-(NSURLRequest*) getFahrenheitToCelsius:(NSString *) value
{
    NSString *soapMessage = @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
    "<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/\">"
    "<soap:Body>"
    "<FahrenheitToCelsius xmlns=\"http://tempuri.org/\">"
    "<Fahrenheit>%@</Fahrenheit>"
    "</FahrenheitToCelsius>"
    "</soap:Body>"
    "</soap:Envelope>";
    
    NSString *message = [NSString stringWithFormat:soapMessage, value];
    
    NSURL *url = [NSURL URLWithString:@"http://w3schools.com/webservices/tempconvert.asmx"];
    NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
    NSString *msgLength = [NSString stringWithFormat:@"%d", [message length]];
    
    [theRequest addValue: @"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    [theRequest addValue: @"http://tempuri.org/FahrenheitToCelsius" forHTTPHeaderField:@"SOAPAction"];
    [theRequest addValue: msgLength forHTTPHeaderField:@"Content-Length"];
    [theRequest setHTTPMethod:@"POST"];
    [theRequest setHTTPBody: [message dataUsingEncoding:NSUTF8StringEncoding]];
    
    
    return theRequest;
}



@end

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController<UITextFieldDelegate>
{
    IBOutlet UISegmentedControl *segmentedControl;
    IBOutlet UILabel *result;
    NSString *value;
}

-(IBAction)segmentControlChanged:(id) sender;

@end

#import "ViewController.h"

#import "SoapRequestFactory.h"
#import "RequestResponseHandler.h"
#import "CelsiusToFahrenheitResponse.h"
#import "FahrenheitToCelsiusResponse.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
 // Do any additional setup after loading the view, typically from a nib.
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [textField resignFirstResponder];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    value = textField.text;
    [self segmentControlChanged:segmentedControl];
    
    return YES;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated.
}

-(IBAction)segmentControlChanged:(UISegmentedControl*) sender
{
    NSURLRequest *request = [[SoapRequestFactory defaultInstance] getRequestForType:sender.selectedSegmentIndex embeddingValue:value];
    
    if (sender.selectedSegmentIndex == 0) {
        [[RequestResponseHandler sharedInstance] executeRequest:request  completion:^(NSDictionary *response){
            result.text = [response valueForKey:@"CelsiusToFahrenheitResult"];            
            
        }];
    }
    else
    {
        [[RequestResponseHandler sharedInstance] executeRequest:request  completion:^(NSDictionary *response){
            result.text = [response valueForKey:@"FahrenheitToCelsiusResult"];            
        }];
    }
}

@end

1 comment:

Unknown said...

Hi Stalin,

I follow your Soap web service Api - IOS ,it is very good ..i have one doubt how you manage callback variable i didn't understand. please if you have source code for this please share with me. i am waiting for your replay.

Thanks & Regards,
Jilanibasha.shaik.