aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/scala/com/softwaremill/sttp/model/package.scala
blob: def6132c2429d309e937444db7b941ed226bc20e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package com.softwaremill.sttp

import java.io.InputStream
import java.net.URLDecoder
import java.nio.ByteBuffer
import java.nio.file.Path

import scala.language.higherKinds
import scala.collection.immutable.Seq

package object model {
  case class Method(m: String) extends AnyVal
  object Method {
    val GET = Method("GET")
    val HEAD = Method("HEAD")
    val POST = Method("POST")
    val PUT = Method("PUT")
    val DELETE = Method("DELETE")
    val OPTIONS = Method("OPTIONS")
    val PATCH = Method("PATCH")
    val CONNECT = Method("CONNECT")
    val TRACE = Method("TRACE")
  }

  /**
    * Provide an implicit value of this type to serialize arbitrary classes into a request body.
    * Handlers might also provide special logic for serializer instances which they define (e.g. to handle streaming).
    */
  type BodySerializer[B] = B => BasicRequestBody

  sealed trait RequestBody[+S]
  case object NoBody extends RequestBody[Nothing]
  case class SerializableBody[T](f: BodySerializer[T], t: T)
      extends RequestBody[Nothing]

  sealed trait BasicRequestBody extends RequestBody[Nothing]
  case class StringBody(s: String, encoding: String) extends BasicRequestBody
  case class ByteArrayBody(b: Array[Byte]) extends BasicRequestBody
  case class ByteBufferBody(b: ByteBuffer) extends BasicRequestBody
  case class InputStreamBody(b: InputStream) extends BasicRequestBody
  case class PathBody(f: Path) extends BasicRequestBody

  case class StreamBody[S](s: S) extends RequestBody[S]

  /**
    * @tparam T Target type as which the response will be read.
    * @tparam S If `T` is a stream, the type of the stream. Otherwise, `Nothing`.
    */
  sealed trait ResponseAs[T, +S] {
    def map[T2](f: T => T2): ResponseAs[T2, S]
  }

  case class IgnoreResponse[T](g: Unit => T) extends ResponseAs[T, Nothing] {
    override def map[T2](f: T => T2): ResponseAs[T2, Nothing] =
      IgnoreResponse(g andThen f)
  }
  case class ResponseAsString[T](encoding: String, g: String => T)
      extends ResponseAs[T, Nothing] {
    override def map[T2](f: T => T2): ResponseAs[T2, Nothing] =
      ResponseAsString(encoding, g andThen f)
  }
  case class ResponseAsByteArray[T](g: Array[Byte] => T)
      extends ResponseAs[T, Nothing] {
    override def map[T2](f: T => T2): ResponseAs[T2, Nothing] =
      ResponseAsByteArray(g andThen f)
  }
  case class ResponseAsParams[T](encoding: String,
                                 g: Seq[(String, String)] => T)
      extends ResponseAs[T, Nothing] {

    override def map[T2](f: T => T2): ResponseAs[T2, Nothing] =
      ResponseAsParams(encoding, g andThen f)

    private[sttp] def parse(s: String): Seq[(String, String)] = {
      s.split("&")
        .toList
        .flatMap(kv =>
          kv.split("=", 2) match {
            case Array(k, v) =>
              Some(
                (URLDecoder.decode(k, encoding),
                 URLDecoder.decode(v, encoding)))
            case _ => None
        })
    }
  }
  case class ResponseAsStream[T, T2, S](g: T => T2)(
      implicit val responseIsStream: S =:= T)
      extends ResponseAs[T2, S] {

    override def map[T3](f: T2 => T3): ResponseAs[T3, S] =
      ResponseAsStream(g andThen f)
  }
}