mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 09:17:43 +03:00
Extract ErrorOps, use liftErr instead of leftMap (#4730)
* Extract ErrorOps, use liftErr instead of leftMap JSON error formatting cleanup CHANGELOG_BEGIN CHANGELOG_END * Good we have tests for this stuff * Apply https://github.com/scala/bug/issues/3664 work-around, so JsonError can be used instead of JsonError.apply * error formatting
This commit is contained in:
parent
9c414f3fed
commit
d93e4382f6
@ -25,7 +25,6 @@ import com.digitalasset.util.ExceptionOps._
|
||||
import com.typesafe.scalalogging.StrictLogging
|
||||
import scalaz.std.scalaFuture._
|
||||
import scalaz.syntax.bitraverse._
|
||||
import scalaz.syntax.show._
|
||||
import scalaz.syntax.std.option._
|
||||
import scalaz.syntax.traverse._
|
||||
import scalaz.{-\/, Bitraverse, EitherT, NonEmptyList, Show, \/, \/-}
|
||||
@ -51,6 +50,7 @@ class Endpoints(
|
||||
extends StrictLogging {
|
||||
|
||||
import Endpoints._
|
||||
import util.ErrorOps._
|
||||
import json.JsonProtocol._
|
||||
|
||||
lazy val all: PartialFunction[HttpRequest, Future[HttpResponse]] = {
|
||||
@ -70,16 +70,14 @@ class Endpoints(
|
||||
(jwt, jwtPayload, reqBody) = t3
|
||||
|
||||
cmd <- either(
|
||||
decoder
|
||||
.decodeR[domain.CreateCommand](reqBody)
|
||||
.leftMap(e => InvalidUserInput(e.shows))
|
||||
decoder.decodeR[domain.CreateCommand](reqBody).liftErr(InvalidUserInput)
|
||||
): ET[domain.CreateCommand[lav1.value.Record]]
|
||||
|
||||
ac <- eitherT(
|
||||
handleFutureFailure(commandService.create(jwt, jwtPayload, cmd))
|
||||
): ET[domain.ActiveContract[lav1.value.Value]]
|
||||
|
||||
jsVal <- either(encoder.encodeV(ac).leftMap(e => ServerError(e.shows))): ET[JsValue]
|
||||
jsVal <- either(encoder.encodeV(ac).liftErr(ServerError)): ET[JsValue]
|
||||
|
||||
} yield domain.OkResponse(jsVal)
|
||||
|
||||
@ -90,9 +88,7 @@ class Endpoints(
|
||||
(jwt, jwtPayload, reqBody) = t3
|
||||
|
||||
cmd <- either(
|
||||
decoder
|
||||
.decodeExerciseCommand(reqBody)
|
||||
.leftMap(e => InvalidUserInput(e.shows))
|
||||
decoder.decodeExerciseCommand(reqBody).liftErr(InvalidUserInput)
|
||||
): ET[domain.ExerciseCommand[LfValue, domain.ContractLocator[LfValue]]]
|
||||
|
||||
resolvedRef <- eitherT(
|
||||
@ -124,9 +120,7 @@ class Endpoints(
|
||||
_ = logger.debug(s"/v1/fetch reqBody: $reqBody")
|
||||
|
||||
cl <- either(
|
||||
decoder
|
||||
.decodeContractLocator(reqBody)
|
||||
.leftMap(e => InvalidUserInput(e.shows))
|
||||
decoder.decodeContractLocator(reqBody).liftErr(InvalidUserInput)
|
||||
): ET[domain.ContractLocator[LfValue]]
|
||||
|
||||
_ = logger.debug(s"/v1/fetch cl: $cl")
|
||||
@ -136,7 +130,7 @@ class Endpoints(
|
||||
): ET[Option[domain.ActiveContract[LfValue]]]
|
||||
|
||||
jsVal <- either(
|
||||
ac.cata(x => lfAcToJsValue(x).leftMap(e => ServerError(e.shows)), \/-(JsNull))
|
||||
ac.cata(x => lfAcToJsValue(x), \/-(JsNull))
|
||||
): ET[JsValue]
|
||||
|
||||
} yield domain.OkResponse(jsVal)
|
||||
@ -163,7 +157,7 @@ class Endpoints(
|
||||
case (jwt, jwtPayload, reqBody) =>
|
||||
SprayJson
|
||||
.decode[domain.GetActiveContractsRequest](reqBody)
|
||||
.leftMap(e => InvalidUserInput(e.shows))
|
||||
.liftErr(InvalidUserInput)
|
||||
.map { cmd =>
|
||||
val result: SearchResult[ContractsService.Error \/ domain.ActiveContract[JsValue]] =
|
||||
contractsService
|
||||
@ -193,9 +187,7 @@ class Endpoints(
|
||||
(jwt, _, reqBody) = t3
|
||||
|
||||
cmd <- either(
|
||||
SprayJson
|
||||
.decode[NonEmptyList[domain.Party]](reqBody)
|
||||
.leftMap(e => InvalidUserInput(e.shows))
|
||||
SprayJson.decode[NonEmptyList[domain.Party]](reqBody).liftErr(InvalidUserInput)
|
||||
): ET[NonEmptyList[domain.Party]]
|
||||
|
||||
ps <- eitherT(
|
||||
@ -212,7 +204,7 @@ class Endpoints(
|
||||
} yield result
|
||||
|
||||
private def handleFutureFailure[A: Show, B](fa: Future[A \/ B]): Future[ServerError \/ B] =
|
||||
fa.map(a => a.leftMap(e => ServerError(e.shows))).recover {
|
||||
fa.map(_.liftErr(ServerError)).recover {
|
||||
case NonFatal(e) =>
|
||||
logger.error("Future failed", e)
|
||||
-\/(ServerError(e.description))
|
||||
@ -227,7 +219,7 @@ class Endpoints(
|
||||
|
||||
private def handleSourceFailure[E: Show, A]: Flow[E \/ A, ServerError \/ A, NotUsed] =
|
||||
Flow
|
||||
.fromFunction((_: E \/ A).leftMap(e => ServerError(e.shows)))
|
||||
.fromFunction((_: E \/ A).liftErr(ServerError))
|
||||
.recover {
|
||||
case NonFatal(e) =>
|
||||
logger.error("Source failed", e)
|
||||
@ -316,6 +308,7 @@ class Endpoints(
|
||||
}
|
||||
|
||||
object Endpoints {
|
||||
import util.ErrorOps._
|
||||
import json.JsonProtocol._
|
||||
|
||||
private type ET[A] = EitherT[Future, Error, A]
|
||||
@ -325,14 +318,13 @@ object Endpoints {
|
||||
private type LfValue = lf.value.Value[lf.value.Value.AbsoluteContractId]
|
||||
|
||||
private def apiValueToLfValue(a: ApiValue): Error \/ LfValue =
|
||||
ApiValueToLfValueConverter.apiValueToLfValue(a).leftMap(e => ServerError(e.shows))
|
||||
ApiValueToLfValueConverter.apiValueToLfValue(a).liftErr(ServerError)
|
||||
|
||||
private def lfValueToJsValue(a: LfValue): Error \/ JsValue =
|
||||
\/.fromTryCatchNonFatal(LfValueCodec.apiValueToJsValue(a)).leftMap(e =>
|
||||
ServerError(e.description))
|
||||
\/.fromTryCatchNonFatal(LfValueCodec.apiValueToJsValue(a)).liftErr(ServerError)
|
||||
|
||||
private def lfValueToApiValue(a: LfValue): Error \/ ApiValue =
|
||||
JsValueToApiValueConverter.lfValueToApiValue(a).leftMap(e => ServerError(e.shows))
|
||||
JsValueToApiValueConverter.lfValueToApiValue(a).liftErr(ServerError)
|
||||
|
||||
@SuppressWarnings(Array("org.wartremover.warts.Any"))
|
||||
private def lfAcToJsValue(a: domain.ActiveContract[LfValue]): Error \/ JsValue = {
|
||||
@ -348,8 +340,9 @@ object Endpoints {
|
||||
else domain.OkResponse(parties, Some(domain.UnknownParties(unknownParties)))
|
||||
}
|
||||
|
||||
private def toJsValue[A: JsonWriter](a: A): Error \/ JsValue =
|
||||
SprayJson.encode(a).leftMap(e => ServerError(e.shows))
|
||||
private def toJsValue[A: JsonWriter](a: A): Error \/ JsValue = {
|
||||
SprayJson.encode(a).liftErr(ServerError)
|
||||
}
|
||||
|
||||
@SuppressWarnings(Array("org.wartremover.warts.Any"))
|
||||
private def toJsValueWithBitraverse[F[_, _], A, B](fab: F[A, B])(
|
||||
@ -357,11 +350,6 @@ object Endpoints {
|
||||
ev2: JsonWriter[F[JsValue, JsValue]],
|
||||
ev3: JsonWriter[A],
|
||||
ev4: JsonWriter[B]): Error \/ JsValue =
|
||||
for {
|
||||
fjj <- fab.bitraverse(
|
||||
a => toJsValue(a),
|
||||
b => toJsValue(b)
|
||||
): Error \/ F[JsValue, JsValue]
|
||||
jsVal <- toJsValue(fjj)
|
||||
} yield jsVal
|
||||
SprayJson.encode2(fab).liftErr(ServerError)
|
||||
|
||||
}
|
||||
|
@ -3,27 +3,16 @@
|
||||
|
||||
package com.digitalasset.http
|
||||
|
||||
import akka.http.scaladsl.model.{
|
||||
ContentTypes,
|
||||
HttpEntity,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
HttpResponse,
|
||||
StatusCode,
|
||||
StatusCodes,
|
||||
Uri
|
||||
}
|
||||
import akka.http.scaladsl.model._
|
||||
import akka.util.ByteString
|
||||
import com.digitalasset.http.domain.JwtPayload
|
||||
import com.digitalasset.http.json.{ResponseFormats, SprayJson}
|
||||
import com.digitalasset.ledger.api.refinements.{ApiTypes => lar}
|
||||
import com.digitalasset.http.json.ResponseFormats
|
||||
import com.digitalasset.jwt.domain.{DecodedJwt, Jwt}
|
||||
import spray.json.{JsObject, JsValue}
|
||||
import scalaz.{-\/, Show, \/}
|
||||
import scalaz.syntax.std.option._
|
||||
import scalaz.syntax.show._
|
||||
import com.digitalasset.http.json.JsonProtocol._
|
||||
import com.digitalasset.ledger.api.auth.AuthServiceJWTCodec
|
||||
import com.digitalasset.ledger.api.refinements.{ApiTypes => lar}
|
||||
import scalaz.syntax.std.option._
|
||||
import scalaz.{-\/, Show, \/}
|
||||
import spray.json.{JsArray, JsString, JsValue}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
@ -59,18 +48,19 @@ object EndpointsCompanion {
|
||||
httpResponse(StatusCodes.OK, ResponseFormats.resultJsObject(data))
|
||||
|
||||
private[http] def httpResponseError(error: Error): HttpResponse = {
|
||||
val (status, jsObject) = errorsJsObject(error)
|
||||
httpResponse(status, jsObject)
|
||||
import com.digitalasset.http.json.JsonProtocol._
|
||||
val resp = errorResponse(error)
|
||||
httpResponse(resp.status, resp.toJson)
|
||||
}
|
||||
|
||||
private[http] def errorsJsObject(error: Error): (StatusCode, JsObject) = {
|
||||
private[http] def errorResponse(error: Error): domain.ErrorResponse[JsValue] = {
|
||||
val (status, errorMsg): (StatusCode, String) = error match {
|
||||
case InvalidUserInput(e) => StatusCodes.BadRequest -> e
|
||||
case ServerError(e) => StatusCodes.InternalServerError -> e
|
||||
case Unauthorized(e) => StatusCodes.Unauthorized -> e
|
||||
case NotFound(e) => StatusCodes.NotFound -> e
|
||||
}
|
||||
(status, ResponseFormats.errorsJsObject(status, errorMsg))
|
||||
domain.ErrorResponse(errors = JsArray(JsString(errorMsg)), status = status)
|
||||
}
|
||||
|
||||
private[http] def httpResponse(status: StatusCode, data: JsValue): HttpResponse = {
|
||||
@ -112,8 +102,4 @@ object EndpointsCompanion {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private[http] def encodeList(as: Seq[JsValue]): ServerError \/ JsValue =
|
||||
SprayJson.encode(as).leftMap(e => ServerError(e.shows))
|
||||
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import json.JsonProtocol.LfValueCodec.{apiValueToJsValue => lfValueToJsValue}
|
||||
import query.ValuePredicate.{LfV, TypeLookup}
|
||||
import com.digitalasset.jwt.domain.Jwt
|
||||
import com.typesafe.scalalogging.LazyLogging
|
||||
import scalaz.{-\/, Liskov, NonEmptyList, Show, \/, \/-}
|
||||
import scalaz.{Liskov, NonEmptyList}
|
||||
import Liskov.<~<
|
||||
import com.digitalasset.http.query.ValuePredicate
|
||||
import scalaz.syntax.bifunctor._
|
||||
@ -28,13 +28,15 @@ import scalaz.syntax.traverse._
|
||||
import scalaz.std.map._
|
||||
import scalaz.std.set._
|
||||
import scalaz.std.tuple._
|
||||
import scalaz.{-\/, Show, \/, \/-}
|
||||
import scalaz.{-\/, \/, \/-}
|
||||
import spray.json.{JsObject, JsString, JsTrue, JsValue}
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
object WebSocketService {
|
||||
import util.ErrorOps._
|
||||
|
||||
private type CompiledQueries = Map[domain.TemplateId.RequiredPkg, LfV => Boolean]
|
||||
|
||||
private type StreamPredicate[+Positive] = (
|
||||
@ -46,11 +48,6 @@ object WebSocketService {
|
||||
val heartBeat: String = JsObject("heartbeat" -> JsString("ping")).compactPrint
|
||||
private val liveMarker = JsObject("live" -> JsTrue)
|
||||
|
||||
private implicit final class `\\/ WSS extras`[L, R](private val self: L \/ R) extends AnyVal {
|
||||
def liftErr[M](f: String => M)(implicit L: Show[L]): M \/ R =
|
||||
self leftMap (e => f(e.shows))
|
||||
}
|
||||
|
||||
private final case class StepAndErrors[+Pos, +LfV](
|
||||
errors: Seq[ServerError],
|
||||
step: ContractStreamStep[domain.ArchivedContract, (domain.ActiveContract[LfV], Pos)]) {
|
||||
@ -242,6 +239,7 @@ class WebSocketService(
|
||||
extends LazyLogging {
|
||||
|
||||
import WebSocketService._
|
||||
import util.ErrorOps._
|
||||
import com.digitalasset.http.json.JsonProtocol._
|
||||
|
||||
private val numConns = new java.util.concurrent.atomic.AtomicInteger(0)
|
||||
|
@ -8,7 +8,6 @@ import com.digitalasset.http.domain.HasTemplateId
|
||||
import com.digitalasset.http.{PackageService, domain}
|
||||
import com.digitalasset.ledger.api.{v1 => lav1}
|
||||
import scalaz.syntax.bitraverse._
|
||||
import scalaz.syntax.show._
|
||||
import scalaz.syntax.std.option._
|
||||
import scalaz.syntax.traverse._
|
||||
import scalaz.{Traverse, \/, \/-}
|
||||
@ -25,12 +24,14 @@ class DomainJsonDecoder(
|
||||
jsValueToApiValue: (domain.LfType, JsValue) => JsonError \/ lav1.value.Value,
|
||||
jsValueToLfValue: (domain.LfType, JsValue) => JsonError \/ domain.LfValue) {
|
||||
|
||||
import com.digitalasset.http.util.ErrorOps._
|
||||
|
||||
def decodeR[F[_]](a: String)(
|
||||
implicit ev1: JsonReader[F[JsObject]],
|
||||
ev2: Traverse[F],
|
||||
ev3: domain.HasTemplateId[F]): JsonError \/ F[lav1.value.Record] =
|
||||
for {
|
||||
b <- SprayJson.parse(a).leftMap(e => JsonError(e.shows))
|
||||
b <- SprayJson.parse(a).liftErr(JsonError)
|
||||
c <- SprayJson.mustBeJsObject(b)
|
||||
d <- decodeR(c)
|
||||
} yield d
|
||||
@ -40,7 +41,7 @@ class DomainJsonDecoder(
|
||||
ev2: Traverse[F],
|
||||
ev3: domain.HasTemplateId[F]): JsonError \/ F[lav1.value.Record] =
|
||||
for {
|
||||
b <- SprayJson.decode[F[JsObject]](a)(ev1).leftMap(e => JsonError(e.shows))
|
||||
b <- SprayJson.decode[F[JsObject]](a)(ev1).liftErr(JsonError)
|
||||
c <- decodeUnderlyingRecords(b)
|
||||
} yield c
|
||||
|
||||
@ -58,7 +59,7 @@ class DomainJsonDecoder(
|
||||
ev2: Traverse[F],
|
||||
ev3: domain.HasTemplateId[F]): JsonError \/ F[lav1.value.Value] =
|
||||
for {
|
||||
b <- SprayJson.parse(a).leftMap(e => JsonError(e.shows))
|
||||
b <- SprayJson.parse(a).liftErr(JsonError)
|
||||
d <- decodeV(b)
|
||||
} yield d
|
||||
|
||||
@ -67,7 +68,7 @@ class DomainJsonDecoder(
|
||||
ev2: Traverse[F],
|
||||
ev3: domain.HasTemplateId[F]): JsonError \/ F[lav1.value.Value] =
|
||||
for {
|
||||
b <- SprayJson.decode[F[JsValue]](a)(ev1).leftMap(e => JsonError(e.shows))
|
||||
b <- SprayJson.decode[F[JsValue]](a)(ev1).liftErr(JsonError)
|
||||
c <- decodeUnderlyingValues(b)
|
||||
} yield c
|
||||
|
||||
@ -94,19 +95,17 @@ class DomainJsonDecoder(
|
||||
val templateId: domain.TemplateId.OptionalPkg = H.templateId(fa)
|
||||
for {
|
||||
tId <- resolveTemplateId(templateId).toRightDisjunction(
|
||||
JsonError(s"DomainJsonDecoder_lookupLfType: ${cannotResolveTemplateId(templateId)}"))
|
||||
JsonError(s"DomainJsonDecoder_lookupLfType ${cannotResolveTemplateId(templateId)}"))
|
||||
lfType <- H
|
||||
.lfType(fa, tId, resolveTemplateRecordType, resolveRecordType, resolveKey)
|
||||
.leftMap(e => JsonError("DomainJsonDecoder_lookupLfType " + e.shows))
|
||||
.liftErrS("DomainJsonDecoder_lookupLfType")(JsonError)
|
||||
} yield lfType
|
||||
}
|
||||
|
||||
def decodeContractLocator(a: String)(implicit ev: JsonReader[domain.ContractLocator[JsValue]])
|
||||
: JsonError \/ domain.ContractLocator[domain.LfValue] =
|
||||
for {
|
||||
b <- SprayJson
|
||||
.parse(a)
|
||||
.leftMap(e => JsonError("DomainJsonDecoder_decodeContractLocator " + e.shows))
|
||||
b <- SprayJson.parse(a).liftErrS("DomainJsonDecoder_decodeContractLocator")(JsonError)
|
||||
c <- decodeContractLocator(b)
|
||||
} yield c
|
||||
|
||||
@ -114,7 +113,7 @@ class DomainJsonDecoder(
|
||||
: JsonError \/ domain.ContractLocator[domain.LfValue] =
|
||||
SprayJson
|
||||
.decode[domain.ContractLocator[JsValue]](a)
|
||||
.leftMap(e => JsonError("DomainJsonDecoder_decodeContractLocator " + e.shows))
|
||||
.liftErrS("DomainJsonDecoder_decodeContractLocator")(JsonError)
|
||||
.flatMap(decodeContractLocatorUnderlyingValue)
|
||||
|
||||
private def decodeContractLocatorUnderlyingValue(
|
||||
@ -130,9 +129,7 @@ class DomainJsonDecoder(
|
||||
implicit ev1: JsonReader[domain.ExerciseCommand[JsValue, domain.ContractLocator[JsValue]]])
|
||||
: JsonError \/ domain.ExerciseCommand[domain.LfValue, domain.ContractLocator[domain.LfValue]] =
|
||||
for {
|
||||
b <- SprayJson
|
||||
.parse(a)
|
||||
.leftMap(e => JsonError("DomainJsonDecoder_decodeExerciseCommand " + e.shows))
|
||||
b <- SprayJson.parse(a).liftErrS("DomainJsonDecoder_decodeExerciseCommand")(JsonError)
|
||||
c <- decodeExerciseCommand(b)
|
||||
} yield c
|
||||
|
||||
@ -143,7 +140,7 @@ class DomainJsonDecoder(
|
||||
for {
|
||||
cmd0 <- SprayJson
|
||||
.decode[domain.ExerciseCommand[JsValue, domain.ContractLocator[JsValue]]](a)
|
||||
.leftMap(e => JsonError("DomainJsonDecoder_decodeExerciseCommand " + e.shows))
|
||||
.liftErrS("DomainJsonDecoder_decodeExerciseCommand")(JsonError)
|
||||
|
||||
lfType <- lookupLfType[domain.ExerciseCommand[+?, domain.ContractLocator[_]]](cmd0)(
|
||||
domain.ExerciseCommand.hasTemplateId)
|
||||
|
@ -5,7 +5,6 @@ package com.digitalasset.http.json
|
||||
|
||||
import com.digitalasset.http.domain
|
||||
import com.digitalasset.ledger.api.{v1 => lav1}
|
||||
import scalaz.syntax.show._
|
||||
import scalaz.syntax.traverse._
|
||||
import scalaz.syntax.bitraverse._
|
||||
import scalaz.{Traverse, \/}
|
||||
@ -17,12 +16,14 @@ class DomainJsonEncoder(
|
||||
apiRecordToJsObject: lav1.value.Record => JsonError \/ JsObject,
|
||||
apiValueToJsValue: lav1.value.Value => JsonError \/ JsValue) {
|
||||
|
||||
import com.digitalasset.http.util.ErrorOps._
|
||||
|
||||
def encodeR[F[_]](fa: F[lav1.value.Record])(
|
||||
implicit ev1: Traverse[F],
|
||||
ev2: JsonWriter[F[JsObject]]): JsonError \/ JsObject =
|
||||
for {
|
||||
a <- encodeUnderlyingRecord(fa)
|
||||
b <- SprayJson.encode[F[JsObject]](a)(ev2).leftMap(e => JsonError(e.shows))
|
||||
b <- SprayJson.encode[F[JsObject]](a)(ev2).liftErr(JsonError)
|
||||
c <- SprayJson.mustBeJsObject(b)
|
||||
} yield c
|
||||
|
||||
@ -36,7 +37,7 @@ class DomainJsonEncoder(
|
||||
ev2: JsonWriter[F[JsValue]]): JsonError \/ JsValue =
|
||||
for {
|
||||
a <- encodeUnderlyingValue(fa)
|
||||
b <- SprayJson.encode[F[JsValue]](a)(ev2).leftMap(e => JsonError(e.shows))
|
||||
b <- SprayJson.encode[F[JsValue]](a)(ev2).liftErr(JsonError)
|
||||
} yield b
|
||||
|
||||
// encode underlying values
|
||||
@ -55,7 +56,7 @@ class DomainJsonEncoder(
|
||||
ref => encodeContractLocatorUnderlyingValue(ref)
|
||||
)
|
||||
|
||||
y <- SprayJson.encode(x).leftMap(e => JsonError(e.shows))
|
||||
y <- SprayJson.encode(x).liftErr(JsonError)
|
||||
|
||||
} yield y
|
||||
|
||||
|
@ -3,31 +3,33 @@
|
||||
|
||||
package com.digitalasset.http.json
|
||||
|
||||
import JsonProtocol.LfValueCodec
|
||||
import com.digitalasset.daml.lf
|
||||
import com.digitalasset.daml.lf.iface
|
||||
import com.digitalasset.http.domain
|
||||
import com.digitalasset.http.json.JsValueToApiValueConverter.LfTypeLookup
|
||||
import com.digitalasset.http.json.JsonProtocol.LfValueCodec
|
||||
import com.digitalasset.ledger.api.{v1 => lav1}
|
||||
import com.digitalasset.platform.participant.util.LfEngineToApi
|
||||
import scalaz.std.string._
|
||||
import scalaz.{-\/, \/, \/-}
|
||||
import spray.json.{JsObject, JsValue}
|
||||
|
||||
class JsValueToApiValueConverter(lfTypeLookup: LfTypeLookup) {
|
||||
import com.digitalasset.http.util.ErrorOps._
|
||||
|
||||
def jsValueToLfValue(
|
||||
lfId: lf.data.Ref.Identifier,
|
||||
jsValue: JsValue): JsonError \/ lf.value.Value[lf.value.Value.AbsoluteContractId] =
|
||||
\/.fromTryCatchNonFatal(
|
||||
LfValueCodec.jsValueToApiValue(jsValue, lfId, lfTypeLookup)
|
||||
).leftMap(JsonError.toJsonError)
|
||||
).liftErr(JsonError)
|
||||
|
||||
def jsValueToLfValue(
|
||||
lfType: iface.Type,
|
||||
jsValue: JsValue): JsonError \/ lf.value.Value[lf.value.Value.AbsoluteContractId] =
|
||||
\/.fromTryCatchNonFatal(
|
||||
LfValueCodec.jsValueToApiValue(jsValue, lfType, lfTypeLookup)
|
||||
).leftMap(JsonError.toJsonError)
|
||||
).liftErr(JsonError)
|
||||
|
||||
def jsValueToApiValue(lfType: domain.LfType, jsValue: JsValue): JsonError \/ lav1.value.Value =
|
||||
for {
|
||||
@ -50,9 +52,10 @@ class JsValueToApiValueConverter(lfTypeLookup: LfTypeLookup) {
|
||||
}
|
||||
|
||||
object JsValueToApiValueConverter {
|
||||
import com.digitalasset.http.util.ErrorOps._
|
||||
|
||||
type LfTypeLookup = lf.data.Ref.Identifier => Option[lf.iface.DefDataType.FWT]
|
||||
|
||||
def lfValueToApiValue(lfValue: domain.LfValue): JsonError \/ lav1.value.Value =
|
||||
\/.fromEither(LfEngineToApi.lfValueToApiValue(verbose = true, lfValue))
|
||||
.leftMap(JsonError.toJsonError)
|
||||
\/.fromEither(LfEngineToApi.lfValueToApiValue(verbose = true, lfValue)).liftErr(JsonError)
|
||||
}
|
||||
|
@ -3,19 +3,11 @@
|
||||
|
||||
package com.digitalasset.http.json
|
||||
|
||||
import com.digitalasset.util.ExceptionOps._
|
||||
import scalaz.Show
|
||||
import scalaz.syntax.show._
|
||||
|
||||
final case class JsonError(message: String)
|
||||
|
||||
object JsonError {
|
||||
def toJsonError(e: String) = JsonError(e)
|
||||
|
||||
def toJsonError[E: Show](e: E) = JsonError(e.shows)
|
||||
|
||||
def toJsonError(e: Throwable) = JsonError(e.description)
|
||||
|
||||
object JsonError extends (String => JsonError) {
|
||||
implicit val ShowInstance: Show[JsonError] = Show shows { f =>
|
||||
s"JsonError: ${f.message}"
|
||||
}
|
||||
|
@ -72,6 +72,25 @@ object SprayJson {
|
||||
\/.fromTryCatchNonFatal(a.toJson).leftMap(e => JsonWriterError(a, e.description))
|
||||
}
|
||||
|
||||
def encode1[F[_], A](fa: F[A])(
|
||||
implicit ev1: JsonWriter[F[JsValue]],
|
||||
ev2: Traverse[F],
|
||||
ev3: JsonWriter[A]): JsonWriterError \/ JsValue =
|
||||
for {
|
||||
fj <- fa.traverse(encode[A](_))
|
||||
jsVal <- encode[F[JsValue]](fj)
|
||||
} yield jsVal
|
||||
|
||||
def encode2[F[_, _], A, B](fab: F[A, B])(
|
||||
implicit ev1: JsonWriter[F[JsValue, JsValue]],
|
||||
ev2: Bitraverse[F],
|
||||
ev3: JsonWriter[A],
|
||||
ev4: JsonWriter[B]): JsonWriterError \/ JsValue =
|
||||
for {
|
||||
fjj <- fab.bitraverse(encode[A](_), encode[B](_))
|
||||
jsVal <- encode[F[JsValue, JsValue]](fjj)
|
||||
} yield jsVal
|
||||
|
||||
def mustBeJsObject(a: JsValue): JsonError \/ JsObject = a match {
|
||||
case b: JsObject => \/-(b)
|
||||
case _ => -\/(JsonError(s"Expected JsObject, got: ${a: JsValue}"))
|
||||
|
@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2020 The DAML Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.digitalasset.http.util
|
||||
|
||||
import com.digitalasset.util.ExceptionOps
|
||||
import scalaz.syntax.show._
|
||||
import scalaz.{Show, \/}
|
||||
|
||||
object ErrorOps {
|
||||
|
||||
implicit final class `\\/ WSS extras throwable`[R](private val self: Throwable \/ R)
|
||||
extends AnyVal {
|
||||
def liftErr[M](f: String => M): M \/ R =
|
||||
self leftMap (e => f(ExceptionOps.getDescription(e)))
|
||||
}
|
||||
|
||||
implicit final class `\\/ WSS extras`[L, R](private val self: L \/ R) extends AnyVal {
|
||||
def liftErr[M](f: String => M)(implicit L: Show[L]): M \/ R =
|
||||
self leftMap (e => f(e.shows))
|
||||
|
||||
def liftErrS[M](msg: String)(f: String => M)(implicit L: Show[L]): M \/ R =
|
||||
liftErr(x => f(msg + " " + x))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user