scala-news-reader

rss/atom news reader in scala

git clone https://9o.is/git/scala-news-reader.git

RestClient.scala

(2715B)


      1 package com.joereader.lib.api.rest
      2 
      3 import oauth._
      4 import dispatch._, Defaults._
      5 
      6 import net.liftweb._
      7 import json._, JsonAST._
      8 import common._
      9 
     10 import com.ning.http.client._
     11 import java.net.URL
     12 
     13 /**
     14  * Client that makes rest api calls.
     15  */
     16 trait RestClient extends Logger {
     17   implicit val formats = DefaultFormats + new URLSerializer
     18 
     19   /* Identification of this rest client. */
     20   protected def name: String
     21 
     22   /* Oauth Builder */
     23   protected def token: OauthAccessToken
     24 
     25   /* The server's domain. */
     26   protected def server: RequestBuilder
     27 
     28   /* Token as request parameter. */
     29   protected def tokenParam(token: AccessToken): Map[String, String]
     30 
     31   /* Build the request with the access token. */
     32   def buildTokenRequest(req: RequestBuilder): Box[RequestBuilder]
     33 
     34   /* Builds a request with access token. */
     35   protected def authReq(path: List[String]): Box[RequestBuilder] =
     36     buildTokenRequest(server / path.mkString("/"))
     37     
     38   /* Builds a request with access token and other query params. */
     39   protected def authReq(path: List[String], params: Map[String, String]): Box[RequestBuilder] =
     40     buildTokenRequest(server / path.mkString("/") <<? params)
     41 
     42   /* Builds a request with access token given a full url. */
     43   protected def authReq(u: URL): Box[RequestBuilder] =
     44     buildTokenRequest(url(u.toString))
     45 
     46   /* Make a GET request to server. */
     47   protected def getJson[T](req: Box[RequestBuilder]): Future[Either[String, JValue]] =
     48     req match {
     49       case Failure(msg, _, _) =>
     50         error(msg)
     51         Future(Left(msg))
     52       case Empty =>
     53         val msg = s"Empty $name request"
     54         error(msg)
     55         Future(Left(msg))
     56       case Full(req) =>
     57         catchThrowable {
     58           getJson(req)
     59         }
     60     }
     61 
     62   /* Extract json response to a typed object. */
     63   protected def extract[T: Manifest](res: Future[Either[String, JValue]]): Future[Either[String, T]] =
     64     for (jvalue <- res.right) 
     65       yield jvalue.extract[T]
     66 
     67   private def getJson(req: RequestBuilder): Future[Either[Throwable, JValue]] = {
     68     val res = Http(req.GET OK as.String).either
     69     for (json <- res.right) 
     70       yield parse(json)
     71   }
     72 
     73   /* Catches exception if it fails to get rsponse from the server. */
     74   private def catchThrowable(res: Future[Either[Throwable, JValue]]): Future[Either[String, JValue]] = {
     75     for (e <- res.left) yield {
     76       val msg = s"Can't connect to $name: \n ${e.getMessage}"
     77       error(msg)
     78       msg
     79     }
     80   }
     81 
     82   /* Extracts the access tokn. */
     83   protected def extractToken =
     84     for {
     85       token <- token.is ?~ s"$name access token missing"
     86     } yield tokenParam(token)
     87 
     88   /* Removes the current access token. */
     89   def resetToken {
     90     token(Empty)
     91     info(s"$name has been reset")
     92   }
     93 }