diff --git a/js/src/main/scala/org/mdedetrich/webmodels/Platform.scala b/js/src/main/scala/org/mdedetrich/webmodels/Platform.scala
new file mode 100644
index 0000000..4e4cc7e
--- /dev/null
+++ b/js/src/main/scala/org/mdedetrich/webmodels/Platform.scala
@@ -0,0 +1,18 @@
+package org.mdedetrich.webmodels
+
+private[webmodels] object Platform {
+
+  /** Note that this only works for non negative int's but since we are using it for HTTP codes it should
+    * be fine
+    * @param digit
+    * @param value
+    * @return
+    */
+  def checkFirstDigitOfInt(digit: Int, value: Int): Boolean = {
+    var x = value
+
+    while (x > 9) x /= 10
+    x == digit
+  }
+
+}
diff --git a/jvm/src/main/scala/org/mdedetrich/webmodels/Platform.scala b/jvm/src/main/scala/org/mdedetrich/webmodels/Platform.scala
new file mode 100644
index 0000000..51986ee
--- /dev/null
+++ b/jvm/src/main/scala/org/mdedetrich/webmodels/Platform.scala
@@ -0,0 +1,44 @@
+package org.mdedetrich.webmodels
+
+private[webmodels] object Platform {
+
+  /** Logic taken for figuring out fast way to calculate first digit
+    * of Int taken using OldCurmudgeon's method is
+    * taken from https://stackoverflow.com/a/18054242. This uses
+    */
+
+  private val limits: Array[Int] = Array[Int](
+    2000000000,
+    Integer.MAX_VALUE,
+    200000000,
+    300000000 - 1,
+    20000000,
+    30000000 - 1,
+    2000000,
+    3000000 - 1,
+    200000,
+    300000 - 1,
+    20000,
+    30000 - 1,
+    2000,
+    3000 - 1,
+    200,
+    300 - 1,
+    20,
+    30 - 1,
+    2,
+    3 - 1
+  )
+
+  def checkFirstDigitOfInt(digit: Int, value: Int): Boolean = {
+    var i = 0
+    while (i < limits.length) {
+      if (value > limits(i + 1)) return false
+      if (value >= limits(i)) return true
+
+      i += digit
+    }
+    false
+  }
+
+}
diff --git a/shared/src/main/scala/org/mdedetrich/webmodels/HttpServiceError.scala b/shared/src/main/scala/org/mdedetrich/webmodels/HttpServiceError.scala
new file mode 100644
index 0000000..fa4e8ad
--- /dev/null
+++ b/shared/src/main/scala/org/mdedetrich/webmodels/HttpServiceError.scala
@@ -0,0 +1,147 @@
+package org.mdedetrich.webmodels
+
+import circe._
+import io.circe._
+import io.circe.syntax._
+
+/** `ResponseContent` provides a convenient abstraction for working with REST'ful HTTP
+  * API's that return RFC3986 Problem in error cases. `ResponseContent` makes the
+  * assumption that the web services that you work with do mainly return RFC3986
+  * Problem however `ResponseContent` also provides fallback data types
+  * (`ResponseContent.JSON`/`ResponseContent.String`) that lets you easily handle
+  * cases where the response of a request isn't a valid Problem JSON (such cases
+  * are not uncommon when you have load balancer's/reverse proxies sitting infront of
+  * webserver's).
+  */
+sealed abstract class ResponseContent extends Product with Serializable {
+
+  /** Checks to see if the [[ResponseContent]] is JSON and contains a JSON field that satisfies a predicate.
+    *
+    * @param field The JSON field to check
+    * @param predicate The predicate
+    * @return Whether the predicate was satisfied. Always returns `false` if the this is a [[ResponseContent.String]]
+    */
+  def checkJsonField(field: String, predicate: Json => Boolean): Boolean =
+    this match {
+      case ResponseContent.Problem(problem) =>
+        problem.asJson.findAllByKey(field).exists(predicate)
+      case ResponseContent.Json(json) =>
+        json
+          .findAllByKey(field)
+          .exists(predicate)
+      case _: ResponseContent.String => false
+    }
+
+  /** A combination of [[checkJsonField]] that also checks if the resulting
+    * JSON field is a String that satisfies a predicate.
+    * @param field The JSON field to look for
+    * @param predicate The predicate to satisfy
+    */
+  def checkJsonFieldAsString(field: String, predicate: String => Boolean): Boolean =
+    checkJsonField(field, _.asString.exists(predicate))
+
+  /** Checks to see if the [[ResponseContent]] contains a specific String, regardless
+    * in what format its stored
+    */
+  def checkString(predicate: String => Boolean): Boolean =
+    this match {
+      case ResponseContent.Problem(problem) =>
+        predicate(problem.asJson.noSpaces)
+      case ResponseContent.Json(json) =>
+        predicate(json.noSpaces)
+      case ResponseContent.String(string) =>
+        predicate(string)
+    }
+}
+
+object ResponseContent {
+
+  /** This case happens if the response of the Http request is a valid Problem according to
+    * RFC7807. This means that the JSON response content is a JSON object that contains the field named `type`
+    * and all other fields (if they exist) satisfy the RFC3986 specification (i.e. the `type` field is
+    * valid URI)
+    * @see https://tools.ietf.org/html/rfc7807
+    */
+  final case class Problem(problem: org.mdedetrich.webmodels.Problem) extends ResponseContent
+
+  /** This case happens if the response of the HTTP request is JSON but it sn't a valid RFC3986 Problem.
+    * This means that either the mandatory `type` field isn't in the JSON response and/or the other fields
+    * specific to Problem don't follow all of the RFC3986 specification (i.e. the `type` field is
+    * not a valid URI)
+    * @see https://tools.ietf.org/html/rfc7159
+    */
+  final case class Json(json: io.circe.Json) extends ResponseContent
+
+  /** This case happens if the body content is not valid JSON according to RFC7159
+    */
+  final case class String(string: java.lang.String) extends ResponseContent
+}
+
+final case class Header(name: String, value: String)
+
+/** The purpose of this data type is to provide a common way of dealing
+  * with errors from REST'ful HTTP APi's making it particularly useful
+  * for strongly typed clients to web services.
+  *
+  * `HttpServiceError` makes no assumptions about what HTTP client you
+  * happen to be using which makes it a great candidate for having a
+  * common error type in projects that have to juggle with
+  * multiple HTTP clients. Since `HttpServiceError` is a trait, it can easily be
+  * extended with existing error types that your library/application may happen
+  * to have.
+  *
+  * Due to the fact that `HttpServiceError` is meant abstract over different HTTP
+  * clients, it exposes methods that provides the minimum necessary data commonly
+  * needed to properly identify errors without exposing too much about the HTTP
+  * client itself. Examples of such methods are `statusCode`, `responseContent`
+  * and `responseHeaders`.
+  */
+trait HttpServiceError {
+
+  /** Type Type of the HttpRequest object from the original Http Client
+    */
+  type HttpRequest
+
+  /** The type of the HttpResponse object from the original Http Client
+    */
+  type HttpResponse
+
+  /** The original request that gave this response
+    */
+  def request: HttpRequest
+
+  /** The original response
+    */
+  def response: HttpResponse
+
+  /** The content of the response represented as a convenient
+    * data type
+    */
+  def responseContent: ResponseContent
+
+  /** The status code of the response
+    */
+  def statusCode: Int
+
+  /** Indicates whether this error is due to a missing resource, i.e. 404 case
+    */
+  def resourceMissingError: Boolean = statusCode.toString.startsWith("404")
+
+  /** Indicates whether this error was caused due to a client error (i.e.
+    * the client is somehow sending a bad request). Retrying such requests
+    * are often pointless.
+    */
+  def clientError: Boolean = Platform.checkFirstDigitOfInt(4, statusCode)
+
+  /** Indicates whether this error was caused due to a server problem.
+    * Such requests are often safe to retry (ideally with an exponential delay)
+    * as long as the request is idempotent.
+    */
+  def serverError: Boolean = Platform.checkFirstDigitOfInt(5, statusCode)
+
+  /** The headers of the response without any alterations made
+    * (i.e. any duplicate fields/ordering should remained untouched
+    * from the original response).
+    */
+  def responseHeaders: IndexedSeq[Header]
+}
diff --git a/shared/src/main/scala/org/mdedetrich/webmodels/circe.scala b/shared/src/main/scala/org/mdedetrich/webmodels/circe.scala
index 337dc1e..8b62a4c 100644
--- a/shared/src/main/scala/org/mdedetrich/webmodels/circe.scala
+++ b/shared/src/main/scala/org/mdedetrich/webmodels/circe.scala
@@ -1,5 +1,7 @@
 package org.mdedetrich.webmodels
 
+import java.net.{URI, URISyntaxException}
+
 import io.circe._
 import io.circe.syntax._