Java开发者的Scala指南: Scala+Twitter=Scitter

欢迎进入Java社区论坛,与200万技术人员互动交流 >>进入

  API 设计

  在深入了解 Scala/Twitter 库的 API 设计之前(根据同事 ThoughtWorker Neal Ford 的建议,我将它称作 “Scitter”),需要明确一些需求。

  首先,Scitter 显然会对网络访问有一些依赖 ― 并且可扩展到 Twitter 服务器 ― 这会使测试变得非常困难。

  其次,我们需要解析(和测试)Twitter 发回的各种格式。

  第三,我们希望隐藏 API 内部各种格式之间的差异,以便客户机不需要担心已记录的 Twitter 消息格式,但是可以仅使用标准类。

  最后,由于 Twitter 依赖 “通过身份验证的用户” 才能使用大量 API,因此 Scitter 库需要适应 “验证” 和 “未验证” API 之间的差异,而不会让事情变得过于复杂。

  网络访问需要一些形式的 HTTP 通信,以便联系 Twitter 服务器。虽然我们可以使用 Java 库本身(特别是 URL 类及其同胞),但由于 Twitter API 需要大量请求和响应主体连接,因此可以更加轻松地使用不同的 HTTP API,特别是 Apache Commons HttpClient 库。为了更便于测试客户机 API,实际通信将隐藏在一些 API 内部的 Scitter 库中,以便能够更加轻松地切换到另一个 HTTP 库(其必要性不太容易想到),并能模拟实际网络通信以简化测试(其作用很容易想到)。

  结果,第一个测试是 Scala 化 HttpClient 调用,以确保基本通信模式就位;注意,由于 HttpClient 依赖另外两个 Apache 库(Commons Logging 和 Commons Codec),因此还需要在运行时提供这些库;对于那些希望开发相似种类代码的读者,确保类路径中包括所有三个库。

  由于最易于使用的 Twitter API 是测试 API

  因此在请求格式中返回 “ok”,并附带 200 OK HTTP 状态码。

  我们将使用它作为 Scitter 测试中的保留条款。它位于 URL http://twitter.com/help/test.format(其中,“format” 为 “xml” 或 “json”;至于目前,我们将选择使用 “xml”),并且仅有的支持 HTTP 方法是 GET。HttpClient 代码简明易懂,如清单 3 所示:

  清单 3. Twitter PING!

