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

com.nrinaudo.fetch.Status.scala Maven / Gradle / Ivy

The newest version!
package com.nrinaudo.fetch

/** Defines known HTTP status codes, as well as pattern match helpers. */
object Status {
  val Ok = Status(200)
  val Created = Status(201)
  val Accepted = Status(202)
  val NonAuthoritativeInformation = Status(203)
  val NoContent = Status(204)
  val ResetContent = Status(205)
  val PartialContent = Status(206)

  val MultipleChoices = Status(300)
  val MovedPermanently = Status(301)
  val Found = Status(302)
  val SeeOther = Status(303)
  val NotModified = Status(304)
  val UseProxy = Status(305)
  val TemporaryRedirect = Status(307)

  val BadRequest = Status(400)
  val Unauthorized = Status(401)
  val PaymentRequired = Status(402)
  val Forbidden = Status(403)
  val NotFound = Status(404)
  val MethodNotAllowed = Status(405)
  val NotAcceptable = Status(406)
  val ProxyAuthenticationRequired = Status(407)
  val RequestTimeout = Status(408)
  val Conflict = Status(409)
  val Gone = Status(410)
  val LengthRequired = Status(411)
  val PreconditionFailed = Status(412)
  val RequestEntityTooLarge = Status(413)
  val RequestUriTooLong = Status(414)
  val UnsupportedMediaType = Status(415)
  val RequestRangeNotSatisfiable = Status(416)
  val ExpectationFailed = Status(417)

  val InternalServerError = Status(500)
  val NotImplemented = Status(501)
  val BadGateway = Status(502)
  val ServiceUnavailable = Status(503)
  val GatewayTimeout = Status(504)
  val HttpVersionNotSupported = Status(505)

  /** Helper for status group extractors.
    *
    * For example, the following code will create an extractor for the `2xx` group ([[Status.Success]], essentially):
    * {{{
    * object Success extends Extractor(_.isSuccess)
    * }}}
    *
    * This can then be used as follows: {{{
    *   val res: Response[ResponseEntity] = ???
    *
    *   // Pattern match against a status
    *   res.status match {
    *     case Success(_) => println("Success")
    *     case _          => println("Not success")
    *   }
    *
    *   // Pattern match against a Response
    *   res match {
    *     case Success(_) => println("Success")
    *     case _          => println("Not success")
    *   }
    * }}}
    *
    * @param f any status for which this returns `true` will be matched by the extractor.
    */
  class Extractor(val f: Status => Boolean) {
    /** Pattern matches against [[Status statuses]]. */
    def unapply(status: Status): Option[Status] =
      if(f(status)) Some(status)
      else          None

    /** Pattern matches against [[Response responses]]. */
    def unapply[T](res: Response[T]): Option[Status] =
      if(f(res.status)) Some(res.status)
      else              None
  }

  def unapply[T](res: Response[T]): Option[Status] = Some(res.status)


  /** Used to pattern match [[Status statuses]] and [[Response responses]] on the `2xx` group. */
  object Success extends Extractor(_.isSuccess)
  /** Used to pattern match [[Status statuses]] and [[Response responses]] on the `4xx` and `5xx` groups. */
  object Error extends Extractor(_.isError)
  /** Used to pattern match [[Status statuses]] and [[Response responses]] on the `4xx` group. */
  object ClientError extends Extractor(_.isClientError)
  /** Used to pattern match [[Status statuses]] and [[Response responses]] on the `5xx` group. */
  object ServerError extends Extractor(_.isServerError)
  /** Used to pattern match [[Status statuses]] and [[Response responses]] on the `3xx` group. */
  object Redirection extends Extractor(_.isRedirection)
}

/** Represents an HTTP status code, as defined in
  * [[http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1 RFC 2616]].
  *
  * This class and its companion objects provide various extraction helpers to ease pattern matching.
  * For example: {{{
  *   val res: Response[ResponseEntity] = ???
  *
  *   res.status match {
  *     case Status.Success(_) => println("Success")
  *     case _                 => println("Not success")
  *   }
  * }}}
  *
  * It's also possible to pattern match directly on instances of [[Response]], which can be useful when
  * [[Request.map mapping]] on [[Request requests]]: {{{
  *   val res: Request[Response[ResponseEntity]] = ???
  *
  *   res map {
  *     // Match on the 2xx group
  *     case res @ Status.Success(_)       => println("Success: " + res.body.as[String])
  *     // Match on HTTP 500
  *     case Status.InternalServerError(_) => println("Internal server error")
  *     // Match on everything else
  *     case _                             => println("Something else entirely")
  *   }
  * }}}
  *
  * See the [[Status$ companion object]] for known status codes.
  */
case class Status(code: Int) {
  require(code > 0 && code < 600)

  /** Allows instances of [[Status]] to be used as extractors for [[Response]].
    *
    * For example: {{{
    *  val req: Request[Response[ResponseEntity]] = ???
    *
    *  req.map {
    *    case res @ Status.Ok(_) => res.body.as[String]
    *    case Status(status)     => throw new Exception("Unexpected status: " + status)
    *  }
    * }}}
    */
  def unapply[T](res: Response[T]): Option[Status] =
    if(res.status == this) Some(res.status)
    else                   None

  override def toString = code.toString

  /** Checks whether the status is a client error (`4xx`). */
  def isClientError = code >= 400 && code < 500
  /** Checks whether the status is a server error (`5xx`). */
  def isServerError = code >= 500 && code < 600
  /** Checks whether the status is a redirection (`3xx`). */
  def isRedirection = code >= 300 && code < 400
  /** Checks whether the status is a client error (`2xx`). */
  def isSuccess     = code >= 200 && code < 300
  /** Checks whether the status is an error (`4xx` and `5xx`). */
  def isError       = isClientError || isServerError
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy