はてなハイクAPIを使ってみよう(LINQ to XML)
C#から「はてなハイクAPI (http://h.hatena.ne.jp/api)」を利用するサンプルを作りました。
他の言語のサンプルは割りとあるようですが、C#ではなかったようなので。
画像を添付した投稿については面倒くさいので直接はサポートしていませんが、
呼び出し側で頑張れば、画像を投稿することも可能なようになっています。
また、画像添付投稿以外のAPI操作については、ほぼサポートしています。
(取得データの扱いについては、LINQ to XMLでの利用を前提としています^^)
HatenaHaikuクラス
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Xml.Linq; namespace ClassLibrary1 { /// <summary> /// はてなハイク /// </summary> public class HatenaHaiku { #region コンストラクタ public HatenaHaiku(string id, string password) { Id = id; Password = password; } public HatenaHaiku(string id, string pass, string clientName) : this(id, pass) { ClientName = clientName; } #endregion #region プロパティ private string Id { get; set; } private string Password { get; set; } private string ClientName { get; set; } /// <summary> /// 接続できるか否かを取得します。 /// </summary> /// <returns></returns> public bool CanConnect { get { WebRequest req = CreateWebRequest("http://h.hatena.ne.jp/api/statuses/update.xml"); req.Method = "GET"; try { using (var wr = (HttpWebResponse)req.GetResponse()) return wr.StatusCode == HttpStatusCode.OK; } catch { return false; } } } #endregion #region メソッド /// <summary> /// 対象UriからデータをXDocument形式で取得します。 /// </summary> /// <param name="uri"></param> /// <param name="parameters">パラメータのキーと値</param> /// <returns>XDocument</returns> private XDocument Get(string uri, params KeyValuePair<string, object>[] parameters) { var req = CreateWebRequest(uri); req.Method = "GET"; SetRequestParameters(req, parameters); var ar = req.BeginGetResponse(r => { }, req); ar.AsyncWaitHandle.WaitOne(new TimeSpan(0, 0, 20), false); var rps = req.EndGetResponse(ar); using (var sr = new StreamReader(rps.GetResponseStream(), Encoding.UTF8)) return XDocument.Parse(sr.ReadToEnd()); } /// <summary> /// 対象UriにデータをPOSTします。 /// </summary> /// <param name="uri"></param> /// <param name="parameters">パラメータのキーと値</param> /// <returns></returns> public bool Post(string uri, params KeyValuePair<string, object>[] parameters) { try { WebRequest req = CreateWebRequest(uri); req.Method = "POST"; SetRequestParameters(req, parameters); var result = (HttpWebResponse)req.GetResponse(); return result.StatusCode == HttpStatusCode.OK; } catch { return false; } } /// <summary> /// WebRequestに対してPOSTする値を設定します。 /// </summary> /// <param name="req"></param> /// <param name="parameters"></param> private void SetRequestParameters(WebRequest req, IEnumerable<KeyValuePair<string, object>> parameters) { byte[] postValue = null; if (parameters.Count() != 0) { var s = ""; foreach (var item in parameters.Select((x,i) => new {v = x, Index = i})) { if (item.Index != 0) s += "&"; s += item.v.Key + "=" + Uri.EscapeUriString(item.v.Value.ToString()); } postValue = Encoding.ASCII.GetBytes(s); req.ContentLength = postValue.Length; using (var strm = req.GetRequestStream()) { strm.Write(postValue, 0, postValue.Length); } } } #endregion #region 認証 /// <summary> /// Basic認証用の文字列を生成します。 /// </summary> /// <returns></returns> private string CreateAuthString() { return "Authorization: Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format("{0}:{1}",Id,Password))); } /// <summary> /// uriからWebリクエストを生成します。 /// </summary> /// <param name="uri"></param> /// <returns></returns> private WebRequest CreateWebRequest(string uri) { var req = HttpWebRequest.Create(uri); req.Proxy = new WebProxy(); ServicePointManager.FindServicePoint(uri, req.Proxy).Expect100Continue = false; req.ContentType = "application/x-www-form-urlencoded"; //req.ContentType = "multipart/form-data"; req.Headers.Add(CreateAuthString()); return req; } #endregion #region ステータス・タイムライン #region GET /// <summary> /// http://h.hatena.ne.jp/ に対応する、はてなハイク全体の最新のエントリーを返します。 /// </summary> /// <returns></returns> public XDocument GetPublicTimeline() { return Get("http://h.hatena.ne.jp/api/statuses/public_timeline.xml"); } /// <summary> /// http://h.hatena.ne.jp/user/following に対応する、認証したユーザー、 /// または指定したユーザーがフォローしているユーザー・キーワードのエントリーを返します。 /// </summary> /// <returns></returns> public XDocument GetFriendsTimeline(params KeyValuePair<string, object>[] parameters) { return Get("http://h.hatena.ne.jp/api/statuses/friends_timeline.xml", parameters); } /// <summary> /// http://h.hatena.ne.jp/user/ に対応する、認証したユーザー、または指定したユーザーの最新のエントリーを返します。 /// </summary> /// <returns></returns> public XDocument GetUserTimeline(params KeyValuePair<string, object>[] parameters) { return Get("http://h.hatena.ne.jp/api/statuses/user_timeline.xml", parameters); } /// <summary> /// http://h.hatena.ne.jp/keyword/keyword に対応する、指定したキーワードに投稿されたエントリを返します。 /// </summary> /// <returns></returns> public XDocument GetKeywordTimeline(params KeyValuePair<string, object>[] parameters) { return Get("http://h.hatena.ne.jp/api/statuses/keyword_timeline.xml",parameters); } /// <summary> /// 画像を含む最新のエントリのリストを返します。 /// </summary> /// <returns></returns> public XDocument GetAlbum() { return Get("http://h.hatena.ne.jp/api/statuses/album.xml"); } /// <summary> /// 指定されたキーワードの画像を含む最新のエントリリストを返します。 /// </summary> /// <param name="keyword"></param> /// <returns></returns> public XDocument GetAlbum(string keyword) { return Get(string.Format("http://h.hatena.ne.jp/api/statuses/album/{0}.xml", Uri.EscapeUriString(keyword))); } /// <summary> /// http://h.hatena.ne.jp/user/id に対応する、指定したエントリーの情報を返します。 /// </summary> /// <param name="id"></param> /// <returns></returns> public XDocument GetShow(string id) { return Get(string.Format("http://h.hatena.ne.jp/api/statuses/show/{0}.xml", Uri.EscapeUriString(id))); } #endregion #region POST /// <summary> /// 新しいエントリーを投稿します。 /// </summary> /// <param name="status"> /// 投稿する本文を指定します。 keyword=本文 の形式でも投稿できます。 /// 先頭の @id は id さんの最後のエントリーへの返信になります。 /// </param> /// <returns>結果</returns> public bool UpdateStatus(string status) { var parameters = new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("source",ClientName) ,new KeyValuePair<string, object>("status",status)}; return Post("http://h.hatena.ne.jp/api/statuses/update.xml", parameters); } /// <summary> /// 新しいエントリーを投稿します。 /// </summary> /// <param name="parameters">パラメータのキーと値</param> /// <returns></returns> public bool UpdateStatus(params KeyValuePair<string, object>[] parameters) { return Post("http://h.hatena.ne.jp/api/statuses/update.xml", parameters); } /// <summary> /// 指定したエントリーを削除します。 /// </summary> public bool DestroyStatus(string id) { return Post(string.Format("http://h.hatena.ne.jp/api/statuses/destroy/{0}.xml", Uri.EscapeUriString(id))); } #endregion #endregion #region スター関係 /// <summary> /// 指定したエントリーにスターを一つ追加します。 /// </summary> /// <param name="id"></param> public bool AddStar(string id) { return Post(string.Format("http://h.hatena.ne.jp/api/favorites/create/{0}.xml", Uri.EscapeUriString(id))); } /// <summary> /// 指定したエントリーのスターを一つ減らします。 /// </summary> /// <param name="id"></param> public bool DeleteStar(String id) { return Post(string.Format("http://h.hatena.ne.jp/api/favorites/destroy/{0}.xml", Uri.EscapeUriString(id))); } #endregion #region ユーザフォロー関係 #region GET /// <summary> /// 認証したユーザーがフォローしているユーザーのリストを100件返します。 /// </summary> /// <returns></returns> public XDocument GetFriends() { return Get("http://h.hatena.ne.jp/api/statuses/friends.xml"); } /// <summary> /// 指定したユーザーがフォローしているユーザーのリストを100件返します。 /// </summary> /// <param name="id"></param> /// <returns></returns> public XDocument GetFriends(string id) { return Get(string.Format("http://h.hatena.ne.jp/api/statuses/friends/{0}.xml", Uri.EscapeUriString(id))); } /// <summary> /// 認証したユーザーをフォローしているユーザーのリストを返します。 /// </summary> /// <returns></returns> public XDocument GetFollowers() { return Get("http://h.hatena.ne.jp/api/statuses/followers.xml"); } /// <summary> /// 指定したユーザーをフォローしているユーザーのリストを返します。 /// </summary> /// <param name="id"></param> /// <returns></returns> public XDocument GetFollowers(string id) { return Get(string.Format("http://h.hatena.ne.jp/api/statuses/followers/{0}.xml", Uri.EscapeUriString(id))); } /// <summary> /// 指定したユーザの情報を取得します。 /// </summary> /// <param name="id"></param> /// <returns></returns> public XDocument Getaaa(string id) { return Get(string.Format("http://h.hatena.ne.jp/api/friendships/show/{0}.xml", Uri.EscapeUriString(id))); } #endregion #region POST /// <summary> /// 指定ユーザーをお気に入りに追加します。 /// /// (旧:ユーザーをフォローします。) /// </summary> /// <param name="id"></param> /// <returns></returns> public bool AddFollowUser(string id) { return Post(string.Format("http://h.hatena.ne.jp/api/friendships/create/{0}.xml", Uri.EscapeUriString(id))); } /// <summary> /// 指定ユーザーをお気に入りから解除します。 /// /// (旧:ユーザーのフォローをやめます。) /// </summary> /// <param name="id"></param> /// <returns></returns> public bool DeleteFollowUser(string id) { return Post(string.Format("http://h.hatena.ne.jp/api/friendships/destroy/{0}.xml", Uri.EscapeUriString(id))); } #endregion #endregion #region キーワード関係 #region GET /// <summary> /// Hot Keywords のリストを返します。 /// </summary> /// <returns></returns> public XDocument GetHotKeyword() { return Get("http://h.hatena.ne.jp/api/keywords/hot.xml"); } /// <summary> /// Keywords のリストを返します。 /// </summary> /// <returns></returns> public XDocument GetKeywordList() { return Get("http://h.hatena.ne.jp/api/keywords/list.xml"); } /// <summary> /// Keywords のリストを返します。 /// </summary> /// <param name="page"></param> /// <returns></returns> public XDocument GetKeywordList(int page) { return Get("http://h.hatena.ne.jp/api/keywords/list.xml",new KeyValuePair<string, object>("page",page)); } /// <summary> /// キーワードの情報を表示します。 /// </summary> /// <param name="id"></param> /// <returns></returns> public XDocument GetKeywordShow(string keyword) { return Get(string.Format("http://h.hatena.ne.jp/api/keywords/show/{0}.xml" , Uri.EscapeUriString(keyword))); } #endregion #region POST /// <summary> /// 指定キーワードをお気に入りに追加します。 /// /// (旧:キーワードをフォローします。) /// </summary> /// <param name="id"></param> /// <returns></returns> public bool AddFollowKeyword(string keyword) { return Post(string.Format("http://h.hatena.ne.jp/api/keywords/create/{0}.xml" , Uri.EscapeUriString(keyword))); } /// <summary> /// 指定キーワードをお気に入りから解除します。 /// /// (旧:キーワードのフォローをやめます。) /// </summary> /// <param name="id"></param> /// <returns></returns> public bool DeleteFollowKeyword(string keyword) { return Post(string.Format("http://h.hatena.ne.jp/api/keywords/destroy/{0}.xml" , Uri.EscapeUriString(keyword))); } /// <summary> /// 関連キーワードを設定します。word1 の情報を返します。 /// </summary> /// <param name="word1"></param> /// <param name="word2"></param> /// <returns></returns> public bool CreateKeywordsRelation(string word1, string word2) { var parameters = new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("word1",word1) ,new KeyValuePair<string, object>("word2",word2)}; return Post("http://h.hatena.ne.jp/api/keywords/relation/create.xml", parameters); } /// <summary> /// 関連キーワードを解除します。word1 の情報を返します。 /// なお、関連キーワードの設定の削除は自分が設定したものに限られます。 /// </summary> /// <param name="word1"></param> /// <param name="word2"></param> /// <returns></returns> public bool DestroyKeywordsRelation(string word1, string word2) { var parameters = new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("word1",word1) ,new KeyValuePair<string, object>("word2",word2)}; return Post("http://h.hatena.ne.jp/api/keywords/relation/destroy.xml", parameters); } #endregion #endregion } }
そのままの利用および改造改変はご自由にどうぞ。
このサンプルを元に、いい感じのHaikuクライアントを作ってもらえたら幸いです。