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 }