Skip to content

Commit

Permalink
Make constructQuery typesafe (closes #62)
Browse files Browse the repository at this point in the history
  • Loading branch information
asoltysik authored and BenFradet committed Jul 17, 2018
1 parent 98a2acb commit 784c0f9
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 35 deletions.
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ lazy val root = project
Dependencies.Libraries.jodaTime,
Dependencies.Libraries.jodaConvert,
Dependencies.Libraries.collUtil,
Dependencies.Libraries.circeGeneric,
Dependencies.Libraries.circeParser,
Dependencies.Libraries.hammockCore,
Dependencies.Libraries.hammockCirce,
Dependencies.Libraries.circeLiteral,
Dependencies.Libraries.specs2,
Dependencies.Libraries.specs2Mock,
Dependencies.Libraries.specsScalaCheck
Expand Down
6 changes: 3 additions & 3 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ object Dependencies {
val jodaTime = "2.10"
val jodaConvert = "2.1"
// Scala
val circe = "0.9.3"
val collUtil = "6.39.0"
val hammock = "0.8.5"
val circe = "0.9.3"
// Tests
val specs2 = "3.9.4"
}
Expand All @@ -37,11 +37,11 @@ object Dependencies {
val jodaTime = "joda-time" % "joda-time" % V.jodaTime
val jodaConvert = "org.joda" % "joda-convert" % V.jodaConvert
// Scala
val circeGeneric = "io.circe" %% "circe-generic" % V.circe
val circeParser = "io.circe" %% "circe-parser" % V.circe
val collUtil = "com.twitter" %% "util-collection" % V.collUtil
val hammockCore = "com.pepegar" %% "hammock-core" % V.hammock
val hammockCirce = "com.pepegar" %% "hammock-circe" % V.hammock
// Tests
val circeLiteral = "io.circe" %% "circe-literal" % V.circe % "test"
val specs2 = "org.specs2" %% "specs2-core" % V.specs2 % "test"
val specs2Mock = "org.specs2" %% "specs2-mock" % V.specs2 % "test"
val specsScalaCheck = "org.specs2" %% "specs2-scalacheck" % V.specs2 % "test"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,16 @@ import Responses._
import Requests._

/**
* Base client trait with defined client methods such as `historyById`, `historyByName`
* Base client trait with defines client methods such as `historyById`, `forecastByName`
* common for subclasses
*
* @tparam F response wrapper for `Client` subclass, such as cats `IO`
* all `receive` logic should be wrapped in it
* @tparam F effect type
*/
trait Client[F[_]] {

/**
* Main client logic for Request => Response function,
* where Response is wrappeed in tparam `F`
* where Response is wrapped in tparam `F`
*
* @param owmRequest request built by client method
* @tparam W type of weather response to extract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,16 @@ case class OwmAsyncClient[F[_]: Sync](appId: String, apiHost: String = "api.open

def receive[W <: OwmResponse: Decoder](request: OwmRequest): F[Either[WeatherError, W]] = {

val uri = request.constructQuery(appId)
val scheme = if (ssl) "https://" else "http://"
val url = scheme + apiHost + uri
val scheme = if (ssl) "https" else "http"
val authority = Uri.Authority(None, Uri.Host.Other(apiHost), None)
val baseUri = Uri(Some(scheme), Some(authority))

Uri
.fromString(url)
.leftMap(InternalError)
.traverse { uri =>
Hammock
.request(Method.GET, uri, Map())
.map(uri => processResponse(uri))
.exec[F]
}
.map(x => x.joinRight)
val uri = request.constructQuery(baseUri, appId)

Hammock
.request(Method.GET, uri, Map())
.map(uri => processResponse(uri))
.exec[F]
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import WeatherCache.{CacheKey, Position}

/**
* Blocking OpenWeatherMap client with history (only) cache
* Uses AsyncOwmClient under the hood, have same method set, but also uses timeouts
* Uses AsyncOwmClient under the hood, has the same method set, but also uses timeouts
*
* WARNING. This client uses pro.openweathermap.org for data access,
* It will not work with free OWM licenses.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,28 @@
*/
package com.snowplowanalytics.weather.providers.openweather

import cats.data.NonEmptyList
import hammock.Uri

private[weather] object Requests {

sealed trait WeatherRequest {
def constructQuery(appId: String): String
def constructQuery(baseUri: Uri, apiKey: String): Uri
}

sealed trait OwmRequest extends WeatherRequest {
val endpoint: Option[String]
val resource: String
val parameters: Map[String, String]

/**
* Construct URI for specific type of request and all other data
*
* @param appId API key
* @return URI string ready to be sent
*/
def constructQuery(appId: String): String = {
val end = endpoint.map(e => s"$e/$resource").getOrElse(s"$resource")
val params = parameters ++ Map("appid" -> appId)
val queryString = params.map { case (a, b) => s"$a=$b" }.mkString("&")
s"/data/2.5/$end?$queryString"
def constructQuery(baseUri: Uri, apiKey: String): Uri = {
val versionedBaseUri = baseUri / "data" / "2.5"
val uriWithPath = endpoint.map(e => versionedBaseUri / e / resource).getOrElse(versionedBaseUri / resource)
val params = NonEmptyList.of("appid" -> apiKey) ++ parameters.toList

uriWithPath ? params
}

}

final case class OwmHistoryRequest(resource: String, parameters: Map[String, String]) extends OwmRequest {
Expand Down

0 comments on commit 784c0f9

Please sign in to comment.