aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradamw <adam@warski.org>2017-10-12 19:23:09 +0200
committeradamw <adam@warski.org>2017-10-12 19:23:09 +0200
commit7bf4d02da823c21b27cf20ba0b764b511ac69432 (patch)
tree04b9ab557c4af82b9970af386e6f4f9e4292e472
parent7885188a982c193e26f8ca6bc9aea8f6a642b32d (diff)
downloadsttp-7bf4d02da823c21b27cf20ba0b764b511ac69432.tar.gz
sttp-7bf4d02da823c21b27cf20ba0b764b511ac69432.tar.bz2
sttp-7bf4d02da823c21b27cf20ba0b764b511ac69432.zip
More docs
-rw-r--r--docs/backends/akkahttp.rst52
-rw-r--r--docs/backends/asynchttpclient.rst82
-rw-r--r--docs/backends/custom.rst19
-rw-r--r--docs/backends/httpurlconnection.rst9
-rw-r--r--docs/backends/okhttp.rst17
-rw-r--r--docs/conf/proxy.rst15
-rw-r--r--docs/conf/ssl.rst14
-rw-r--r--docs/conf/timeouts.rst23
-rw-r--r--docs/credits.rst11
-rw-r--r--docs/index.rst14
-rw-r--r--docs/json.rst29
-rw-r--r--docs/other.rst12
-rw-r--r--docs/requests/defaults.rst11
-rw-r--r--docs/requests/type.rst17
-rw-r--r--docs/testing.rst44
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
+