Skip to content

Commit

Permalink
Add logging, d timing, fix extractions, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
nfolkert-foursquare committed Sep 8, 2011
1 parent f045756 commit 21d0adf
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 22 deletions.
52 changes: 40 additions & 12 deletions src/main/scala/org/scalafoursquare/call/Caller.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ case class ParseFailed(msg: String, cause: Throwable, raw: String) extends Throw
}

class RawRequest(val app: App, val endpoint: String, val params: List[(String, String)] = Nil, val method: String = "GET", val postData: Option[PostData]=None) {
def getRaw: String = app.caller.makeCall(this, app.token, method, postData)
lazy val (getRaw, duration) = app.caller.makeCall(this, app.token, method, postData)
def getJson: JObject = JsonParser.parse(getRaw).asInstanceOf[JObject]
}

Expand All @@ -76,10 +76,11 @@ class PostDataRequest[T](app: App, endpoint: String, params: List[(String, Strin

class RawMultiRequest(app: App, reqA: Option[RawRequest], reqB: Option[RawRequest], reqC: Option[RawRequest],
reqD: Option[RawRequest], reqE: Option[RawRequest], val method: String="GET") {
def getRaw: String = {
lazy val (getRaw, duration): (String, Long) = {
val subreqs = List(reqA, reqB, reqC, reqD, reqE).flatten
val param = subreqs.map(r=>r.endpoint + (if (r.params.isEmpty) "" else "?" + r.params.map(p=>(p._1 + "=" + urlEncode(p._2))).join("&"))).join(",")
new RawRequest(app, "/multi", List(("requests", param)), method, None).getRaw
val rawReq = new RawRequest(app, "/multi", List(("requests", param)), method, None)
(rawReq.getRaw, rawReq.duration)
}
def getJson: JObject = JsonParser.parse(getRaw).asInstanceOf[JObject]
}
Expand All @@ -91,9 +92,10 @@ class MultiRequest[A,B,C,D,E](app: App, reqA: Option[Request[A]], reqB: Option[R
}

class RawMultiRequestList(val app: App, val subreqs: List[RawRequest], val method: String="GET") {
def getRaw: String = {
lazy val (getRaw, duration): (String, Long) = {
val param = subreqs.map(r=>r.endpoint + (if (r.params.isEmpty) "" else "?" + r.params.map(p=>(p._1 + "=" + urlEncode(p._2))).join("&"))).join(",")
new RawRequest(app, "/multi", List(("requests", param)), method, None).getRaw
val rawReq = new RawRequest(app, "/multi", List(("requests", param)), method, None)
(rawReq.getRaw, rawReq.duration)
}
def getJson: JObject = JsonParser.parse(getRaw).asInstanceOf[JObject]
}
Expand All @@ -103,15 +105,17 @@ class MultiRequestList[A](app: App, subreqs: List[Request[A]])(implicit mf: Mani
}

abstract class Caller {
def makeCall(req: RawRequest, token: Option[String]=None, method: String="GET", postData: Option[PostData]=None): String
def makeCall(req: RawRequest, token: Option[String]=None, method: String="GET", postData: Option[PostData]=None): (String, Long)
}

case class HttpCaller(clientId: String, clientSecret: String,
urlRoot: String = "https://api.foursquare.com/v2",
version: String = "20110823",
connectTimeout: Int=1000, readTimeout: Int=2000
) extends Caller {
def makeCall(req: RawRequest, token: Option[String]=None, method: String="GET", postData: Option[PostData]=None): String = {
import App.logger

def makeCall(req: RawRequest, token: Option[String]=None, method: String="GET", postData: Option[PostData]=None): (String, Long) = {
val fullParams: List[(String, String)] = ("v", version) ::
(token.map(t => List(("oauth_token", t))).getOrElse(List(("client_id", clientId), ("client_secret", clientSecret)))) ++
req.params.toList
Expand All @@ -124,17 +128,18 @@ case class HttpCaller(clientId: String, clientSecret: String,
case _ => throw new Exception("Don't understand " + method)
}).options(HttpOptions.connTimeout(connectTimeout), HttpOptions.readTimeout(readTimeout)).params(fullParams)

// println(http.getUrl.toString)

val startTime = System.currentTimeMillis
val result = try {
http.asString
} catch {
case e: HttpException => {e.body}
}

// println(result)
val duration = System.currentTimeMillis - startTime
logger.call(url + " " + method, duration)
logger.debug(result)

result
(result, duration)
}
}

Expand Down Expand Up @@ -387,13 +392,36 @@ object App {
None
})
}

trait CallLogger {
def call(msg: => String, timeMillis: Long): Unit

def trace(msg: => String): Unit
def debug(msg: => String): Unit
def info(msg: => String): Unit
def warn(msg: => String): Unit
def error(msg: => String): Unit
}

class DefaultCallLogger extends CallLogger {
def call(msg: => String, timeMillis: Long) {}
def trace(msg: => String) {}
def debug(msg: => String) {}
def info(msg: => String) {}
def warn(msg: => String) {}
def error(msg: => String) {}
}

object NoopCallLogger extends DefaultCallLogger

var logger: CallLogger = NoopCallLogger
}

case class EndpointInterface(endpoint: String, requestType: String,
requiredQueryParams: List[(String, String)],
optionalQueryParams: List[(String, String)],
returnTree: JValue) {
def pretty = {
def pretty {
println("Endpoint: " + endpoint + " " + requestType)

if (!requiredQueryParams.isEmpty) {
Expand Down
11 changes: 8 additions & 3 deletions src/main/scala/org/scalafoursquare/response/Response.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ case class VenueTodos(count: Int, items: List[TodoForVenue])
case class VenueHereNowCompact(count: Int)

case class VenueLists(count: Int, items: List[String])
case class VenueListed(count: Int, items: Option[List[String]])

trait VenueKernel {
def id: String
Expand Down Expand Up @@ -51,12 +52,13 @@ case class VenueDetailExtended(
specials: List[Special],
specialsNearby: List[Special],
shortUrl: String,
canonicalUrl: String,
timeZone: String,
beenHere: Option[VenueBeenHere],
photos: Option[VenuePhotos],
description: Option[String],
events: Option[List[CompactEvent]],
lists: Option[VenueLists],
listed: Option[VenueListed],
todos: Option[VenueTodos]
)

Expand All @@ -81,12 +83,13 @@ case class VenueDetail(
def specials = extended.specials
def specialsNearby = extended.specialsNearby
def shortUrl = extended.shortUrl
def canonicalUrl = extended.canonicalUrl
def timeZone = extended.timeZone
def beenHere = extended.beenHere
def photos = extended.photos
def description = extended.description
def events = extended.events
def lists = extended.lists
def listed = extended.listed
def todos = extended.todos

}
Expand Down Expand Up @@ -373,9 +376,11 @@ case class DoneDetailGroup(`type`: String, name: String, count: Option[Int], ite
case class TodoDetail(count: Int, groups: List[TodoDetailGroup])
case class DoneDetail(count: Int, groups: List[DoneDetailGroup])

case class TipListed(count: Int, items: Option[List[String]])
case class TipDetail(id: String, createdAt: Long, text: String, url: Option[String], status: Option[String],
photo: Option[PhotoCore], photourl: Option[String], venue: Option[VenueCompact],
user: Option[UserCompact], todo: TodoDetail, done: DoneDetail) extends TipKernel
user: Option[UserCompact], todo: TodoDetail, done: DoneDetail,
listed: Option[TipListed]) extends TipKernel
case class TipDetailResponse(tip: TipDetail)

case class AddTipResponse(tip: TipForList)
Expand Down
8 changes: 5 additions & 3 deletions src/test/scala/org/scalafoursquare/Components.scala
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,15 @@ object Components {
def genericVenueDetail1 = venueCore1 ~ ("createdAt" -> 1000) ~ ("hereNow" -> venueHereNow1) ~
("mayor" -> venueMayor1) ~ ("tips" -> venueTipData1) ~ ("tags" -> List("tag1", "tag2")) ~
("specials" -> List(venueSpecial1, venueSpecial2)) ~ ("specialsNearby" -> List(specialNearby1, specialNearby2)) ~
("shortUrl" -> "venueShortUrl") ~ ("timeZone" -> "venueTimeZone") ~ ("beenHere" -> ("count" -> 5)) ~
("shortUrl" -> "venueShortUrl") ~ ("canonicalUrl" -> "venueCanonicalUrl") ~
("timeZone" -> "venueTimeZone") ~ ("beenHere" -> ("count" -> 5)) ~
("photos" -> venuePhotosData1) ~ ("description" -> "venueDescription") ~
("events" -> List(compactEvent1, compactEvent2)) ~ ("lists" -> countList(2, List("List1", "List2")))
("events" -> List(compactEvent1, compactEvent2)) ~ ("listed" -> countList(2, List[JValue]()))
def genericVenueDetail2 = venueCore2 ~ ("createdAt" -> 1000) ~ ("hereNow" -> venueHereNow2) ~
("mayor" -> venueMayor2) ~ ("tips" -> venueTipData2) ~ ("tags" -> List("tag1", "tag2")) ~
("specials" -> List[JValue]()) ~ ("specialsNearby" -> List[JValue]()) ~
("shortUrl" -> "venueShortUrl") ~ ("timeZone" -> "venueTimeZone")
("shortUrl" -> "venueShortUrl") ~ ("canonicalUrl" -> "venueCanonicalUrl") ~
("timeZone" -> "venueTimeZone")

def venueDetail1 = genericVenueDetail1 ~ ("todos" -> countList(2, List(todoForVenue1, todoForVenue2)))
def venueDetail2 = genericVenueDetail2 ~ ("todos" -> countList(0, List[JValue]()))
Expand Down
4 changes: 3 additions & 1 deletion src/test/scala/org/scalafoursquare/ReflectionTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ class ReflectionTest extends SpecsMatchers {
val userless = App.deriveInterface(userlessApp)
val auth = App.deriveInterface(authApp)


/*
// Uncomment to see structure
println("Userless App:")
userless.map(_.pretty)
println("Authenticated App:")
auth.map(_.pretty)
*/

}

Expand Down
9 changes: 6 additions & 3 deletions src/test/scala/org/scalafoursquare/TestCaller.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ import org.scalafoursquare.call.{Caller, RawRequest, PostData, PhotoData}
import net.liftweb.util.Helpers._

object TestCaller extends Caller {
def makeCall(req: RawRequest, token: Option[String], method: String="GET", postData: Option[PostData]=None): String = {
def makeCall(req: RawRequest, token: Option[String], method: String="GET", postData: Option[PostData]=None): (String, Long) = {
def m(jsonObj: String) = """{"meta":{"code":200},"response":""" + jsonObj + "}"
def unparse(reqStr: String): RawRequest = {
new RawRequest(req.app, reqStr) // TODO: unparse parameters from endpoint
}

req.endpoint match {
val ret = req.endpoint match {
case "/multi" => {
req.params.find(_._1 == "requests").map(reqEntry => {
val reqs = reqEntry._2
val reqList = reqs.split(",").toList
m("{\"responses\":[" + reqList.map(r => makeCall(unparse(r), req.app.token)).join(",") + "]}")
m("{\"responses\":[" + reqList.map(r => makeCall(unparse(r), req.app.token)._1).join(",") + "]}")
}).getOrElse("""{"meta":{"code":404, "errorType":"other", "errorDetail":"Endpoint not found"},"response":{}}""")
}
case "/venues/categories" => {
Expand Down Expand Up @@ -65,6 +65,7 @@ object TestCaller extends Caller {
"specials":[],
"specialsNearby":[],
"shortUrl":"fakeUrl",
"canonicalUrl":"fakeUrl",
"timeZone":"America/New_York",
"beenHere":{"count":40},
"photos":{"count":100,"groups":[
Expand All @@ -84,6 +85,8 @@ object TestCaller extends Caller {
case "/venues/missingId" => """{"meta":{"code":400,"errorType":"param_error","errorDetail":"Value missingId is invalid for venue id"},"response":{}}"""
case _ => """{"meta":{"code":404, "errorType":"other", "errorDetail":"Endpoint not found"},"response":{}}"""
}

(ret, 0L)
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/test/scala/org/scalafoursquare/UserlessEndpointTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ object EndpointTest {
try {
val raw = req.getRaw
println(raw)
val duration = req.duration
println("Took " + duration + " ms")

val json = req.getJson

Expand Down

0 comments on commit 21d0adf

Please sign in to comment.