Last active
April 8, 2018 13:56
-
-
Save felipecrv/2687421a7f98a8b57af6e731f8a633a5 to your computer and use it in GitHub Desktop.
A convenient HTTP API Client based on the Jetty HTTP client written in Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package m79.infra | |
import java.net.URI | |
import java.time.format.DateTimeFormatter | |
import m79.infra.HttpAPIClient.Call | |
import org.eclipse.jetty.client.HttpClient | |
import org.eclipse.jetty.client.api.{Request, Result} | |
import org.eclipse.jetty.client.util.{BufferingResponseListener, MultiPartContentProvider, StringContentProvider} | |
import org.eclipse.jetty.http.HttpMethod | |
import org.eclipse.jetty.util.Fields | |
import org.eclipse.jetty.util.ssl.SslContextFactory | |
import org.slf4j.LoggerFactory | |
import scala.concurrent.{ExecutionContext, Future, Promise} | |
object HttpAPIClient { | |
val Logger = LoggerFactory.getLogger(classOf[HttpAPIClient]) | |
val MaxContentLength: Int = 2 * 1024 * 1024 | |
// HTTP Date header format "Sun, 06 Nov 1994 08:49:37 GMT" | |
val HttpDateFormat: DateTimeFormatter = DateTimeFormatter.RFC_1123_DATE_TIME | |
class Call(request: Request) { | |
private var multiPartContentProvider: MultiPartContentProvider = null | |
def data(name: String, value: String): Call = { | |
if (multiPartContentProvider == null) { | |
multiPartContentProvider = new MultiPartContentProvider | |
} | |
multiPartContentProvider.addFieldPart(name, new StringContentProvider(value), null) | |
this | |
} | |
def param(name: String, value: String): Call = { | |
request.param(name, value) | |
this | |
} | |
def params: Fields = request.getParams | |
def param(name: String): Option[String] = { | |
Option(request.getParams.get(name)).map(_.getValue) | |
} | |
def header(name: String, value: String) = { | |
request.header(name, value) | |
this | |
} | |
/** | |
* Send a HTTP request and get the response content at once asynchronously. | |
* | |
* @param maxContentLength The maximum size of response content in bytes | |
* @return A BufferedResponseListener future providing getContent*() methods | |
*/ | |
def send(maxContentLength: Int = MaxContentLength) | |
(implicit ec: ExecutionContext): Future[BufferingResponseListener] = { | |
send0(maxContentLength).map(_._2) | |
} | |
/** | |
* Send a HTTP request and get only the response asynchronously. | |
* The content is discarded. | |
*/ | |
def complete(): Future[Result] = { | |
if (multiPartContentProvider != null) { | |
request.content(multiPartContentProvider) | |
} | |
val p = Promise[Result] | |
request.send((result: Result) => { | |
if (result.isFailed) { | |
Logger.error("API client request failed", result.getFailure) | |
p.failure(result.getFailure) | |
} else { | |
p.success(result) | |
} | |
}) | |
p.future | |
} | |
def send0(maxContentLength: Int = 2 * 1024 * 1024): Future[(Result, BufferingResponseListener)] = { | |
if (multiPartContentProvider != null) { | |
request.content(multiPartContentProvider) | |
} | |
val p = Promise[(Result, BufferingResponseListener)] | |
request.send(new BufferingResponseListener(maxContentLength) { | |
override def onComplete(result: Result): Unit = { | |
if (result.isFailed) { | |
Logger.error("API client request failed", result.getFailure) | |
p.failure(result.getFailure) | |
} else { | |
val adapter = this | |
p.success((result, adapter)) | |
} | |
} | |
}) | |
p.future | |
} | |
} | |
} | |
class HttpAPIClient(httpClient: HttpClient) { | |
httpClient.setFollowRedirects(true) | |
def this(sslContextFactory: SslContextFactory) = this(new HttpClient(sslContextFactory)) | |
def this() = this(new SslContextFactory) | |
def start = httpClient.start | |
def stop = httpClient.stop | |
def call(uri: URI, method: HttpMethod) = { | |
val request = httpClient.newRequest(uri).method(method) | |
new Call(request) | |
} | |
def call(uri: String, method: HttpMethod): Call = call(URI.create(uri), method) | |
def GET(uri: URI): Call = { | |
val request = httpClient.newRequest(uri).method(HttpMethod.GET) | |
new Call(request) | |
} | |
def POST(uri: URI) = { | |
val request = httpClient.newRequest(uri).method(HttpMethod.POST) | |
new Call(request) | |
} | |
def GET(uri: String): Call = GET(URI.create(uri)) | |
def POST(uri: String): Call = POST(URI.create(uri)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Call
client.start()
when the program starts and addclient.stop()
to the JVM shutdown hook.Then the client can be used like this