All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sttp.tapir.model.ServerRequest.scala Maven / Gradle / Ivy

There is a newer version: 1.11.9
Show newest version
package sttp.tapir.model

import sttp.model.headers.Accepts
import sttp.model.{ContentTypeRange, Header, MediaType, Method, QueryParams, RequestMetadata, Uri}
import sttp.tapir.AttributeKey

import java.net.InetSocketAddress
import scala.collection.immutable.Seq

/** Implement for specific request representation of a particular server. Consider overriding [[ServerRequest#uri]] and
  * [[ServerRequest#showShort]] for a backend-specific implementation of constructing the Uri and printing the path + query params. This way
  * you'll avoid a performance overhead of parsing [[sttp.model.Uri]]. See https://softwaremill.com/benchmarking-tapir-part-2/ for more
  * details.
  */
trait ServerRequest extends RequestMetadata {
  def protocol: String
  def connectionInfo: ConnectionInfo
  def underlying: Any

  /** Can differ from `uri.path`, if the endpoint is deployed in a context */
  def pathSegments: List[String]
  def queryParameters: QueryParams

  lazy val acceptsContentTypes: Either[String, Seq[ContentTypeRange]] = Accepts.parse(headers)
  lazy val contentTypeParsed: Option[MediaType] = contentType.flatMap(MediaType.parse(_).toOption)

  def attribute[T](k: AttributeKey[T]): Option[T]
  def attribute[T](k: AttributeKey[T], v: T): ServerRequest

  /** Create a copy of this server request, which reads data from the given underlying implementation. The type of `underlying` should be
    * the same as the type of `this.underlying`.
    */
  def withUnderlying(underlying: Any): ServerRequest

  /** Create a copy of this server request, which overrides some of the data that is read from the underlying implementation with the given
    * values. E.g. instead of reading the headers from the underlying request, the headers might be given explicitly.
    */
  def withOverride(
      methodOverride: Option[Method] = None,
      uriOverride: Option[Uri] = None,
      protocolOverride: Option[String],
      connectionInfoOverride: Option[ConnectionInfo],
      pathSegmentsOverride: Option[List[String]] = None,
      queryParametersOverride: Option[QueryParams] = None,
      headersOverride: Option[Seq[Header]] = None
  ): ServerRequest =
    new ServerRequestOverride(
      methodOverride,
      uriOverride,
      protocolOverride,
      connectionInfoOverride,
      pathSegmentsOverride,
      queryParametersOverride,
      headersOverride,
      this
    )

  /** A short representation of this request, including the request method, path and query. */
  def showShort: String = s"$method ${uri.copy(scheme = None, authority = None, fragmentSegment = None).toString}"
}

class ServerRequestOverride(
    methodOverride: Option[Method],
    uriOverride: Option[Uri],
    protocolOverride: Option[String],
    connectionInfoOverride: Option[ConnectionInfo],
    pathSegmentsOverride: Option[List[String]],
    queryParametersOverride: Option[QueryParams],
    headersOverride: Option[Seq[Header]],
    delegate: ServerRequest
) extends ServerRequest {
  override def method: Method = methodOverride.getOrElse(delegate.method)
  override def uri: Uri = uriOverride.getOrElse(delegate.uri)
  override def protocol: String = protocolOverride.getOrElse(delegate.protocol)
  override def connectionInfo: ConnectionInfo = connectionInfoOverride.getOrElse(delegate.connectionInfo)
  override def underlying: Any = delegate.underlying
  override def pathSegments: List[String] = pathSegmentsOverride.getOrElse(delegate.pathSegments)
  override def queryParameters: QueryParams = queryParametersOverride.getOrElse(delegate.queryParameters)
  override def headers: Seq[Header] = headersOverride.getOrElse(delegate.headers)
  override def attribute[T](k: AttributeKey[T]): Option[T] = delegate.attribute(k)
  override def attribute[T](k: AttributeKey[T], v: T): ServerRequest =
    new ServerRequestOverride(
      methodOverride,
      uriOverride,
      protocolOverride,
      connectionInfoOverride,
      pathSegmentsOverride,
      queryParametersOverride,
      headersOverride,
      delegate.attribute(k, v)
    )
  override def withUnderlying(underlying: Any): ServerRequest =
    new ServerRequestOverride(
      methodOverride,
      uriOverride,
      protocolOverride,
      connectionInfoOverride,
      pathSegmentsOverride,
      queryParametersOverride,
      headersOverride,
      delegate.withUnderlying(underlying)
    )
}

case class ConnectionInfo(local: Option[InetSocketAddress], remote: Option[InetSocketAddress], secure: Option[Boolean])

object ConnectionInfo {

  /** When no info can be obtained from context. */
  val NoInfo: ConnectionInfo = ConnectionInfo(None, None, None)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy