New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cats-effect module #155
cats-effect module #155
Changes from 6 commits
2b04152
e1a52d6
2d086a3
99c963b
5eec899
db0780c
d222b52
8226339
c3690d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* Copyright 2016-2017 47 Degrees, LLC. <http://www.47deg.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package github4s.cats.effect | ||
|
||
import cats.effect.IO | ||
import cats.Eval.later | ||
import fr.hmil.roshttp.response.SimpleHttpResponse | ||
import github4s.{HttpRequestBuilder, HttpRequestBuilderExtension, HttpRequestBuilderExtensionJS} | ||
import github4s.GithubResponses.GHResponse | ||
import io.circe.Decoder | ||
|
||
import scala.concurrent.Future | ||
|
||
trait IOHttpRequestBuilderExtensionJS extends HttpRequestBuilderExtensionJS { | ||
|
||
import monix.execution.Scheduler.Implicits.global | ||
|
||
implicit def extensionIOJS: HttpRequestBuilderExtension[SimpleHttpResponse, IO] = | ||
new HttpRequestBuilderExtension[SimpleHttpResponse, IO] { | ||
|
||
def run[A](rb: HttpRequestBuilder[SimpleHttpResponse, IO])( | ||
implicit D: Decoder[A]): IO[GHResponse[A]] = | ||
runMapWrapper[A](rb, decodeEntity[A]) | ||
|
||
def runEmpty(rb: HttpRequestBuilder[SimpleHttpResponse, IO]): IO[GHResponse[Unit]] = | ||
runMapWrapper[Unit](rb, emptyResponse) | ||
|
||
private[this] def runMapWrapper[A]( | ||
rb: HttpRequestBuilder[SimpleHttpResponse, IO], | ||
mapResponse: SimpleHttpResponse => GHResponse[A]): IO[GHResponse[A]] = | ||
IO.fromFuture(later(runMap[A, IO](rb, mapResponse))) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
* Copyright 2016-2017 47 Degrees, LLC. <http://www.47deg.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package github4s.cats.effect.js | ||
|
||
object Implicits extends ImplicitsJS |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Copyright 2016-2017 47 Degrees, LLC. <http://www.47deg.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package github4s.cats.effect.js | ||
|
||
import cats.effect.IO | ||
import fr.hmil.roshttp.response.SimpleHttpResponse | ||
import github4s.HttpRequestBuilderExtensionJS | ||
import github4s.cats.effect.{IOCaptureInstance, IOHttpRequestBuilderExtensionJS} | ||
import github4s.free.interpreters.Interpreters | ||
import github4s.implicits._ | ||
|
||
trait ImplicitsJS extends IOHttpRequestBuilderExtensionJS with IOCaptureInstance { | ||
implicit val intInstanceIORosHttp = | ||
new Interpreters[IO, SimpleHttpResponse] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* Copyright 2016-2017 47 Degrees, LLC. <http://www.47deg.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package github4s.cats.effect.js | ||
|
||
import cats.effect.IO | ||
import github4s.Github | ||
import github4s.Github._ | ||
import github4s.cats.effect.js.Implicits._ | ||
import org.scalatest.{Assertion, AsyncFunSuite, Matchers} | ||
import fr.hmil.roshttp.response.SimpleHttpResponse | ||
import github4s.GithubResponses.GHResponse | ||
import github4s.free.domain.User | ||
import org.scalactic.source.Position | ||
|
||
import scala.concurrent.{ExecutionContext, ExecutionContextExecutor, Future, Promise} | ||
import scala.util.Try | ||
|
||
class CatsEffectJSSpec extends AsyncFunSuite with Matchers { | ||
|
||
implicit override def executionContext: ExecutionContextExecutor = ExecutionContext.global | ||
|
||
def testEffectOnRunAsync[A](source: IO[GHResponse[A]], f: GHResponse[A] => Assertion)( | ||
implicit pos: Position): Future[Assertion] = { | ||
|
||
val effect = Promise[GHResponse[A]]() | ||
val attempt = Promise[Try[GHResponse[A]]]() | ||
effect.future.onComplete(attempt.success) | ||
|
||
val io = source.runAsync { | ||
case Right(s) => IO(effect.success(s)) | ||
case Left(e) => IO(effect.failure(e)) | ||
} | ||
|
||
for (_ <- io.unsafeToFuture(); v <- attempt.future) yield { | ||
v.toOption | ||
.map { result => | ||
f(result) | ||
} | ||
.getOrElse(fail("effect attempt failed")) | ||
} | ||
} | ||
|
||
val accessToken = sys.env.get("GITHUB4S_ACCESS_TOKEN") | ||
val headerUserAgent = Map("user-agent" -> "github4s") | ||
val validUsername = "rafaparadela" | ||
val invalidUsername = "GHInvalidUserName" | ||
val okStatusCode = 200 | ||
|
||
test("return a succeded result for a valid call") { | ||
val response = Github(accessToken).users | ||
.get(validUsername) | ||
.exec[IO, SimpleHttpResponse](headerUserAgent) | ||
|
||
testEffectOnRunAsync(response, { r: GHResponse[User] => | ||
r.isRight shouldBe true | ||
r.right.map(_.statusCode) shouldBe Right(okStatusCode) | ||
}) | ||
} | ||
|
||
test("return a failed result for an invalid call") { | ||
val response = Github(accessToken).users | ||
.get(invalidUsername) | ||
.exec[IO, SimpleHttpResponse](headerUserAgent) | ||
|
||
testEffectOnRunAsync(response, { r: GHResponse[User] => | ||
r.isLeft shouldBe true | ||
}) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This spec is never run, I don't know why. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See #156 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
* Copyright 2016-2017 47 Degrees, LLC. <http://www.47deg.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package github4s.cats.effect.jvm | ||
|
||
object Implicits extends ImplicitsJVM |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Copyright 2016-2017 47 Degrees, LLC. <http://www.47deg.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package github4s.cats.effect.jvm | ||
|
||
import cats.effect.IO | ||
import github4s.HttpRequestBuilderExtensionJVM | ||
import github4s.cats.effect.IOCaptureInstance | ||
import github4s.free.interpreters.Interpreters | ||
import github4s.implicits._ | ||
import scalaj.http.HttpResponse | ||
|
||
trait ImplicitsJVM extends HttpRequestBuilderExtensionJVM with IOCaptureInstance { | ||
implicit val intInstanceIOScalaJ = | ||
new Interpreters[IO, HttpResponse[String]] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* Copyright 2016-2017 47 Degrees, LLC. <http://www.47deg.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package github4s.cats.effect.jvm | ||
|
||
import cats.effect.IO | ||
import github4s.Github | ||
import github4s.Github._ | ||
import github4s.cats.effect.jvm.Implicits._ | ||
import org.scalatest.{FlatSpec, Matchers} | ||
import scalaj.http.HttpResponse | ||
|
||
class CatsEffectJVMSpec extends FlatSpec with Matchers { | ||
val accessToken = sys.env.get("GITHUB4S_ACCESS_TOKEN") | ||
val headerUserAgent = Map("user-agent" -> "github4s") | ||
val validUsername = "rafaparadela" | ||
val invalidUsername = "GHInvalidUserName" | ||
val okStatusCode = 200 | ||
|
||
"cats-effect jvm integration" should "return a succeded result for a valid call" in { | ||
val response = | ||
Github(accessToken).users.get(validUsername).exec[IO, HttpResponse[String]](headerUserAgent) | ||
|
||
val res = response.unsafeRunSync | ||
res.isRight shouldBe true | ||
res.right.map(_.statusCode) shouldBe Right(okStatusCode) | ||
} | ||
|
||
it should "return a failed result for an invalid call" in { | ||
val response = | ||
Github(accessToken).users | ||
.get(invalidUsername) | ||
.exec[IO, HttpResponse[String]](headerUserAgent) | ||
|
||
val res = response.unsafeRunSync | ||
res.isLeft shouldBe true | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* Copyright 2016-2017 47 Degrees, LLC. <http://www.47deg.com> | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package github4s.cats.effect | ||
|
||
import cats.effect.IO | ||
import github4s.free.interpreters.Capture | ||
|
||
trait IOCaptureInstance { | ||
implicit val ioCaptureInstance = new Capture[IO] { | ||
override def capture[A](a: ⇒ A): IO[A] = IO.pure(a) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,8 +56,8 @@ an [HttpClient][http-client]. | |
|
||
The previously mentioned implicit classes carry out of the box | ||
instances for working with [scalaj][scalaj] (for JVM-compatible apps) and [roshttp][roshttp] (for | ||
scala-js-compatible apps). Take into account that in the latter case, you can only use `Future` in | ||
place of `M[_]`. | ||
scala-js-compatible apps). Take into account that in the latter case, you can only use `Future` and | ||
`cats.effect.IO` (if you pull in the `github4s-cats-effect` dependency) in place of `M[_]`. | ||
|
||
A few examples follow with different `MonadError[M, Throwable]`. | ||
|
||
|
@@ -115,7 +115,6 @@ object ProgramFuture { | |
```tut:silent | ||
import scalaz.concurrent.Task | ||
import github4s.scalaz.implicits._ | ||
import scalaj.http.HttpResponse | ||
|
||
object ProgramTask { | ||
val u4 = Github(accessToken).users.get("franciscodr").exec[Task, HttpResponse[String]]() | ||
|
@@ -125,6 +124,33 @@ object ProgramTask { | |
|
||
Note that you'll need a dependency to the `github4s-scalaz` pacakge to leverage `scalaz.Task`. | ||
|
||
### Using `cats.effect.IO` | ||
|
||
On the JVM: | ||
```scala | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't seem to get this example to compile with tut despite adding cats-effect to the doc deps, any ideas? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See #158 |
||
import cats.effect.IO | ||
import github4s.cats.effect.jvm.Implicits._ | ||
|
||
object ProgramTask { | ||
val u5 = Github(accesstoken).users.get("juanpedromoreno").exec[IO, HttpResponse[String]]() | ||
u5.unsafeRunSync | ||
} | ||
``` | ||
|
||
Using scala-js: | ||
```scala | ||
import github4s.cats.effect.js.Implicits._ | ||
import fr.hmil.roshttp.response.SimpleHttpResponse | ||
|
||
object ProgramTask { | ||
val u6 = Github(accesstoken).users.get("fedefernandez").exec[IO, SimpleHttpResponse]() | ||
u6.unsafeRunAsync | ||
} | ||
``` | ||
|
||
Note that you'll need a dependency to the `github4s-cats-effect` package to leverage | ||
`cats.effect.IO`. | ||
|
||
## Specifying custom headers | ||
|
||
The different `exec` methods let users include custom headers for any Github API request: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
curious as to how you found all this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cats-effects
project, I only adapted it for our use case ;)