Skip to content

Instantly share code, notes, and snippets.

@khanlou
Last active May 24, 2016 15:01
Show Gist options
  • Save khanlou/e4d24affadbf6694391c to your computer and use it in GitHub Desktop.
Save khanlou/e4d24affadbf6694391c to your computer and use it in GitHub Desktop.
Requests
@interface SKRequestBuilder ()
@property (nonatomic) SKSafeRequestTemplate *safeTemplate;
@end
@implementation SKRequestBuilder
- (instancetype)initWithRequestTemplate:(id<SKRequestTemplate>)template {
self = [super init];
if (!self) return nil;
_safeTemplate = [[SKSafeRequestTemplate alloc] initWithTemplate:template];
return self;
}
- (id<SKRequestTemplate>)template {
return self.safeTemplate.unsafeTemplate;
}
- (NSData *)HTTPBody {
if (!self.safeTemplate.parameters || self.safeTemplate.isGETRequest) {
return nil;
}
return [NSJSONSerialization dataWithJSONObject:self.safeTemplate.parameters options:0 error:nil];
}
- (NSURL *)URL {
NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:self.safeTemplate.baseURL resolvingAgainstBaseURL:YES];
NSString *path = [URLComponents.path stringByAppendingString:self.safeTemplate.path];
URLComponents.path = path;
if (self.safeTemplate.isGETRequest) {
URLComponents.queryItems = [[self parametersAsQueryItems] arrayByAddingObjectsFromArray:URLComponents.queryItems];
}
return URLComponents.URL;
}
- (NSArray *)parametersAsQueryItems {
NSMutableArray *queryItems = [NSMutableArray array];
[self.safeTemplate.parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[queryItems addObject:[NSURLQueryItem queryItemWithName:key value:obj]];
}];
return queryItems;
}
- (NSURLRequest *)URLRequest {
NSMutableURLRequest *mutableURLRequest = [[NSMutableURLRequest alloc] init];
mutableURLRequest.HTTPMethod = self.safeTemplate.method;
mutableURLRequest.HTTPBody = [self HTTPBody];
mutableURLRequest.URL = [self URL];
[self.safeTemplate.headers enumerateKeysAndObjectsUsingBlock:^(NSString *fieldName, NSString *value, BOOL *stop) {
[mutableURLRequest addValue:value forHTTPHeaderField:fieldName];
}];
return [mutableURLRequest copy];
}
@end
@protocol SKRequestTemplate <NSObject>
@property (readonly) NSURL *baseURL;
@optional
@property (readonly) NSString *method;
@property (readonly) NSString *path;
@property (readonly) NSDictionary *parameters;
@property (readonly) NSDictionary *headers;
- (void)finalizeWithResponse:(SKResponseHandler *)response;
@end
@interface SKResponseHandler ()
@end
@implementation SKResponseHandler
- (instancetype)initWithResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *)error {
self = [super init];
if (!self) return nil;
_response = response;
_data = data;
_error = error;
_result = [NSJSONSerialization JSONObjectWithData:self.data options:0 error:nil];
return self;
}
- (NSHTTPURLResponse *)HTTPResponse {
if ([self.response isKindOfClass:[NSHTTPURLResponse class]]) {
return (NSHTTPURLResponse *)self.response;
}
return nil;
}
- (NSInteger)statusCode {
return self.HTTPResponse.statusCode;
}
@end
@implementation SKSafeRequestTemplate
- (instancetype)initWithTemplate:(id<SKRequestTemplate>)template {
self = [super init];
if (!self) return nil;
_unsafeTemplate = template;
return self;
}
- (NSString *)method {
if ([self.unsafeTemplate respondsToSelector:@selector(method)]) {
return [self.unsafeTemplate method];
}
return @"GET";
}
- (BOOL)isGETRequest {
return [self.method isEqualToString:@"GET"];
}
- (NSURL *)baseURL {
if ([self.unsafeTemplate respondsToSelector:@selector(baseURL)]) {
return [self.unsafeTemplate baseURL];
}
return nil;
}
- (NSString *)path {
if ([self.unsafeTemplate respondsToSelector:@selector(path)]) {
return [self.unsafeTemplate path];
}
return nil;
}
- (NSDictionary *)parameters {
if ([self.unsafeTemplate respondsToSelector:@selector(parameters)]) {
return [self.unsafeTemplate parameters];
}
return nil;
}
- (NSDictionary *)headers {
if ([self.unsafeTemplate respondsToSelector:@selector(headers)]) {
return [self.unsafeTemplate headers];
}
return nil;
}
- (void)finalizeWithResponse:(id<SKResponse>)response {
if ([self.unsafeTemplate respondsToSelector:@selector(finalizeWithResponse:)]) {
[self.unsafeTemplate finalizeWithResponse:response];
}
}
@end
@interface SKSendableRequest ()
@property (nonatomic) SKRequestBuilder *requestBuilder;
@end
@implementation SKSendableRequest
- (instancetype)initWithRequestTemplate:(id<SKRequestTemplate>)template {
self = [super init];
if (!self) return nil;
_requestBuilder = [[SKRequestBuilder alloc] initWithRequestTemplate:template];
return self;
}
- (id<BAKRequestTemplate>)template {
return self.requestBuilder.template;
}
- (BAKSafeRequestTemplate *)safeTemplate {
return self.requestBuilder.safeTemplate;
}
- (void)sendRequestWithSuccessBlock:(void (^)(id result))successBlock failureBlock:(void (^)(NSError *error))failureBlock {
[[[NSURLSession sharedSession] dataTaskWithRequest:self.requestBuilder.URLRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
BAKResponseHandler *responseHandler = [[BAKResponseHandler alloc] initWithResponse:response data:data error:error];
[self.safeTemplate finalizeWithResponse:responseHandler];
if (error || responseHandler.error) {
if (failureBlock) {
failureBlock(responseHandler.error);
}
} else {
if (successBlock) {
successBlock(responseHandler.result);
}
}
});
}] resume];
}
@end
@onmyway133
Copy link

Thanks for the great blog post. But finally, it seems you choose the "One object per request", which is to instantiate the object, make request, and wait for result in the completion block

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment