TwitterAPI 1.1への対応メモ

開発したアプリでTwitterAPI1.1への移行を行ったので、メモ。

TwitterAPI1.1で何が変わるのかという点については、いろいろな記事が書かれていて、すごく参考になりました。
結局、Twitter API 1.1で何が変わる? 5つのポイント:Twitter APIと開発者規約変更のインパクトまとめ - @IT

自分のアプリでは、次のAPIを使っていました。

  • トレンドの取得
  • ツイートの検索

TwitterAPI1.1になることで、次の点を考慮して修正する必要があります。

  • OAuthが必須になる
  • レートリミットの変更


ACAccountのidentifierを記録する文字列

@property (atomic,retain) NSString *accountId;

ACAccountの登録があれば、identifierの値を記憶しておきます。

	ACAccountStore *accountStore = [[ACAccountStore alloc]init];
	ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
	
	[accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
		if(granted)
		{
			NSArray *accounts = [accountStore accountsWithAccountType:accountType];
			if([accounts count] > 0)
			{
				ACAccount *account = accounts[0];
				self.accountId = account.identifier;
			}
		}
	}];

TWRequestクラスのsetAccountでACAccountを指定すればOKです。
ACAccountの登録がなかったり、アプリ自体がアクセスを許可されていない場合もレスポンスでわかります。

	ACAccountStore *accountStore = [[ACAccountStore alloc]init];
	ACAccount *account = [accountStore accountWithIdentifier:self.accountId];
	
	NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/1.1/trends/place.json?id=23424856"];
	
	TWRequest *request = [[TWRequest alloc]initWithURL:url parameters:nil requestMethod:TWRequestMethodGET];
	[request setAccount:account];
	
	[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
		if(responseData)
		{
			if(urlResponse.statusCode == 200)
			{
				NSError *jsonError;
				
				NSArray *jsonData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&jsonError];
				
				NSLog(@"%@",jsonData);
			}
			else
			{
				// 認証エラー、レートリミットオーバーなど
				NSLog(@"Error. %@",[[NSString alloc]initWithData:responseData encoding:NSUTF8StringEncoding]);
			}
		}
		else
		{
			// レスポンスを受け取れなかった場合
			
		}
	}];

TwitterAPIにアクセスした結果は、NSHTTPURLResponse.statusCodeの値で判別すればいいと思います。
正常に結果が返ってきた場合、200になります。

ACAccountをなんらかの理由で取得できなかった場合は、StatusCodeは400になり、
レスポンスは次のようになります。

{"errors":[{"message":"Bad Authentication data","code":215}]}

レートリミットをオーバーした場合は、StatusCodeは429になり、
レスポンスは次のようになります。

{"errors":[{"message":"Rate limit exceeded","code":88}]}

この辺はTwitterAPI1.0のときから同じだったかもしれませんが、今回調べてみてはじめて分かりました。(^^;

レートリミットはAPI単位でのカウントになったので、ものによっては連打するとあっという間に上限に達してしまいます。
(工夫次第でどうとでもなりそうですが。)

API毎のレートリミットはこちら。
https://dev.twitter.com/docs/rate-limiting/1.1/limits



ちなみに、iOS6のsocial.frameworkを使ってアクセスする場合はこうなります。

	ACAccountStore *accountStore = [[ACAccountStore alloc]init];
	ACAccount *account = [accountStore accountWithIdentifier:self.accountId];
	
	NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/1.1/trends/place.json?id=23424856"];
	
	SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:url parameters:nil];
	[request setAccount:account];
	
	[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
		if(responseData)
		{
			if(urlResponse.statusCode == 200)
			{
				NSError *jsonError;
				
				NSArray *jsonData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&jsonError];
				
				NSLog(@"%@",jsonData);
			}
			else
			{
				// 認証エラー、レートリミットオーバーなど
				NSLog(@"Error. %@",[[NSString alloc]initWithData:responseData encoding:NSUTF8StringEncoding]);
			}
		}
		else
		{
			// レスポンスを受け取れなかった場合
			
		}
	}];