Move to 0.7.20 or newer releases, now!
Sunsetting of Bintray is forcing our hand to give up on versions before 0.7.20. So please migrate to 0.7.20 or later ASAP. Checkout the releases https://github.com/ppurang/asynch/releases.
Prologue
Sbt library dependency
libraryDependencies += "org.purang.net" %% "asynch" % "0.7.20" withSources()
From Maven Central, check the badge above.
For older releases use:
resolvers += "ppurang bintray" at "https://dl.bintray.com/ppurang/maven"
Note: Soon the bintray service will be sunset and not available hence use the maven central versions. Checkout - https://search.maven.org/search?q=org.purang.net
Quick
The code below executes a blocking POST against http://httpize.herokuapp.com/post with request headers Accept: application/json, text/html, text/plain, Cache-Control: no-cache and Content-Type: text/plain, and request entity some very important message. It expects a 200 with some response body. If it encounters an exception or another status code then they are returned too. The type returned is \/[String, String]: left String (-\/[String]) indicates the error, and the right String (\/-[String]) contains the successful response body.
import org.purang.net.http._
import scalaz._, Scalaz._
import org.purang.net.http.ning.DefaultAsyncHttpClientNonBlockingExecutor
import org.asynchttpclient.DefaultAsyncHttpClientConfig
implicit val sse = java.util.concurrent.Executors.newScheduledThreadPool(2)
val config = new DefaultAsyncHttpClientConfig.Builder()
.setCompressionEnforced(true)
.setConnectTimeout(500)
.setRequestTimeout(3000)
.setCookieStore(null) //recommended as clients should be stateless
.build()
implicit val newExecutor = DefaultAsyncHttpClientNonBlockingExecutor(config)
val response = (POST >
"http://httpize.herokuapp.com/post" >>
("Accept" `:` "application/json" ++ "text/html" ++ "text/plain") ++
("Cache-Control" `:` "no-cache") ++
("Content-Type" `:` "text/plain") >>>
"some very important message").~>(
(x: ExecutedRequest) => x.fold(
t => t._1.getMessage.left,
{
case (200, _, Some(body), _) => body.right
case (status: Status, headers: Headers, body: Body, req: Request) => status.toString.left
}
))
// close the client
// newExecutor.close()
// sse.shutdownNow()
For examples of non blocking/ asynchronous calls look at src/test/scala/NonBlockingExecutorSpec.scala
For examples of blocking calls look at src/test/scala/ExecutorSpec.scala
For an example of a custom configured executor look at src/test/scala/CustomNingExecutorSpec.scala. Here is the meat of the code:
implicit val sse = java.util.concurrent.Executors.newScheduledThreadPool(2)
val config = new DefaultAsyncHttpClientConfig.Builder()
.setCompressionEnforced(true)
.setConnectTimeout(500)
.setRequestTimeout(3000)
.setCookieStore(null) //recommended as clients should be stateless
.build()
implicit val newExecutor = DefaultAsyncHttpClientNonBlockingExecutor(config)
Types
type FailedRequest = (Throwable, Request)
type AResponse = (Status, Headers, Body, Request)
type or[+E, +A] = \/[E, A]
type ExecutedRequest = FailedRequest or AResponse
type NonBlockingExecutedRequest = scalaz.concurrent.Task[AResponse]
trait NonBlockingExecutor extends (Timeout => Request => NonBlockingExecutedRequest)
type ExecutedRequestHandler[T] = (ExecutedRequest => T)
Testing support? Easy.
Here is an example of test executor src/test/scala/TestExecutor.scala that looks up things in a Map used internally to test things.
Philosophy
- Timeouts - Yes! we do timeouts.
- Immutable - API to assemble requests and response handling is immutable.
- Easy parts are easy (if you can look beyond weird operators and operator precedence). For example a request is easy to assemble
GET > "http://www.google.com"actually even theGETisn't really needed either("http://www.host.com" >> Accept(ApplicationJson)). - Full control - you are forced to deal with the exceptions and responses. You even have the request that got executed if you wanted to modify it to re-execute.
- Parts are done with scalaz goodness.
Limitations
- Too many implicits!
- Entity bodies can only be strings or types that can implictly be converted to strings. No endless Streams.
- No explicit Authentication support.
- No web socket or such support.
- Underlying http call infrastructure is as asynchronous, fast, bug-free as async-http-client.
- No metrics and no circuit breakers.
Help/Join
Critique is sought actively. Help will be provided keenly. Contributions are welcome. Install simple build tool 0.13+, fork the repo and get hacking.
LICENSE
licenses += ("BSD", url("http://www.tldrlegal.com/license/bsd-3-clause-license-%28revised%29"))
Disclaimer
Use at your own risk. See LICENSE for more details.