packagecom.tedneward.scitter.test   {   classExplorationTests   {   //…   importorg.apache.commons.httpclient._,methods._,params._,cookie._   @TestdefcallTwitterTest=   {   valtestURL=”http://twitter.com/help/test.xml”   //HttpClientAPI101   valclient=newHttpClient()   valmethod=newGetMethod(testURL)   method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,   newDefaultHttpMethodRetryHandler(3,false))   client.executeMethod(method)   valstatusLine=method.getStatusLine()   assertEquals(statusLine.getStatusCode(),200)   assertEquals(statusLine.getReasonPhrase(),”OK”)   }   }   }

  此代码中最重要的一部分是 HttpClient 样板 ― 感兴趣的读者应该查阅 HttpClient API 文档了解详细信息。假设连接到公共 Internet 的网络可用(并且 Twitter 并未修改其公共 API),那么该测试应该能顺利通过。

  鉴于此,我们详细分析 Scitter 客户机的第一部分。这意味着我们需要解决一个设计问题:如何构建 Scitter 客户机来处理经过验证和未经过验证的调用。目前,我将采用典型的 Scala 方式,假定验证是 “按对象” 执行的,因此将需要验证的调用放在类定义中,并在未验证的调用放在对象定义中:

  清单 4. Scitter.test

 packagecom.tedneward.scitter   {   /**   *Objectforconsuming”non-specific”Twitterfeeds,suchasthepublictimeline.   *Usethistodonon-authenticatedrequestsofTwitterfeeds.   */   objectScitter   {   importorg.apache.commons.httpclient._,methods._,params._,cookie._   /**   *Pingtheservertoseeifit’supandrunning.   *   *Twitterdocssay:   *test   *Returnsthestring”ok”intherequestedformatwitha200OKHTTPstatuscode.   *URL:http://twitter.com/help/test.format   *Formats:xml,json   *Method(s):GET   */   deftest:Boolean=   {   valclient=newHttpClient()   valmethod=newGetMethod(“http://twitter.com/help/test.xml”)   method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,   newDefaultHttpMethodRetryHandler(3,false))   client.executeMethod(method)   valstatusLine=method.getStatusLine()   statusLine.getStatusCode()==200   }   }   /**   *Classforconsuming”authenticateduser”TwitterAPIs.Eachinstanceis   *thus”tied”toaparticularauthenticateduseronTwitter,andwill   *behaveaccordingly(accordingtotheTwitterAPIdocumentation).   */   classScitter(username:String,password:String)   {   }   }

  目前,我们将网络抽象放在一边 ― 稍后,当离线测试变得更加重要时再添加它。当我们更好地理解如何使用 HttpClient 类时,这还将帮助避免 “过度抽象” 网络通信。

  由于已经明确区分了验证和未验证 Twitter 客户机,因此我们将快速创建一个经过验证的方法。看上去 Twitter 提供了一个可验证用户登录凭证的 API。再次,HttpClient 代码将类似于之前的代码,除了将用户名和密码传递到 Twitter API 中之外。

  这引出了 Twitter 如何验证用户的概念。快速查看 Twitter API 页面后,可以发现 Twitter 使用的是一种 Stock HTTP 验证方法,这与任何经过验证的资源在 HTTP 中的方法相同。这意味着 HttpClient 代码必须提供用户名和密码作为 HTTP 请求的一部分,而不是作为 POST 的主体,如清单 5 所示:

  清单 5. 您好 Twitter,是我!

packagecom.tedneward.scitter.test   {   classExplorationTests   {   deftestUser=”TwitterUser”   deftestPassword=”TwitterPassword”   @TestdefverifyCreds=   {   valclient=newHttpClient()   valverifyCredsURL=”http://twitter.com/account/verify_credentials.xml”   valmethod=newGetMethod(verifyCredsURL)   method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,   newDefaultHttpMethodRetryHandler(3,false))   client.getParams().setAuthenticationPreemptive(true)   valdefaultcreds=newUsernamePasswordCredentials(testUser,testPassword)   client.getState().setCredentials(newAuthScope(“twitter.com”,80,   AuthScope.ANY_REALM),defaultcreds)   client.executeMethod(method)   valstatusLine=method.getStatusLine()   assertEquals(200,statusLine.getStatusCode())   assertEquals(“OK”,statusLine.getReasonPhrase())   }   }   }

  注意,要让此测试顺利通信,用户名和密码字段将需要输入 Twitter 能接收的内容 ― 我在开发时使用了自己的 Twitter 用户名和密码,但显然您需要使用自己设定的用户名和密码。注册新的 Twitter 帐户相当简单,因此我假定您已经拥有一个帐户,或者知道如何注册(很好。我会等待完成此任务)。

  完成后,使用用户名和密码构造函数参数将它映射到 Scitter 类非常简单,如清单 6 所示:

  清单 6. Scitter.verifyCredentials

packagecom.tedneward.scitter   {   importorg.apache.commons.httpclient._,auth._,methods._,params._   //…   /**   *Classforconsuming”authenticateduser”TwitterAPIs.Eachinstanceis   *thus”tied”toaparticularauthenticateduseronTwitter,andwill   *behaveaccordingly(accordingtotheTwitterAPIdocumentation).   */   classScitter(username:String,password:String)   {   /**   *VerifytheusercredentialsagainstTwitter.   *   *Twitterdocssay:   *verify_credentials   *ReturnsanHTTP200OKresponsecodeandarepresentationofthe   *requestinguserifauthenticationwassuccessful;returnsa401status   *codeandanerrormessageifnot.Usethismethodtotestifsupplied   *usercredentialsarevalid.   *URL:http://twitter.com/account/verify_credentials.format   *Formats:xml,json   *Method(s):GET   */   defverifyCredentials:Boolean=   {   valclient=newHttpClient()   valmethod=newGetMethod(“http://twitter.com/help/test.xml”)   method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,   newDefaultHttpMethodRetryHandler(3,false))   client.getParams().setAuthenticationPreemptive(true)   valcreds=newUsernamePasswordCredentials(username,password)   client.getState().setCredentials(   newAuthScope(“twitter.com”,80,AuthScope.ANY_REALM),creds)   client.executeMethod(method)   valstatusLine=method.getStatusLine()   statusLine.getStatusCode()==200   }   }   }

[1][2][3][4]

愚公因此敢移山,矢志不渝是前行,握紧拳头勇登攀,

Java开发者的Scala指南: Scala+Twitter=Scitter

相关文章:

你感兴趣的文章:

标签云: