Last active
December 20, 2015 17:39
-
-
Save beccadax/6170253 to your computer and use it in GitHub Desktop.
What I imagine a Cocoa-like Objective-C web framework woud look like. Pseudocode, so don't take it too seriously.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@interface MyRootController: OWWebController | |
// GET / | |
- (BOOL)get:(OWRequest*)request error:(NSError**)error { | |
return [request.responder renderTemplate:@"Root" withObject:nil error:error]; | |
} | |
// Everything under /users is handled by MyUsersController | |
- (OWWebController*)controllerForUsersRequest:(OWRequest*)request error:(NSError**)error { | |
return [[MyUsersController alloc] initWithManagedObjectContext:self.managedObjectContext]; | |
} | |
// Stuff inherited: | |
- (BOOL)request:(OWRequest*)request error:(NSError**)error; | |
- (OWController*)controllerForRequest:(OWRequest*)request error:(NSError**)error; | |
- (NSURL*)URLForComponents:(NSArray*)components andParameters:(NSDictionary*)params; // And, for instance, -URLForUsersAndParameters:, etc. | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@interface MyUsersController: OWRestfulWebController | |
- (NSString*)entityName { | |
return @"User"; | |
} | |
// Maybe there would be predicateForObjectsWith: and sortDescriptors in the parent class, and you could override those? | |
- (NSFetchRequest*)fetchRequestForObjectsWith:(NSString*)username forRequest:(OWRequest*)request error:(NSError**)error { | |
NSFetchRequest * fetchReq = [super fetchRequestForObjectsWith:username forRequest:request error:error]; | |
if(username) { | |
fetchReq.predicate = [NSPredicate predicateWithFormat:@"username = %@", username]; | |
} | |
else { | |
fetchReq.sortDescriptors = @[ [NSSortDescriptor sortDescriptorForKey:@"username" ascending:YES] ]; | |
} | |
return YES; | |
} | |
// Ensures only you can edit your own account. | |
// There are also methods like -canPut:with:error: if there's only one action to worry about. | |
- (BOOL)canPerformAction:(SEL)action forRequest:(OWRequest*)request withComponents:(NSArray*)components error:(NSError**)error { | |
if(![super canPerformAction:action forRequest:request withComponents:components error:error]) { | |
return NO; | |
} | |
if(action == @selector(put:with:error:) || action == @selector(delete:with:error:) || action == @selector(get:with:editWithError:) || action == @selector(post:with:followWith:error:)) { | |
User * accessingUser = [self objectWith:components.firstObject forRequest:request error:error]; | |
User * authenticatingUser = [self objectWith:request.session[@"authenticatedUser"] forRequest:request error:error]; | |
// Should sessions be structured somehow? Or should we expect people to declare appropriate categories on OWSession/OWWebController? | |
if(authenticatingUser != accessingUser && !authenticatingUser.administrator) { | |
*error = [NSError errorWithDomain:OWErrorDomain code:OWErrorUnauthorized userInfo:@{ NSLocalizedDescriptionKey: NSLocalizedString(@"You are not authorized to access this user's data.", @"") }]; | |
return NO; | |
} | |
} | |
return YES; | |
} | |
// These actions are all implemented by OWRestfulWebController, so we get them for free: | |
// GET . | |
- (BOOL)get:(OWRequest*)request error:(NSError**)error; | |
// POST . | |
- (BOOL)post:(OWRequest*)request error:(NSError**)error; | |
// GET ./new | |
- (BOOL)get:(OWRequest*)request newWithError:(NSError**)error; | |
// GET ./$username | |
- (BOOL)get:(OWRequest*)request with:(NSString*)component error:(NSError**)error; | |
// PUT ./$username | |
- (BOOL)put:(OWRequest*)request with:(NSString*)component error:(NSError**)error; | |
// DELETE ./$username | |
- (BOOL)delete:(OWRequest*)request with:(NSString*)component error:(NSError**)error; | |
// GET ./$username/edit | |
- (BOOL)get:(OWRequest*)request with:(NSString*)component editWithError:(NSError**)error; | |
// Everything under ./$username/posts is handled by MyPostsController | |
- (OWWebController*)controllerWith:(NSString*)username postsWithRequest:(OWRequest*)request error:(NSError**)error { | |
OWUser * user = [self objectWith:username forRequest:request error:error]; | |
// This would be a custom-implemented initializer | |
return [[MyPostsController alloc] initWithUser:user]; | |
} | |
// Here are some additional non-restful actions... | |
// GET ./suspended | |
- (BOOL)get:(OWRequest*)request suspendedWithError:(NSError**)error { | |
NSFetchRequest * fetchReq = [self fetchRequestForObjectsWith:nil forRequest:request error:error]; | |
if(!fetchReq) { | |
return nil; | |
} | |
fetchReq.predicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:[NSPredicate predicateWithFormat:@"suspended == YES"], fetchReq.predicate, nil]]; | |
NSArray * users = [self.managedObjectContext executeFetchRequest:fetchReq error:error]; | |
if(!users) { | |
return NO; | |
} | |
return [request.responder renderTemplate:@"MyUsersController/suspended" withObject:users error:error]; | |
} | |
// POST ./$foo/follow/$bar | |
- (BOOL)post:(OWRequest*)request with:(NSString*)username followWith:(NSString*)otherUsername error:(NSError**)error { | |
OWAccount * me = [self objectWith:username forRequest:request error:error]; | |
OWAccount * other = [self objectWith:otherUsername forRequest:request error:error]; | |
if(!me || !other) { | |
return NO; | |
} | |
[me addFollowing:other]; | |
if(![self.managedObjectContext save:error]) { | |
return NO; | |
} | |
return [request.responder redirectTo:[OWApplication.sharedApplication.rootWebController URLForUsersWith:otherUsername andParameters:nil]]; | |
} | |
// DELETE ./$foo/follow/$bar | |
- (BOOL)delete:(OWRequest*)request with:(NSString*)username followWith:(NSString*)otherUsername error:(NSError**)error { | |
OWUser * me = [self objectWith:username forRequest:request error:error]; | |
OSUser * other = [self objectWith:otherUsername forRequest:request error:error]; | |
if(!me || !other) { | |
return NO; | |
} | |
[me removeFollowing:other]; | |
if(![self.managedObjectContext save:error]) { | |
return NO; | |
} | |
return [request.responder redirectTo:[OWApplication.sharedApplication.rootWebController URLForUsersWith:otherUsername andParameters:nil]]; | |
} | |
// Stuff inherited: | |
- (NSArray*)objectsWith:(NSString*)username forRequest:(OWRequest*)request error:(NSError**)error; | |
- (NSManagedObject*)objectWith:(NSString*)username forRequest:(OWRequest*)request error:(NSError**)error; // Requires exactly one, errors otherwise | |
- (NSManagedObject*)newObjectForRequest:(OWRequest*)request error:(NSError**)error; | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment