Scitter 庫經歷四階段:
User、Status 等 Case ClassOptionalParam 密封層級結構Scitter Object:匿名訪問與通信基礎Scitter Class:認證用戶操作本文實現缺失的寫操作:update、show、destroy,以及輔助的 endSession、rateLimitStatus。
原 execute 僅支持 GET。重構引入 Map[String,String] 區分 POST/GET:
private[scitter] def execute(url: String, dataMap: Map[String,String],
username: String, password: String): (Int, String) = {
val method = if (dataMap.isEmpty) new GetMethod(url)
else {
val m = new PostMethod(url)
val pairs = dataMap.map { case (k,v) => new NameValuePair(k,v) }.toArray
m.setRequestBody(pairs)
m
}
// 認證、執行、返回狀態碼與響應體...
}
設計決策:空 Map 視為 GET,非空視為 POST。未來若需 PUT/DELETE,可引入 HTTP 方法參數進一步重構。
endSessiondef endSession: Boolean = {
val (code, _) = Scitter.execute(
"https://twitter.com/account/end_session.xml",
Map("" -> ""), // 觸發 POST
username, password)
code == 200
}
rateLimitStatus (雙版本)
// 匿名版本 (Scitter Object)
def rateLimitStatus: Option[RateLimits] = {
val (code, body) = Scitter.execute("https://twitter.com/account/rate_limit_status.xml")
if (code == 200) Some(RateLimits.fromXml(XML.loadString(body))) else None
}
// 認證版本 (Scitter Class)
def rateLimitStatus: Option[RateLimits] = {
val (code, body) = Scitter.execute(url, username, password)
// 同樣解析邏輯
}
update — 處理可變參數與不可變 Mapdef update(message: String, options: OptionalParam*): Option[Status] = {
// 遞歸將 OptionalParam 列表轉為 Map
def optionsToMap(opts: List[OptionalParam]): Map[String,String] = opts match {
case hd :: tl => hd match {
case InReplyToStatusId(id) => Map("in_reply_to_status_id" -> id.toString) ++ optionsToMap(tl)
case _ => optionsToMap(tl)
}
case Nil => Map()
}
val params = Map("status" -> message) ++ optionsToMap(options.toList)
val (code, body) = Scitter.execute("https://twitter.com/statuses/update.xml", params, username, password)
if (code == 200) Some(Status.fromXml(XML.loadString(body))) else None
}
Scala 不可變集合技巧:通過遞歸 ++ 合併 Map,避免可變狀態,符合函數式風格。
show — 模式匹配優雅處理響應def show(id: Long): Option[Status] = {
Scitter.execute(s"https://twitter.com/statuses/show/$id.xml", username, password) match {
case (200, body) => Some(Status.fromXml(XML.loadString(body)))
case _ => None
}
}
模式匹配版本比 if/else 更清晰,易於擴展處理特定錯誤碼(如 400 Bad Request)。
destroy — 重載支持 ID 類型def destroy(id: Long): Option[Status] = {
val params = Map("id" -> id.toString)
val (code, body) = Scitter.execute(s"https://twitter.com/statuses/destroy/$id.xml", params, username, password)
if (code == 200) Some(Status.fromXml(XML.loadString(body))) else None
}
def destroy(id: Id): Option[Status] = destroy(id.id.toLong) // 適配領域模型 Id 類
Scitter 從純 GET 讀操作擴展到完整 CRUD,展示了 Scala Case Class、模式匹配、高階函數、XML 處理在 REST 客戶端開發中的表達力。雖非生產級成熟庫,但已具備構建文本模式 Twitter 客戶端的能力。鼓勵開發者基於此代碼庫或自行設計,探索 Scala 在社交 API 集成中的更多可能。