diff options
author | Jakob Odersky <jakob@driver.xyz> | 2018-08-22 12:51:36 -0700 |
---|---|---|
committer | Jakob Odersky <jakob@driver.xyz> | 2018-09-12 14:17:39 -0700 |
commit | 5ec270aa98b806f32338fa25357abdf45dd0625b (patch) | |
tree | f1423f8add00cc2f899d2f8259b9ab33ba3c914b /src/main/scala/xyz/driver/core/json.scala | |
parent | 3eb6a9e96bd8bf111490f390ea94a1c6d7677eff (diff) | |
download | driver-core-5ec270aa98b806f32338fa25357abdf45dd0625b.tar.gz driver-core-5ec270aa98b806f32338fa25357abdf45dd0625b.tar.bz2 driver-core-5ec270aa98b806f32338fa25357abdf45dd0625b.zip |
Trait-based initialization and other utilities
Adds the concept of a 'platform', a centralized place in which
environment-specific information will be managed, and provides common
initialization logic for most "standard" apps.
As part of the common initialization, other parts of core have also
been reworked:
- HTTP-related unmarshallers and path matchers have been factored out
from core.json to a new core.rest.directives package (core.json
extends those unmarshallers and matchers for backwards
compatibility)
- CORS handling has also been moved to a dedicated utility trait
- Some custom headers have been moved from raw headers to typed ones
in core.rest.headers
- The concept of a "reporter" has been introduced. A reporter is a
context-aware combination of tracing and logging. It is intended to
issue diagnostic messages that can be traced across service
boundaries.
Closes #192
Closes #195
Diffstat (limited to 'src/main/scala/xyz/driver/core/json.scala')
-rw-r--r-- | src/main/scala/xyz/driver/core/json.scala | 80 |
1 files changed, 2 insertions, 78 deletions
diff --git a/src/main/scala/xyz/driver/core/json.scala b/src/main/scala/xyz/driver/core/json.scala index d9319e9..4daf127 100644 --- a/src/main/scala/xyz/driver/core/json.scala +++ b/src/main/scala/xyz/driver/core/json.scala @@ -5,10 +5,6 @@ import java.time.format.DateTimeFormatter import java.time.{Instant, LocalDate} import java.util.{TimeZone, UUID} -import akka.http.scaladsl.marshalling.{Marshaller, Marshalling} -import akka.http.scaladsl.model.Uri.Path -import akka.http.scaladsl.server.PathMatcher.{Matched, Unmatched} -import akka.http.scaladsl.server._ import akka.http.scaladsl.unmarshalling.Unmarshaller import com.neovisionaries.i18n.{CountryCode, CurrencyCode} import enumeratum._ @@ -19,6 +15,7 @@ import spray.json._ import xyz.driver.core.auth.AuthCredentials import xyz.driver.core.date.{Date, DayOfWeek, Month} import xyz.driver.core.domain.{Email, PhoneNumber} +import xyz.driver.core.rest.directives.{PathMatchers, Unmarshallers} import xyz.driver.core.rest.errors._ import xyz.driver.core.time.{Time, TimeOfDay} @@ -27,25 +24,9 @@ import scala.reflect.{ClassTag, classTag} import scala.util.Try import scala.util.control.NonFatal -object json { +object json extends PathMatchers with Unmarshallers { import DefaultJsonProtocol._ - private def UuidInPath[T]: PathMatcher1[Id[T]] = - PathMatchers.JavaUUID.map((id: UUID) => Id[T](id.toString.toLowerCase)) - - def IdInPath[T]: PathMatcher1[Id[T]] = UuidInPath[T] | new PathMatcher1[Id[T]] { - def apply(path: Path) = path match { - case Path.Segment(segment, tail) => Matched(tail, Tuple1(Id[T](segment))) - case _ => Unmatched - } - } - - implicit def paramUnmarshaller[T](implicit reader: JsonReader[T]): Unmarshaller[String, T] = - Unmarshaller.firstOf( - Unmarshaller.strict((JsString(_: String)) andThen reader.read), - stringToValueUnmarshaller[T] - ) - implicit def idFormat[T]: RootJsonFormat[Id[T]] = new RootJsonFormat[Id[T]] { def write(id: Id[T]) = JsString(id.value) @@ -67,13 +48,6 @@ object json { override def read(json: JsValue): F @@ T = transformReadValue(underlying.read(json)) } - def NameInPath[T]: PathMatcher1[Name[T]] = new PathMatcher1[Name[T]] { - def apply(path: Path) = path match { - case Path.Segment(segment, tail) => Matched(tail, Tuple1(Name[T](segment))) - case _ => Unmatched - } - } - implicit def nameFormat[T] = new RootJsonFormat[Name[T]] { def write(name: Name[T]) = JsString(name.value) @@ -83,26 +57,6 @@ object json { } } - def TimeInPath: PathMatcher1[Time] = InstantInPath.map(instant => Time(instant.toEpochMilli)) - - private def timestampInPath: PathMatcher1[Long] = - PathMatcher("""[+-]?\d*""".r) flatMap { string => - try Some(string.toLong) - catch { case _: IllegalArgumentException => None } - } - - def InstantInPath: PathMatcher1[Instant] = - new PathMatcher1[Instant] { - def apply(path: Path): PathMatcher.Matching[Tuple1[Instant]] = path match { - case Path.Segment(head, tail) => - try Matched(tail, Tuple1(Instant.parse(head))) - catch { - case NonFatal(_) => Unmatched - } - case _ => Unmatched - } - } | timestampInPath.map(Instant.ofEpochMilli) - implicit val timeFormat: RootJsonFormat[Time] = new RootJsonFormat[Time] { def write(time: Time) = JsObject("timestamp" -> JsNumber(time.millis)) @@ -194,14 +148,6 @@ object json { } } - def RevisionInPath[T]: PathMatcher1[Revision[T]] = - PathMatcher("""[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}""".r) flatMap { string => - Some(Revision[T](string)) - } - - implicit def revisionFromStringUnmarshaller[T]: Unmarshaller[String, Revision[T]] = - Unmarshaller.strict[String, Revision[T]](Revision[T]) - implicit def revisionFormat[T]: RootJsonFormat[Revision[T]] = new RootJsonFormat[Revision[T]] { def write(revision: Revision[T]) = JsString(revision.id.toString) @@ -413,17 +359,6 @@ object json { } } - def NonEmptyNameInPath[T]: PathMatcher1[NonEmptyName[T]] = new PathMatcher1[NonEmptyName[T]] { - def apply(path: Path) = path match { - case Path.Segment(segment, tail) => - refineV[NonEmpty](segment) match { - case Left(_) => Unmatched - case Right(nonEmptyString) => Matched(tail, Tuple1(NonEmptyName[T](nonEmptyString))) - } - case _ => Unmatched - } - } - implicit def nonEmptyNameFormat[T](implicit nonEmptyStringFormat: JsonFormat[Refined[String, NonEmpty]]) = new RootJsonFormat[NonEmptyName[T]] { def write(name: NonEmptyName[T]) = JsString(name.value.value) @@ -452,15 +387,4 @@ object json { case "DatabaseException" => jsonFormat(DatabaseException, "message") } - val jsValueToStringMarshaller: Marshaller[JsValue, String] = - Marshaller.strict[JsValue, String](value => Marshalling.Opaque[String](() => value.compactPrint)) - - def valueToStringMarshaller[T](implicit jsonFormat: JsonWriter[T]): Marshaller[T, String] = - jsValueToStringMarshaller.compose[T](jsonFormat.write) - - val stringToJsValueUnmarshaller: Unmarshaller[String, JsValue] = - Unmarshaller.strict[String, JsValue](value => value.parseJson) - - def stringToValueUnmarshaller[T](implicit jsonFormat: JsonReader[T]): Unmarshaller[String, T] = - stringToJsValueUnmarshaller.map[T](jsonFormat.read) } |