Sunday, March 2, 2014

REST API and JSON


Hi all,

Almost every mobile app uses REST API where user needs to handle web requests.
The request could be GET or POST
The data to be carried could be JSON or XML or nay other.

So today we will be working on GET and POST requests using JSON.

Hope you find it useful and easy too. 
:)

Lets begin...

***********************How things work******************************

LoginViewController 
  •  Implements the Webservice Protocol.
  •  Calls method of webserviceManager to execute login webrequest
  •  Handles response

WebServiceManager
  • Creates JSON request dict / object.
  • Makes GET / POST request.
  • Creates NSURL Connections.
  • Receives the Response.
  • Using delegate makes a callback to the calling class that implemented the protocol method.
***************************************************************************

1) Create WebServiceManager.h
  •     @property (weak, nonatomic) id                               delegate;
  •     @property (strong, nonatomic) NSMutableData       *responseData;
  •     @property (strong, nonatomic) NSURLConnection *remoteConnection;
  •     @property (nonatomic) NSInteger                             statusCode;
  •    @property (strong, nonatomic) NSMutableData        *connectionData;
  •    @property (nonatomic) WebServiceTransactionType   transactionType;
  •    Create ENUMS
2) Create protocol in WebServiceManager.h.
    This protocol will be implemented by the class that implements it
     typedef NS_ENUM (NSInteger, WebServiceTransactionType)
    {
        WebServiceTransactionTypeUserLogin,
        WebServiceTransactionTypeUserLogout,
    };

    typedef NS_ENUM (NSInteger, NetworkOperationStatusCode)
   {
        NetworkOperationStatusCodeUnkown,
        NetworkOperationStatusCodeInProgress,
        NetworkOperationStatusCodeSuccess,
       NetworkOperationStatusCodeError
   };

     #pragma mark - Delegate Protocol

    @protocol WebServiceTransactionResponseDelegate <NSObject>

    @required

     - (void)assitant : (WebServicesManager *)assistant
           transaction : (WebServiceTransactionType)type
                   status : (NetworkOperationStatusCode)statusCode
         remoteData : (id)remoteData;

@end

3) WebServiceManager.m 

a) Execute login with POST request  & credentials in JSON format.
    Call this method from any class

- (void)authenticateLoginforUserName : (NSString*)userName
                                              password : (NSString*)password
                                     transactiontype : (WebServiceTransactionType)transaction_type
                                               delegate : (id)del
{
    self.delegate = del;  
    
    NSDictionary *requestDict = [[NSDictionary alloc] initWithObjectsAndKeys:
                                 userName  ,@"userName",
                                 password   ,@"password",
                                 nil];
    
    NSString *url = [NSString stringWithFormat:@"%@%@",BASE_URL,LOGIN_REQUEST];

    [self createURLRequest : url 
                        requestDict : requestDict 
                 transactionType : transaction_type 
                             delegate : del];
}

b) Creating a generic method that handles GET / POST request

- (void)createURLRequest : (NSString*)url
                        requestDict : (NSDictionary*)requestDict
                transactionType : (WebServiceTransactionType)transaction_type
                            delegate : (id)del
{
    if (self.remoteConnection)
        [self.remoteConnection cancel];
    
    self.delegate = del;
    self.transactionType = transaction_type;
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:
                                                                                        [NSURL URLWithString : url]];

    [request setValue : @"application/json" forHTTPHeaderField : @"Content-Type"];
    
    if(requestDict != nil)
    {
        [request setHTTPMethod:@"POST"];

        NSData *jsonData = [NSJSONSerialization dataWithJSONObject : requestDict 
                                                                                                          options : 0 
                                                                                                              error : nil];
        [request setHTTPBody : jsonData];
    }
    else
        [request setHTTPMethod : @"GET"];
    

    [request setTimeoutInterval : 10];
    
    self.remoteConnection = [NSURLConnection connectionWithRequest : request
                                                                                                      delegate : self];
    self.statusCode = -1;
    [self.remoteConnection start];
}


c) NSURLConnection Delegate methods


- (void)connection : (NSURLConnection *)connection 
                                        didFailWithError : (NSError *)error
{
        if([self.delegate respondsToSelector:@selector(assitant : transaction : status : remoteData : )])
        {
            [self.delegate assitant : self
                            transaction : self.transactionType
                                    status : NetworkOperationStatusCodeError
                          remoteData : nil];
        }
      
    if (connection == self.remoteConnection)
        self.remoteConnection = nil;
}


- (void)connection : (NSURLConnection *)connection 
                                    didReceiveResponse : (NSURLResponse *)response
{
    self.statusCode = [(NSHTTPURLResponse*) response statusCode];
    
    if (self.statusCode > 200) return;
    
    self.connectionData = nil;
}

- (void)connection : (NSURLConnection *)connection 
                                     didReceiveData : (NSData *)data
{
    if (self.statusCode > 200 || data == nil) return;
    
    if (self.connectionData ==  nil)
        self.connectionData = [NSMutableData dataWithData:data];
    else
        [self.connectionData appendData : data];
}


- (void)connectionDidFinishLoading : (NSURLConnection *)connection
{
    id temp;

    if (self.statusCode > 200)
    {
        temp = nil;
        
        if([self.delegate respondsToSelector : @selector(assitant : transaction : status : remoteData : )])
        {
            [self.delegate assitant : self
                            transaction : self.transactionType
                                    status : NetworkOperationStatusCodeError
                          remoteData : nil];
        }
    }
    else
    {
        if (connection == self.remoteConnection)
            self.remoteConnection = nil;
        
        if(self.statusCode == 200)
        {
            if([self.delegate respondsToSelector:@selector(assitant : transaction : status : remoteData :)])
            {
               NSDictionary *parsedData = [Utils convertJSONDataToDictionary : self.connectionData];
                
              // Check JSON Parsing in another blog of mine :  JSON Parsing Tutorial

                [self.delegate assitant : self
                                transaction : self.transactionType
                                        status : NetworkOperationStatusCodeSuccess
                              remoteData : parsedData];
            }
        }
    }
}

4) Implementing the protocol in LoginViewController.h

 @interface LoginViewController : UIViewController              
                                                         <WebServiceTransactionResponseDelegate>

    @end

5) Calling WebServiceManager from LoginViewController.m

    WebServicesManager *webManager = [[WebServicesManager alloc] init];

    [webManager authenticateLoginforUserName : @"Swati"
                                                              password : @"password"
                                                     transactiontype : WebServiceTransactionTypeUserLogin
                                                                delegate : self];

6) Handling response in LoginViewController.m

-  (void) assitant : (WebServicesManager *)assistant
        transaction : (WebServiceTransactionType)type
                status : (NetworkOperationStatusCode)statusCode
      remoteData : (id)remoteData
{
    switch (type)
    {
        case WebServiceTransactionTypeUserLogin:
        {            
            if(statusCode == NetworkOperationStatusCodeError)
            {
                // FAILURE                
                return;
            }
          else
          {
                  // SUCCESS
           }
        }
            break;
        default:
            break;
    }
}

tada........

now try out yourself.....