diff options
author | adamw <adam@warski.org> | 2017-10-12 19:23:09 +0200 |
---|---|---|
committer | adamw <adam@warski.org> | 2017-10-12 19:23:09 +0200 |
commit | 7bf4d02da823c21b27cf20ba0b764b511ac69432 (patch) | |
tree | 04b9ab557c4af82b9970af386e6f4f9e4292e472 /docs | |
parent | 7885188a982c193e26f8ca6bc9aea8f6a642b32d (diff) | |
download | sttp-7bf4d02da823c21b27cf20ba0b764b511ac69432.tar.gz sttp-7bf4d02da823c21b27cf20ba0b764b511ac69432.tar.bz2 sttp-7bf4d02da823c21b27cf20ba0b764b511ac69432.zip |
More docs
Diffstat (limited to 'docs')
-rw-r--r-- | docs/backends/akkahttp.rst | 52 | ||||
-rw-r--r-- | docs/backends/asynchttpclient.rst | 82 | ||||
-rw-r--r-- | docs/backends/custom.rst | 19 | ||||
-rw-r--r-- | docs/backends/httpurlconnection.rst | 9 | ||||
-rw-r--r-- | docs/backends/okhttp.rst | 17 | ||||
-rw-r--r-- | docs/conf/proxy.rst | 15 | ||||
-rw-r--r-- | docs/conf/ssl.rst | 14 | ||||
-rw-r--r-- | docs/conf/timeouts.rst | 23 | ||||
-rw-r--r-- | docs/credits.rst | 11 | ||||
-rw-r--r-- | docs/index.rst | 14 | ||||
-rw-r--r-- | docs/json.rst | 29 | ||||
-rw-r--r-- | docs/other.rst | 12 | ||||
-rw-r--r-- | docs/requests/defaults.rst | 11 | ||||
-rw-r--r-- | docs/requests/type.rst | 17 | ||||
-rw-r--r-- | docs/testing.rst | 44 |
15 files changed, 369 insertions, 0 deletions
diff --git a/docs/backends/akkahttp.rst b/docs/backends/akkahttp.rst new file mode 100644 index 0000000..41e3a7c --- /dev/null +++ b/docs/backends/akkahttp.rst @@ -0,0 +1,52 @@ +``AkkaHttpBackend`` +=================== + +To use, add the following dependency to your project:: + + "com.softwaremill.sttp" %% "akka-http-backend" % "0.0.20" + +This backend depends on `akka-http <http://doc.akka.io/docs/akka-http/current/scala/http/>`_. +A fully **asynchronous** backend. Sending a request returns a response wrapped +in a ``Future``. + +Next you'll need to add an implicit value:: + + implicit val sttpBackend = AkkaHttpBackend() + + // or, if you'd like to use an existing actor system: + implicit val sttpBackend = AkkaHttpBackend.usingActorSystem(actorSystem) + +This backend supports sending and receiving +`akka-streams <http://doc.akka.io/docs/akka/current/scala/stream/index.html>`_ +streams of type ``akka.stream.scaladsl.Source[ByteString, Any]``. + +To set the request body as a stream:: + + import com.softwaremill.sttp._ + import com.softwaremill.sttp.akkahttp._ + + import akka.stream.scaladsl.Source + import akka.util.ByteString + + val source: Source[ByteString, Any] = ... + + sttp + .streamBody(source) + .post(uri"...") + +To receive the response body as a stream:: + + import com.softwaremill.sttp._ + import com.softwaremill.sttp.akkahttp._ + + import akka.stream.scaladsl.Source + import akka.util.ByteString + + implicit val sttpBackend = AkkaHttpBackend() + + val response: Future[Response[Source[ByteString, Any]]] = + sttp + .post(uri"...") + .response(asStream[Source[ByteString, Any]]) + .send() + diff --git a/docs/backends/asynchttpclient.rst b/docs/backends/asynchttpclient.rst new file mode 100644 index 0000000..cd359b1 --- /dev/null +++ b/docs/backends/asynchttpclient.rst @@ -0,0 +1,82 @@ +``AsyncHttpClientBackend`` +========================== + +To use, add the following dependency to your project:: + + "com.softwaremill.sttp" %% "async-http-client-backend-future" % "0.0.20" + // or + "com.softwaremill.sttp" %% "async-http-client-backend-scalaz" % "0.0.20" + // or + "com.softwaremill.sttp" %% "async-http-client-backend-monix" % "0.0.20" + // or + "com.softwaremill.sttp" %% "async-http-client-backend-cats" % "0.0.20" + +This backend depends on `async-http-client <https://github.com/AsyncHttpClient/async-http-client>`_. +A fully **asynchronous** backend, which uses `Netty <http://netty.io>`_ behind the +scenes. + +The responses are wrapped depending on the dependency chosen in either a: + +* standard Scala ``Future`` +* `Scalaz <https://github.com/scalaz/scalaz>`_ ``Task``. There's a transitive dependency on ``scalaz-concurrent``. +* `Monix <https://monix.io`_ ``Task``. There's a transitive dependency on ``monix-eval``. +* Any type implementing the `Cats Effect <https://github.com/typelevel/cats-effect>`_ ``Async`` typeclass, such as ``cats.effect.IO``. There's a transitive dependency on ``cats-effect``. + +Next you'll need to add an implicit value:: + + implicit val sttpBackend = AsyncHttpClientFutureBackend() + + // or, if you're using the scalaz version: + implicit val sttpBackend = AsyncHttpClientScalazBackend() + + // or, if you're using the monix version: + implicit val sttpBackend = AsyncHttpClientMonixBackend() + + // or, if you're using the cats effect version: + implicit val sttpBackend = AsyncHttpClientCatsBackend[cats.effect.IO]() + + // or, if you'd like to use custom configuration: + implicit val sttpBackend = AsyncHttpClientFutureBackend.usingConfig(asyncHttpClientConfig) + + // or, if you'd like to instantiate the AsyncHttpClient yourself: + implicit val sttpBackend = AsyncHttpClientFutureBackend.usingClient(asyncHttpClient) + +Streaming using Monix +--------------------- + +The Monix backend supports streaming (as both Monix and Async Http Client +support reactive streams ``Publisher``s out of the box). The type of +supported streams in this case is ``Observable[ByteBuffer]``. That is, you can +set such an observable as a request body:: + + import com.softwaremill.sttp._ + + import java.nio.ByteBuffer + import monix.reactive.Observable + + val obs: Observable[ByteBuffer] = ... + + sttp + .streamBody(obs) + .post(uri"...") + +And receive responses as an observable stream:: + + import com.softwaremill.sttp._ + import com.softwaremill.sttp.asynchttpclient.monix._ + + import java.nio.ByteBuffer + import monix.eval.Task + import monix.reactive.Observable + + implicit val sttpBackend = AsyncHttpClientMonixBackend() + + val response: Task[Response[Observable[ByteBuffer]]] = + sttp + .post(uri"...") + .response(asStream[Observable[ByteBuffer]]) + .send() + +It's also possible to use `fs2 <https://github.com/functional-streams-for-scala/fs2>`_ +streams for sending request & receiving responses. + diff --git a/docs/backends/custom.rst b/docs/backends/custom.rst new file mode 100644 index 0000000..86d750a --- /dev/null +++ b/docs/backends/custom.rst @@ -0,0 +1,19 @@ +Custom backends, logging, metrics +================================= + +It is also entirely possible to write your own backend (if so, please consider +contributing!) or wrapping an existing one. You can even write completely +generic wrappers for any delegate backend, as each backend comes equipped +with a monad for the response type. This brings the possibility to ``map`` and +``flatMap`` over responses. + +Possible use-cases for wrapper-backend include: + +* logging +* capturing metrics +* request signing (transforming the request before sending it to the delegate) + +To pass some context to wrapper-backends, requests can be *tagged*. Each +``RequestT`` instance contains a ``tags: Map[String, Any]`` field. This is unused +by http, but can be used e.g. to pass a metric name or logging context. + diff --git a/docs/backends/httpurlconnection.rst b/docs/backends/httpurlconnection.rst new file mode 100644 index 0000000..a196343 --- /dev/null +++ b/docs/backends/httpurlconnection.rst @@ -0,0 +1,9 @@ +``HttpURLConnectionBackend`` +============================ + +The default **synchronous** backend. Sending a request returns a response wrapped +in the identity type constructor, which is equivalent to no wrapper at all. + +To use, add an implicit value:: + + implicit val sttpBackend = HttpURLConnectionBackend() diff --git a/docs/backends/okhttp.rst b/docs/backends/okhttp.rst new file mode 100644 index 0000000..52fbc49 --- /dev/null +++ b/docs/backends/okhttp.rst @@ -0,0 +1,17 @@ +``OkHttpClientBackend`` +======================= + +To use, add the following dependency to your project:: + + "com.softwaremill.sttp" %% "okhttp-backend" % "0.0.20" + // or, for the monix version: + "com.softwaremill.sttp" %% "okhttp-backend-monix" % "0.0.20" + +This backend depends on `OkHttp <http://square.github.io/okhttp/>`_, and offers: + +* a **synchronous** backend: ``OkHttpSyncBackend`` +* an **asynchronous**, ``Future``-based backend: ``OkHttpFutureBackend`` +* an **asynchronous**, Monix-``Task``-based backend: ``OkHttpMonixBackend`` + +OkHttp fully supports HTTP/2. + diff --git a/docs/conf/proxy.rst b/docs/conf/proxy.rst new file mode 100644 index 0000000..85b140a --- /dev/null +++ b/docs/conf/proxy.rst @@ -0,0 +1,15 @@ +Proxy support +============= + +A proxy can be specified when creating a backend:: + + import com.softwaremill.sttp._ + + implicit val backend = HttpURLConnectionBackend( + options = SttpBackendOptions.httpProxy("some.host", 8080)) + + sttp + .get(uri"...") + .send() // uses the proxy + + diff --git a/docs/conf/ssl.rst b/docs/conf/ssl.rst new file mode 100644 index 0000000..8b58e25 --- /dev/null +++ b/docs/conf/ssl.rst @@ -0,0 +1,14 @@ +SSL +=== + +SSL handling can be customized (or disabled) when creating a backend and is +backend-specific. + +Depending on the underlying backend's client, you can customize SSL settings +as follows: + +* ``HttpUrlConnectionBackend``: when creating the backend, specify the ``customizeConnection: HttpURLConnection => Unit`` parameter, and set the hostname verifier & SSL socket factory as required +* akka-http: when creating the backend, specify the ``customHttpsContext: Option[HttpsConnectionContext]`` parameter. See `akka-http docs <http://doc.akka.io/docs/akka-http/current/scala/http/server-side/server-https-support.html>`_ +* async-http-client: create a custom client and use the ``setSSLContext`` method +* OkHttp: create a custom client modifying the SSL settings as described `on the wiki <https://github.com/square/okhttp/wiki/HTTPS>`_ + diff --git a/docs/conf/timeouts.rst b/docs/conf/timeouts.rst new file mode 100644 index 0000000..72b2f4a --- /dev/null +++ b/docs/conf/timeouts.rst @@ -0,0 +1,23 @@ +Timeouts +======== + +Sttp supports read and connection timeouts: + +* Connection timeout - can be set globally (30 seconds by default) +* Read timeout - can be set per request (1 minute by default) + +How to use:: + + import com.softwaremill.sttp._ + import scala.concurrent.duration._ + + // all backends provide a constructor that allows users to specify backend options + implicit val backend = HttpURLConnectionBackend( + options = SttpBackendOptions.connectionTimeout(1.minute)) + + sttp + .get(uri"...") + .readTimeout(5.minutes) // or Duration.Inf to turn read timeout off + .send() + + diff --git a/docs/credits.rst b/docs/credits.rst new file mode 100644 index 0000000..4826afe --- /dev/null +++ b/docs/credits.rst @@ -0,0 +1,11 @@ +Credits +======= + +* `Adam Warski <https://github.com/adamw>`_ +* `Tomasz Szymański <https://github.com/szimano>`_ +* `Omar Alejandro Mainegra Sarduy <https://github.com/omainegra)>`_ +* `Bjørn Madsen <https://github.com/aeons>`_ +* `Piotr Buda <https://github.com/pbuda>`_ +* `Piotr Gabara <https://github.com/bhop>`_ +* `Gabriele Petronella <https://github.com/gabro>`_ + diff --git a/docs/index.rst b/docs/index.rst index e78ae4b..0550cd7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -55,8 +55,22 @@ If you'd like to use an alternate backend, [see below](#supported-backends) for goals requests/basics requests/uri + requests/defaults + requests/type backends/summary backends/start_stop + backends/httpurlconnection + backends/akkahttp + backends/asynchttpclient + backends/okhttp + backends/custom + conf/timeouts + conf/ssl + conf/proxy + json + testing + other + credits Indices and tables ================== diff --git a/docs/json.rst b/docs/json.rst new file mode 100644 index 0000000..28cee81 --- /dev/null +++ b/docs/json.rst @@ -0,0 +1,29 @@ +JSON +==== + +JSON encoding of bodies and decoding of responses can be handled using +`Circe <https://circe.github.io/circe/>`_ by the ``circe`` module. To use +add the following dependency to your project:: + + "com.softwaremill.sttp" %% "circe" % "0.0.20" + +This module adds a method to the request and a function that can be given to +a request to decode the response to a specific object. + + import com.softwaremill.sttp._ + import com.softwaremill.sttp.circe._ + + implicit val backend = HttpURLConnectionBackend() + + // Assume that there is an implicit circe encoder in scope + // for the request Payload, and a decoder for the Response + val requestPayload: Payload = ??? + + val response: Either[io.circe.Error, Response] = + sttp + .post(uri"...") + .body(requestPayload) + .response(asJson[Response]) + .send() + + diff --git a/docs/other.rst b/docs/other.rst new file mode 100644 index 0000000..7ee7f83 --- /dev/null +++ b/docs/other.rst @@ -0,0 +1,12 @@ +Other Scala HTTP clients +======================== + +* `scalaj <https://github.com/scalaj/scalaj-http>`_ +* `akka-http client <http://doc.akka.io/docs/akka-http/current/scala/http/client-side/index.html>`_ +* `dispatch <http://dispatch.databinder.net/Dispatch.html>`_ +* `play ws <https://github.com/playframework/play-ws>`_ +* `fs2-http <https://github.com/Spinoco/fs2-http>`_ +* `http4s <http://http4s.org/v0.17/client/>`_ +* `Gigahorse <http://eed3si9n.com/gigahorse/>`_ +* `RösHTTP <https://github.com/hmil/RosHTTP>`_ + diff --git a/docs/requests/defaults.rst b/docs/requests/defaults.rst new file mode 100644 index 0000000..f393c04 --- /dev/null +++ b/docs/requests/defaults.rst @@ -0,0 +1,11 @@ +Defaults +======== + +The encoding for ``String``s defaults to ``utf-8``. + +Unless explicitly specified, the ``Content-Type`` defaults to: + +* ``text/plain`` for text +* ``application/x-www-form-urlencoded`` for form data +* ``multipart/form-data`` for multipart form data +* ``application/octet-stream`` for everything else (binary) diff --git a/docs/requests/type.rst b/docs/requests/type.rst new file mode 100644 index 0000000..3cefe97 --- /dev/null +++ b/docs/requests/type.rst @@ -0,0 +1,17 @@ +Request type +============ + +All request descriptions have type ``RequestT[U, T, S]`` (T as in Template). +If this looks a bit complex, don't worry, what the three type parameters stand +for is the only thing you'll hopefully have to remember when using the API! + +Going one-by-one: + +* ``U[_]`` specifies if the request method and URL are specified. Using the API, this can be either ``type Empty[X] = None``, meaning that the request has neither a method nor an URI. Or, it can be ``type Id[X] = X`` (type-level identity), meaning that the request has both a method and an URI specified. Only requests with a specified URI & method can be sent. +* ``T`` specifies the type to which the response will be read. By default, this is ``String``. But it can also be e.g. ``Array[Byte]`` or ``Unit``, if the response should be ignored. Response body handling can be changed by calling the ``.response`` method. With backends which support streaming, this can also be a supported stream type. +* ``S`` specifies the stream type that this request uses. Most of the time this will be ``Nothing``, meaning that this request does not send a streaming body or receive a streaming response. So most of the times you can just ignore that parameter. But, if you are using a streaming backend and want to send/receive a stream, the ``.streamBody`` or ``response(asStream[S])`` will change the type parameter. + +There are two type aliases for the request template that are used: + +* ``type Request[T, S] = RequestT[Id, T, S]``. A sendable request. +* ``type PartialRequest[T, S] = RequestT[Empty, T, S]`` diff --git a/docs/testing.rst b/docs/testing.rst new file mode 100644 index 0000000..0ac21c2 --- /dev/null +++ b/docs/testing.rst @@ -0,0 +1,44 @@ +Testing +======= + +If you need a stub backend for use in tests instead of a "real" backend (you +probably don't want to make HTTP calls during unit tests), you can use the +``SttpBackendStub`` class. It allows specifying how the backend should respond +to requests matching given predicates. + +A backend stub can be created using an instance of a "real" backend, or by +explicitly giving the response wrapper monad and supported streams type. + +For example:: + + implicit val testingBackend = SttpBackendStub(HttpURLConnectionBackend()) + .whenRequestMatches(_.uri.path.startsWith(List("a", "b"))) + .thenRespond("Hello there!") + .whenRequestMatches(_.method == Method.POST) + .thenRespondServerError() + + val response1 = sttp.get(uri"http://example.org/a/b/c").send() + // response1.body will be Right("Hello there") + + val response2 = sttp.post(uri"http://example.org/d/e").send() + // response2.code will be 500 + +However, this approach has one caveat: the responses are not type-safe. That +is, the backend cannot match on or verify that the type included in the +response matches the response type requested. + +It is also possible to create a stub backend which delegates calls to another +(possibly "real") backend if none of the specified predicates match a request. +This can be useful during development, to partially stub a yet incomplete +API with which we integrate:: + + implicit val testingBackend = SttpBackendStub.withFallback(HttpURLConnectionBackend()) + .whenRequestMatches(_.uri.path.startsWith(List("a"))) + .thenRespond("I'm a STUB!") + + val response1 = sttp.get(uri"http://api.internal/a").send() + // response1.body will be Right("I'm a STUB") + + val response2 = sttp.post(uri"http://api.internal/b").send() + // response2 will be whatever a "real" network call to api.internal/b returns + |