Developing
an iOS App sometimes needs a REST API Server to communicate with and handle
most of the app’s data. So how should we start in developing the connection
between an iOS app to a REST API Server?
I
have developed a few iOS apps and basically the basic workflow I currently have
in developing that kind of app is:
1.
Use a networking library to connect to the web service.
2.
Download the server response (JSON, XML and etc.).
3.
Parse the response by transforming it into an NSDictionary or NSArray.
4.
Handle or display the data retrieved from the NSDictionary or NSArray.
And "poof"
you now have a working iOS app connecting to a REST API Server. Sounds simple
right? So to start the tutorial lets first talk about the needed tools in order
to start the app development.
XCode
and Objective-C
You
are going to develop an iOS app surely you should know about XCode and Objective-C?
So for those who still don’t have any idea about XCode and Objective-C there
are quite a lot of great tutorials on the web probably you could start on
Apple’s “Your First iOS App”.
Networking
Library
Your
app couldn’t live without networking and to add to it, networking is hard.
There are quite various parts and factors that you really need to understand
and consider to make it work. There is already NSURLConnection on Apple’s Foundation
framework to handle networking however like I said it’s hard to understand.
Fortunately, a quite few open-source libraries have emerged to make networking
easy. Thank God for open-source.
One
such library is AFNetworking, created
and maintained by the awesome people of Gowalla,
which its former name is “Alamofire”(Where they based “AF” for the name
AFNetworking, cool). It is an easy to use network API for iOS. It contains
everything you need to interface with online resources, web services to file
downloads. It also helps you ensure that your UI is still responsive even when
your app is in the middle of a large download. There are other networking
libraries out there but I find AFNetworking as the library that is fit for our
app.
REST
API Server
Aside
from being an iOS developer I am also a Python-Django Developer. So I have
decided to use Python
as the language and Django
as its web framework for the REST API Server. And yes, I mentioned on the
tutorial’s title Django so probably most of you who are viewing this page
should have already an idea regarding about Python and Django. If not there are
quite a few resources on the web regarding Python and Django.
So
moving on, basically we need to create an API framework from scratch. Just kidding,
why create when there are open-sourced API frameworks ready to be implemented
on your Django app, unless you really want to create your own REST API
framework for your app (so hardcore… lol). Choosing from the
list of known API frameworks, we previously chose django-rest-framework (version
0.4.0, I know it’s an old version…lol) to be used on our REST API Server
however just recently we started working on Django-TastyPie. So why use Django-TastyPie? I guess they have good
documentation, found out it was basically mostly used to connect to an iOS app,
good community and other reasons are found on there “Why TastyPie”
section on github.
Getting Started with AFNetworking
Okay, we already talked about the tools used for
the app development. So to start the app development, I guess you already have
created a new project on XCode. If not, here is a tutorial on creating a new project
on XCode. After creating a new project, download and add the
AFNetworking library to your project. You could add the library by just
dragging the folder into your XCode project, as shown on the image below.
After adding up
you could probably develop your own Client class to which you could use the
AFNetworking library. Here is a sample ClientSDK developed by my fellow
developer, Mr. JA Arce.
+ (void)query: (NSString *)queryPath: (NSString *)method: (NSDictionary *)data: (void(^)(NSMutableDictionary*
data))callback {
/* querypath
-- The relative URL of the resource ex. article, telemedicine, etc.
method -- Either POST, PUT or GET it's up to you
baby!
data -- it'll be treated as a POST Data or
Query String depending on the method.
callback -- callback function/completion block.
*/
NSUserDefaults *userDefaults
= [NSUserDefaults standardUserDefaults];
NSString *urlPath = [NSString stringWithFormat:@"%@%@/",API_URL,queryPath];
NSURL *url = [[NSURL alloc] initWithString:urlPath];
AFHTTPClient *httpClient =
[[AFHTTPClient alloc] initWithBaseURL:url];
[httpClient setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"OAuth
%@", [userDefaults objectForKey:@"access_token"]]];
if ([method isEqualToString:@"GET"]) {
[httpClient getPath:urlPath parameters:data success:^(AFHTTPRequestOperation *operation, id
responseObject) {
callback([self parseResponseToDict:operation.responseData]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
callback([self parseResponseToDict:operation.responseData]);
}];
} else if ([method isEqualToString:@"POST"]) {
[httpClient postPath:urlPath parameters:data success:^(AFHTTPRequestOperation *operation, id
responseObject) {
callback([self parseResponseToDict:operation.responseData]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
callback([self parseResponseToDict:operation.responseData]);
}];
} else {
//whatever!?
:P
}
}
The query method, as shown above basically connects to the API
Rest Server with the url, urlPath
string variable. The urlPath is
composed of the API_URL (The
base URL of the API Rest Server) and the
queryPath (The relative URL). Basically
on userDefaults the access_token can be found which was stored during
authentication, I will discuss later on how the Access Token was created. The
Access token is used and placed on the request header as shown on this line of
code.
[httpClient setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"OAuth
%@", [userDefaults objectForKey:@"access_token"]]];
The Authorization request-header would be
checked on the REST API Server, which I will discuss later on. The request
method is then checked if it’s either a GET or a POST request. Then after which
the client then connects to the REST API Server. The success and failure block
will run depending on the response of the REST API server. The JSON response
would then be parsed and transform into a NSMutableDictionary using the parseResponseToDict
method found below.
+ (NSMutableDictionary *)parseResponseToDict: (NSData
*)responseData {
NSError *err;
NSString *responseStr
= [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSData *data =
[responseStr dataUsingEncoding:NSUTF8StringEncoding];
NSMutableDictionary
*jsonDictionary = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&err];
return
jsonDictionary;
}
So basically you could use the code above
like the one shown below which fetches for the user data.
- (void)fetchUserData
{
{
NSUserDefaults *userDefault
= [NSUserDefaults standardUserDefaults];
NSString *urlPath = [NSString stringWithFormat:@"user/%@", [userDefault
objectForKey:@"user_id"]];
[PClientSDK query:urlPath :@"GET" :nil :^(NSMutableDictionary *data) {
NSString *displayName
= [NSString stringWithFormat:@"%@
%@", [data objectForKey:@"first_name"], [data objectForKey:@"last_name"]];
[self.displayNameLbl setText:displayName];
}];
}
The query method is
found on the PClientSDK class so we
can call it as shown above. Basically the code uses a GET request method and if the connection is successful it will
display the first_name and last_name found on the data NSMutableDictionary. As you can
see AFNetworking is easy to use. You could explore more methods on the library
like AFJSONRequestOperation
and many more.
Getting Started with Django-TastyPie
So now let us start discussing on how to implement
Django-TastyPie. I assume you already have a working Django project with models
and other stuff needed to run the project app. First we need to install
Django-TastyPie:
$ pip install django-tastypie
Then let us use the built-in Django User Model as a sample. We
then create a file named api.py and
there we can create a Resource for the User Model.
class UserResource(ModelResource):
class Meta:
queryset = User.objects.all()
resource_name = 'user'
authorization = DjangoAuthorization()
authentication =
OAuth20Authentication()
You could check the documentation
of TastyPie regarding the fields on class Meta. However I will discuss the
authentication field, which is used to verify a certain user and validate their
access to the API. Remember the Access Token we added on the Authorization
request-header, it was used on the custom authentication as shown below.
class
OAuth20Authentication(Authentication):
def __init__(self, realm='API'):
self.realm = realm
def is_authenticated(self, request, **kwargs):
"""
Verify 2-legged oauth request.
Parameters accepted as
values in "Authorization"
header, or as a GET request
or in a POST body.
"""
logging.info("OAuth20Authentication")
try:
key = request.GET.get('oauth_consumer_key')
if not key:
key = request.POST.get('oauth_consumer_key')
if not key:
auth_header_value =
request.META.get('HTTP_AUTHORIZATION')
if auth_header_value:
key =
auth_header_value.split('
')[1]
if not key:
logging.error('OAuth20Authentication. No
consumer_key found.')
return None
"""
If verify_access_token() does not
pass, it will raise an error
"""
token = verify_access_token(key)
# If OAuth authentication is successful, set the
request user to the token user for authorization
request.user = token.user
# If OAuth authentication is successful, set
oauth_consumer_key on request in case we need it later
request.META['oauth_consumer_key'] = key
return True
except KeyError, e:
logging.exception("Error in
OAuth20Authentication.")
request.user = AnonymousUser()
return False
except Exception, e:
logging.exception("Error in
OAuth20Authentication.")
return False
return True
def verify_access_token(key):
# Check if key is in AccessToken key
try:
token =
AccessToken.objects.get(token=key)
# Check if token has expired
if token.expires < timezone.now():
raise OAuthError('AccessToken has expired.')
except AccessToken.DoesNotExist, e:
raise OAuthError("AccessToken
not found at all.")
logging.info('Valid access')
return token
Basically the custom authentication just checks for a provided HTTP_AUTHORIZATION and looks up to see
if the token is a valid OAuth Access Token. If ever it fails it will return an
error. So every time a request to the REST API Server is called the custom
authentication would then run and authenticates if the request is valid or not.
After adding up the resources we then update the urls.py.
from tastypie.api import Api
from api import UserResource
v1_api
= Api(api_name='v1')
v1_api.register(UserResource())
urlpatterns
+= patterns("",
url(r'^api/', include(v1_api.urls)),
}
Then you can curl to the
server the URL (assuming you are running it on localhost) to retrieve the users
data which is formatted on json depending on what you added on the format GET
parameter.
curl -v -H "Authorization: OAuth
"
http://localhost:8000/api/v1/users/?format=json
You would then have a JSON response upon calling the URL on the
REST API Server. Then all you have to do
is call the URLs on your iOS App. But wait, how was the Access token created? Basically we installed
django-oauth2-provider also to handle OAuth2.0 on our REST API Server. Just
read the docs
on installing it. And after installing it we need to add and create a method on
our Client Class for authentication.
#define CLIENT_ID @"#####################"
#define CLIENT_SECRET @"##########################"
#define
OAUTH_URL @"http://localhost:8000/oauth2/access_token/"
+ (void)authenticate: (NSString *)username: (NSString *)password: (void(^)(NSMutableDictionary*
data))callback {
// username
-- Username of the user in NSString format
// password
-- Password of the user in NSString format
// callback
-- callback function/completion block.
NSURL *url = [[NSURL alloc] initWithString:OAUTH_URL];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
CLIENT_ID , @"client_id",
CLIENT_SECRET, @"client_secret",
@"password" , @"grant_type",
username , @"username",
password , @"password",
@"write" , @"scope"
, nil];
AFHTTPClient *httpClient =
[[AFHTTPClient alloc] initWithBaseURL:url];
[httpClient postPath:@"" parameters:params success:^(AFHTTPRequestOperation *operation, id
responseObject) {
callback([self parseResponseToDict:operation.responseData]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
callback([self parseResponseToDict:operation.responseData]);
}
];
}
Then call the method on your login view.
- (void)loginUser {
NSString *username = self.usernameIn.text;
NSString *password = self.passwordIn.text;
[PClientSDK authenticate:username
:password :^(NSMutableDictionary *data) {
if (!data) {
[Utils createAlert:@"An
Unexpected Error Occured." :@"Error Message" :@"Ok"];
} else if ([data objectForKey:@"error"]) {
[Utils createAlert:@"Invalid
Username/Password." :@"Error Message" :@"Ok"];
} else {
NSUserDefaults *userDefaults
= [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[data objectForKey:@"access_token"] forKey:@"access_token"];
[userDefaults setObject:[data objectForKey:@"user_id"] forKey:@"user_id"];
[self navigateToDashboard];
}
}];
}
As you could see on the above code the string username and
password are passed on the authenticate method
on the PClientSDK. Then checks the values returned by the server on the data NSMutableDictionary if it is valid
or not. If it is valid it will store the user_id
and access_token created for that
user on NSUserDefaults. Then everytime a request to the server is called the access_token on NSUserDefaults would be
needed.
Simple right? Now you can connect the iOS App to your Django app. whew
I n this regards it is a wise idea to have a firm grasp of Abu Dhabi Website Design the fundamentals before venturing off into more advanced courses.
ReplyDeleteRegular people call for savings and also other cheap small business arrivals. For the reason that they will journey over a day-to-day foundation. Number of air flow arrivals companies take into account these types of people while many do not.discount travel
ReplyDeleteWebsite development, the speediest growing segment one of the different procedures regarding video pattern, message or calls on the imaginative along with wonderful knowledge of the video designer, nonetheless it usually takes developers far from the bodily marketing with that they can are generally almost all acquainted. Instead, website development difficulties the generation regarding eye-catching along with evocative types solely in the electric, electronic digital moderate.CMS for html sites
ReplyDelete