Skip to content

Commit

Permalink
Add validation to status code
Browse files Browse the repository at this point in the history
  • Loading branch information
adamw committed Oct 24, 2019
1 parent cf79730 commit 0dec944
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 2 deletions.
1 change: 1 addition & 0 deletions .adr-dir
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docs/adr
26 changes: 26 additions & 0 deletions docs/adr/0002-http-model-conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# 2. HTTP model conventions

Date: 2019-10-24

## Context

The classes which form the HTTP model (in the `sttp.model` package) vary in the conventions they use for error-handling
and the parsing interface they offer.

## Decision

We want to unify the behavior of the HTTP model classes so that they work in a predictable and similar way.
The conventions are:

* `.toString` returns a representation of the model class in a format as in an HTTP request/response. For example,
for an uri this will be `http://...`, for a header `[name]: [value]`, etc.
* constructors of the model classes are private; instances should be created through methods on the companion objects.
* `[SthCompanionObject].parse(serialized: String): Either[String, Sth]`: returns an error message or an instance of
the model class
* `[SthCompanionObject].apply(values)`: creates an instance of the model class; validates the input values and in case
of an error, *throws an exception*. An error could be e.g. that the input values contain characters outside of
the allowed range
* `[SthCompanionObject].validated(...): Either[String, Sth]`: same as above, but doesn't throw exceptions. Instead,
returns an error message or the model class instance
* `[SthCompanionObject].notValidated(...): Sth`: creates the model type, without validation, and without throwing
exceptions
11 changes: 9 additions & 2 deletions model/shared/src/main/scala/sttp/model/StatusCode.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package sttp.model

case class StatusCode(code: Int) extends AnyVal {
class StatusCode private (val code: Int) extends AnyVal {
def isInformational: Boolean = code / 100 == 1
def isSuccess: Boolean = code / 100 == 2
def isRedirect: Boolean = code / 100 == 3
Expand All @@ -10,7 +10,14 @@ case class StatusCode(code: Int) extends AnyVal {
override def toString: String = code.toString
}

object StatusCode extends StatusCodes
object StatusCode extends StatusCodes {
def apply(code: Int): StatusCode = validated(code).fold(e => throw new IllegalArgumentException(e), identity)
def validated(code: Int): Either[String, StatusCode] = {
if (code < 100 || code > 599) Left(s"Status code outside of the allowed range 100-599: $code")
else Right(new StatusCode(code))
}
def notValidated(code: Int) = new StatusCode(code)
}

// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
trait StatusCodes {
Expand Down
18 changes: 18 additions & 0 deletions model/shared/src/test/scala/sttp/model/StatusCodeTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package sttp.model

import org.scalatest.{FlatSpec, Matchers}

class StatusCodeTests extends FlatSpec with Matchers {
it should "return a string description of the status code" in {
StatusCode.Accepted.toString shouldBe "202"
}

it should "validate status codes" in {
StatusCode.validated(8) shouldBe 'left
StatusCode.validated(200) shouldBe Right(StatusCode.Ok)
}

it should "throw exceptions on invalid status codes" in {
an[IllegalArgumentException] shouldBe thrownBy(StatusCode(8))
}
}

0 comments on commit 0dec944

Please sign in to comment.