Tags

    MetaWeblog API & Objective-C: newPost

    Comments

    Looking at the MetaWeblog API, a post can several fields. I really hate it when methods are bloated with too many parameters, so I'll encapsulate the data related to a post in a "Post" class.

    #import <Cocoa/Cocoa.h>
    
    @interface Post : NSObject {
     NSString* title;
     NSCalendarDate* dateCreated;
     NSString* description;
     NSString* postId;
     NSString* blogId;
     NSString* summary;
     NSArray *categories;
     NSString* link;
     NSString* keywords;
     NSString* more;
    }
    
    @property(readwrite,copy) NSString* title;
    @property(readwrite,copy) NSCalendarDate* dateCreated;
    @property(readwrite,copy) NSString* description;
    @property(readwrite,copy) NSString* postId;
    @property(readwrite,copy) NSString* blogId;
    @property(readwrite,copy) NSString* summary;
    @property(readwrite,copy) NSArray *categories;
    @property(readwrite,copy) NSString* link;
    @property(readwrite,copy) NSString* keywords;
    @property(readwrite,copy) NSString* more;
    
    - (id) init;
    
    @end
    

    With the implementation not looking any more spectacular.

    #import "Post.h"
    
    @implementation Post
    
    @synthesize title;
    @synthesize dateCreated;
    @synthesize description;
    @synthesize postId;
    @synthesize blogId;
    @synthesize categories;
    @synthesize summary;
    @synthesize link;
    @synthesize keywords;
    @synthesize more;
    
    - (id) init
    {
     dateCreated = [NSCalendarDate init];
     description = @"";
     postId = @"";
     title = @"";
     summary = @"";
     categories = nil;
     link = @"";
     keywords = @"";
     more = @"";
     return self;
    }
    
    @end
    

    Lets add a method to create a new post. First, I'll need a class to encapsulate the MetaWeblog API. Surprise, surprise, its called MetaWeblog. I made the design choice to initialize the instances of this class with the url, credentials and blog id that will be used to create new posts. My gut tells me it is required for all calls.

    #import <Cocoa/Cocoa.h>
    #import "Post.h"
    
    @interface MetaWeblog : NSObject {
            NSString *url;  
            NSString *username;
            NSString *password;
            NSString *blogId;
    }
    
    @property(readwrite,copy) NSString *url; 
    @property(readwrite,copy) NSString *username;
    @property(readwrite,copy) NSString *password;
    @property(readwrite,copy) NSString *blogId; 
    
    - (id) initWithArgs: (NSString*)theUrl andUsername: (NSString*) theUsername andPassword: (NSString*) thePassword andBlogId: (NSString*) theBlogId;
    - (NSString*)newPost: (Post*) post;
    
    @end
    

    The implementation looks daunting. In reality, it isn't.

    #import "MetaWeblog.h"
    
    @implementation MetaWeblog
    
    @synthesize url; 
    @synthesize username;
    @synthesize password;
    @synthesize blogId; 
    
    - (id) initWithArgs: (NSString*)theUrl andUsername: (NSString*) theUsername andPassword: (NSString*) thePassword andBlogId: (NSString*) theBlogId
    {
     url = theUrl;
     username = theUsername;
     password = thePassword;
     blogId = theBlogId;
     [super init]; 
     return self;
    }
    
    - (NSString*)newPost: (Post*) post
    {
     // create local copies of the attributes
     NSString* title = post.title;
     NSString* summary = post.summary;
     NSString* body = post.description;
     NSDate* date = post.dateCreated;
     NSString* more = post.more;
     NSArray* categories = [[NSArray alloc] initWithArray: post.categories copyItems: YES];
     
     // configure parameters
     NSString *description = body;
     WSMethodInvocationRef rpcCall;
     NSURL *rpcURL = [NSURL URLWithString: url];
     NSString *methodName = @"metaWeblog.newPost";
     NSArray *postKey = [NSArray arrayWithObjects: @"description", @"dateCreated", @"title", @"mt_excerpt", @"mt_text_more", @"categories", nil];
     NSArray *postObject = [NSArray arrayWithObjects: description, date, title, summary, more, categories, nil];
     NSDictionary *post = [NSDictionary dictionaryWithObjects:postObject forKeys:postKey]; 
     NSArray *keys = [NSArray arrayWithObjects: @"blog_ID" , @"username", @"password", @"post", @"publish", nil];
     NSMutableArray *objects = [NSArray arrayWithObjects: blogId, username, password, post, kCFBooleanTrue, nil];
     NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
     NSArray *order = [NSArray arrayWithObjects: @"blog_ID", @"username", @"password", @"post", @"publish", nil];
     
     // create the XMLRPC method and invoke it
     rpcCall = WSMethodInvocationCreate ((CFURLRef) rpcURL, (CFStringRef) methodName, kWSXMLRPCProtocol);
     WSMethodInvocationSetParameters (rpcCall, (CFDictionaryRef) params, (CFArrayRef) order);
     NSDictionary *result = (NSDictionary *) (WSMethodInvocationInvoke (rpcCall));
     
     // Check for errors
     if (WSMethodResultIsFault((CFDictionaryRef)result))
     {
      NSString* faultString = [result objectForKey: (NSString *) kWSFaultString];
      NSLog(@"[metaWeblog.newPost] failed = %@", result); 
      NSException* theException = [NSException exceptionWithName: @"MetaWeblogException" reason: faultString userInfo:nil]; 
      @throw theException; 
     }
     
     // Log the success
     NSLog(@"[metaWeblog.newPost] result = %@", result); 
    
     // Return the URL
     return (NSString*) [result objectForKey:(NSString*)kWSMethodInvocationResult ];
    }
    
    @end
    

    Most of the call above is to configure the params and order variables. These are passed into the rpcCall which we create and then invoke. Lastly, we free resources and check for results. Upon success we return the url of the post that was created. Now lets use it to create a post in a weblog. I believe this should work against any weblog, including MovableType, Expression Engine or WordPress. I use ExpressionEngine so, I'm going to use that. One thing to note is that you must link against the "CoreServices" framework in order to compile and run this.

    #import <Cocoa/Cocoa.h>
    #import "MetaWeblog.h"
    
    int main(int argc, char *argv[])
    {
     NSString* url = @"https://example.com/index.php?ACT=52&id=82";
     NSString* username = @"Klaas";
     NSString* password = @"Vakie!";
     NSString* blogId = @"13";
     
     MetaWeblog* blog = [[MetaWeblog alloc] initWithArgs: url 
               andUsername:username 
               andPassword:password 
                 andBlogId:blogId];
     Post* post = [[Post alloc] init];
     post.title = @"My first post";
     post.description = @"Tant Sannie; life is lekker here";
     [blog newPost:post];
     [post release];
     [blog release];      
     return 0;
    }
    
    

    Sure enough, running this code snippet results in a "My first post" in the blog. Go ahead, try it. In the next installment, I'll add the ability to upload an image to the server. For an aperture plug-in, this will be critical. I can't wait.