Skip to content
master
Go to file
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
src
 
 
 
 
 
 
 
 
 
 

README.md

Build Status

Download

Prologue

Sbt library dependency (for latest versions check https://bintray.com/ppurang/maven/asynch)

//for netty 4.0.x
libraryDependencies += "org.purang.net" %% "asynch" % "0.6.1" withSources()

//for netty 4.1.x and async-http-client:2.10.x
libraryDependencies += "org.purang.net" %% "asynch" % "0.7.17" withSources()

From

resolvers += "ppurang bintray" at "https://dl.bintray.com/ppurang/maven"

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

  1. Timeouts - Yes! we do timeouts.
  2. Immutable - API to assemble requests and response handling is immutable.
  3. 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 the GET isn't really needed either ("http://www.host.com" >> Accept(ApplicationJson)).
  4. 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.
  5. Parts are done with scalaz goodness.

Limitations

  1. Too many implicits!
  2. Entity bodies can only be strings or types that can implictly be converted to strings. No endless Streams.
  3. No explicit Authentication support.
  4. No web socket or such support.
  5. Underlying http call infrastructure is as asynchronous, fast, bug-free as async-http-client.
  6. 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.

About

Consume REST or HTTP endpoints. Scala http client based on scalaz Task and AsyncHttpClient.

Resources

Packages

No packages published

Languages

You can’t perform that action at this time.