Cocoa/CocoaTouchからRemember The Milk APIを使ってみる(その2:APIの呼び出しと署名)

さて、MD5で何に署名するのかというわけで、APIの呼び出し。
こんなフォーマットでメソッドとパラメータを送る。GETでもPOSTでもいい。

http://www.rememberthemilk.com/services/api/request.rest.rtm
http://api.rememberthemilk.com/services/rest/?method=rtm.test.echo&api_key=123456789&name=value

これをただ送信するわけではなくて、次のような作法で署名する。
http://www.rememberthemilk.com/services/api/authentication.rtm

キー/バリューペアを、キーのアルファベット順でソートする。

yxz=foo feg=bar abc=baz

これを

abc=baz feg=bar yxz=foo

こう。

キー/バリューペアを結合し、Shared Secretと結合する。

abc=baz feg=bar yxz=foo

これを結合して

abcbazfegbaryxzfoo

Shared Secret(API Keyの申請をするともらえる)を前にくっつける

BANANASabcbazfegbaryxzfoo

MD5の値を求めて、パラメータに付加する。

BANANASabcbazfegbaryxzfoo

こういう文字列から、前回書いたメソッドMD5値を求めて、パラメータに付加する。3

http://api.rememberthemilk.com/services/rest/?method=rtm.test.echo&api_key=123456789&name=value&api_sig=zxy987

ソースコード

私が書いたコードでNSURLRequestを作るとこんな感じ。POST。cachePolicyだのtimeoutIntervalは適当。

NSDictionary *requestKeyValue
パラメータを入れておく
NSString *methodString
RTM APIのメソッドを入れておく
__apiKey
API Keyを入れておく
__sharedSecret
Shared Secretを入れておく
__authToken
認証でもらったトークンを入れておく
__apiURL
送信先のURL(http://api.rememberthemilk.com/services/rest/
	NSMutableDictionary *mutableRequestKeyValue;
	if (requestKeyValue)
		mutableRequestKeyValue= [[requestKeyValue mutableCopy] autorelease];
	else
		mutableRequestKeyValue = [NSMutableDictionary dictionary];

	if (__apiKey)
		[mutableRequestKeyValue setObject:__apiKey forKey:@"api_key"];
	if (__authToken) 
		[mutableRequestKeyValue setObject:__authToken forKey:@"auth_token"];
	[mutableRequestKeyValue setObject:methodString forKey:@"method"];
	requestKeyValue = [[mutableRequestKeyValue copy] autorelease];
	
	NSArray *keys = [requestKeyValue allKeys];
	NSArray *sortedKeys = [keys sortedArrayUsingSelector:@selector(compare:)];

	NSMutableString *apiSigInput = [NSMutableString string];
	if (__sharedSecret)
		[apiSigInput setString:__sharedSecret];
	NSMutableString *httpBody = [NSMutableString string];
	
	for (NSString *key in sortedKeys) {
		NSString *value = [requestKeyValue objectForKey:key];
		
		[apiSigInput appendString:key];
		[apiSigInput appendString:value];
		
		value = [value stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
		
		if ([httpBody length] > 0) {
			[httpBody appendString:@"&"];
		}
		[httpBody appendFormat:@"%@=%@", key, value];
	}
	
	NSString *apiSig = [apiSigInput md5];
	[httpBody appendFormat:@"&api_sig=%@", apiSig];
	
	NSData *httpBodyData = [httpBody dataUsingEncoding:NSASCIIStringEncoding];
	
	NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:__apiURL]
														   cachePolicy:NSURLRequestReloadIgnoringCacheData
													   timeoutInterval:30];
	[request setHTTPMethod:@"POST"];
	[request setHTTPBody:httpBodyData];

で、実際にAPIを使う時はその前に認証をしなければならない。それは次回。