sttp client

repository·master·Indexed 23 days ago

https://github.com/softwaremill/sttp

An open-source, multi-platform HTTP client for Scala. It features a decoupled architecture separating request description from execution via backends, supporting synchronous and asynchronous effects (ZIO, cats-effect) and low-level backends like Java HttpClient, Akka HTTP, and http4s. It provides a fluent API for building requests, support for WebSockets and streaming, and a RequestListener trait for intercepting request lifecycle events.

Tokens
82.5K
Snippets
210
Records
388
Agent score
79%

What's inside sttp

  1. Overview of sttp client capabilities

    master

    sttp client is a multi-platform Scala HTTP client (JVM, Scala.JS, Scala Native) that supports various programming styles:

    • Synchronous (direct-style)
    • Future-based
    • Functional Effect Systems (cats-effect, ZIO, Monix, Kyo, scalaz)

    It supports common use cases including:

    • JSON API interaction (automatic serialization/deserialization)
    • File uploads and downloads
    • Form data and multipart requests
    • WebSockets
    • Streaming (fs2, ZIO Streams, Akka Streams, Pekko Streams)

    It integrates with various backends (Java HttpClient, Akka HTTP, Pekko HTTP, http4s, OkHttp, Armeria) and JSON libraries (circe, uPickle, etc.).

  2. Understand caching eligibility and default configuration

    master

    When using CachingConfig.Default, the backend follows standard HTTP semantics to determine if a request and response should be cached:

    Request Eligibility:

    • The request method must be GET or HEAD.
    • Non-blocking streaming responses, file-based responses, and WebSockets are excluded from caching.

    Response Eligibility:

    • The response must contain a Cache-Control header with a max-age directive.
    • The response is cached for the duration specified in that directive.

    Cache Key and Storage:

    • Cache Key: Created using the request method, URI, and the values of headers specified in the response's Vary header.
    • Storage Format: For eligible requests, the response body is read into a byte array and serialized to JSON using jsoniter-scala for storage.
  3. How resilience works with sttp

    master

    sttp does not implement resilience features like retries, circuit breaking, or rate limiting directly. Instead, it is designed to be compatible with existing Scala resilience libraries by treating the send() operation as a lazily evaluated description of a request.

    Depending on your backend, myRequest.send(backend) can be viewed as:

    • A synchronous function: () => Response[T]
    • A Future-based asynchronous function: () => Future[Response[T]]
    • A process description for effect systems: IO[Response[T]] or Task[Response[T]]

    Because these are lazy descriptions, you can wrap the send() call in a higher-level resilience tool that manages retries or circuit breaking based on the resulting exception or response, as well as the original request details (like the host or HTTP method).

  4. Wrap a backend with Prometheus for monitoring

    master

    The Prometheus backend is a wrapper that can be applied to any existing sttp backend. It automatically registers histograms for request execution times and gauges for active requests. Note that you are responsible for exposing these metrics to a Prometheus server.

    By default, it uses:

    • http_client_request_duration_seconds (defined in PrometheusBackend.DefaultHistogramName) for request durations.
    • http_client_requests_active (defined in PrometheusBackend.DefaultRequestsActiveCounterName) for in-progress requests.
    import sttp.client4.pekkohttp.*
    val backend = PrometheusBackend(PekkoHttpBackend())
  5. Generate sttp-client requests from OpenAPI specifications

    master

    You can automatically generate sttp-client request definitions and models from OpenAPI (.yaml) specifications using the scala-sttp code generator, which is part of the openapi-generator project.

    There are two available generators:

    • scala-sttp4-jsoniter: Uses sttp-client 4, Scala 3, and jsoniter-scala for JSON handling.
    • scala-sttp: Uses sttp-client 4, and json4s or circe for JSON handling.
  6. Construct sttp model instances using companion objects

    master

    Companion objects for model classes provide several ways to create instances, ranging from unvalidated creation to strict parsing. Use these methods based on your need for safety and validation:

    MethodBehavior
    .apply(...)Creates the model type without validation and without throwing exceptions.
    .safeApply(...)Creates an instance with validation; returns Either[String, ModelClass] (error message or instance).
    .unsafeApply(...)Creates an instance with validation; throws an exception on error (e.g., invalid characters).
    .parse(serialized: String)Parses a serialized string; returns Either[String, ModelClass].
    .unsafeParse(serialized: String)Parses a serialized string; throws an exception on error.

    Companion objects also provide constants for well-known instances, such as StatusCode.Ok, Method.POST, MediaType.ImageGif, and constructor methods like Header.contentType(MediaType).

  7. Understand the core design principles of sttp

    master

    sttp is designed around several key architectural principles to provide a consistent and developer-friendly experience:

    • Separation of Concerns: The definition of an HTTP request is decoupled from its execution. You define a request object first, then pass it to a backend to execute it.
    • Immutability: Requests and responses are represented by immutable, easily modifiable data structures.
    • Backend Agnostic: sttp acts as a wrapper around existing HTTP clients rather than implementing a full client itself. It delegates network concerns like connection pooling and sending requests to a chosen backend.
    • Backend Support: It supports multiple execution backends, both synchronous and asynchronous, including support for backend-specific streaming.
    • Minimal Dependencies: The library aims to keep its dependency footprint small.
    • Flexible Request Building: Uses an immutable request builder that does not impose a specific order for parameters. This allows you to define partial requests (e.g., with common headers or cookies) and specialize them later with specific URIs or methods.
  8. Understand the sttp request type hierarchy

    master

    sttp has refactored its request types to simplify the API and improve type safety. Instead of a single complex RequestT type, requests are now organized into a hierarchy based on their capabilities (e.g., streaming or WebSockets).

    Request Builders

    Requests are constructed using builders:

    • PartialRequest: The top-level entry point for starting a request.
    • PartialRequestBuilder: A trait providing common methods for building requests.
    • RequestBuilder: A trait for requests that are fully specified and ready to be sent.

    Request Types

    Once a request is configured, it falls into one of these categories based on its capabilities:

    • GenericRequest: A base trait representing a request description (containing at least a URI and a Method).
    • Request[T]: A standard request with a response target type T.
    • StreamRequest[T]: A request designed for streaming bodies or responses.
    • WebSocketRequest: A request for WebSocket communication.
    • WebSocketStreamRequest: A request combining WebSocket and streaming capabilities.

    Type Promotion

    Capabilities are promoted as you configure the request. For example, setting a response description or an input stream body will promote a Request or PartialRequest to the appropriate streaming type.

  9. How to use WebSockets in sttp

    master

    WebSocket requests in sttp are defined using the same basicRequest pattern as regular HTTP requests. To initiate a WebSocket connection instead of a standard HTTP request, you must specify a WebSocket response specification using the .response(...) method.

    Depending on your backend and concurrency model, you must import the appropriate module to bring the asWebSocket methods into scope:

    • Synchronous: import sttp.client4.ws.sync.* (e.g., for DefaultSyncBackend).
    • Asynchronous: import sttp.client4.ws.async.* (e.g., for backends using Future or IO).
    • Streaming: import sttp.client4.ws.stream.* (e.g., for fs2.Stream or akka.stream.scaladsl.Source).
  10. Understand the sttp model classes

    master

    The sttp-model project provides a basic HTTP model used throughout the sttp ecosystem. It includes core classes for representing HTTP components and constants for common values like headers, media types, and status codes.

    Core model classes include:

    • Header
    • Cookie
    • CookieWithMeta
    • MediaType
    • Method
    • StatusCode
    • CacheDirective
    • ETag
    • Uri

    Calling .toString on these classes returns a string representation consistent with HTTP request/response formats.