feat(rest): Add common `serialization` utils
This commit is contained in:
parent
40543e3706
commit
d69a0206a7
|
@ -0,0 +1,87 @@
|
||||||
|
import std/[strutils, algorithm, sets, strformat]
|
||||||
|
import chronos, chronos/apps, chronos/unittest2/asynctests, stew/byteutils,
|
||||||
|
metrics,
|
||||||
|
nimcrypto
|
||||||
|
import presto/[route, segpath, server, client]
|
||||||
|
import json_serialization/std/[net, sets],
|
||||||
|
json_serialization/stew/results as jsonSerializationResults,
|
||||||
|
serialization, json_serialization
|
||||||
|
|
||||||
|
const ApplicationJsonMediaType* = MediaType.init("application/json")
|
||||||
|
|
||||||
|
createJsonFlavor RestJson
|
||||||
|
|
||||||
|
RestJson.useDefaultSerializationFor(
|
||||||
|
auto
|
||||||
|
)
|
||||||
|
|
||||||
|
type
|
||||||
|
DecodeTypes* =
|
||||||
|
auto
|
||||||
|
|
||||||
|
type
|
||||||
|
EncodeTypes* =
|
||||||
|
auto
|
||||||
|
|
||||||
|
proc encodeBytes*[T: EncodeTypes](value: T,
|
||||||
|
contentType: string): RestResult[seq[byte]] =
|
||||||
|
case contentType
|
||||||
|
of "application/json":
|
||||||
|
let data =
|
||||||
|
block:
|
||||||
|
try:
|
||||||
|
var stream = memoryOutput()
|
||||||
|
var writer = JsonWriter[RestJson].init(stream)
|
||||||
|
writer.writeValue(value)
|
||||||
|
stream.getOutput(seq[byte])
|
||||||
|
except IOError:
|
||||||
|
return err("Input/output error")
|
||||||
|
except SerializationError:
|
||||||
|
return err("Serialization error")
|
||||||
|
ok(data)
|
||||||
|
else:
|
||||||
|
err("Content-Type not supported")
|
||||||
|
|
||||||
|
proc decodeBytes*[T: DecodeTypes](t: typedesc[T],
|
||||||
|
value: openArray[byte],
|
||||||
|
contentType: Opt[ContentTypeData]
|
||||||
|
): RestResult[T] =
|
||||||
|
|
||||||
|
let mediaType =
|
||||||
|
if contentType.isNone():
|
||||||
|
ApplicationJsonMediaType
|
||||||
|
else:
|
||||||
|
if isWildCard(contentType.get().mediaType):
|
||||||
|
return err("Incorrect Content-Type")
|
||||||
|
contentType.get().mediaType
|
||||||
|
|
||||||
|
if mediaType == ApplicationJsonMediaType:
|
||||||
|
try:
|
||||||
|
ok RestJson.decode(value, T,
|
||||||
|
requireAllFields = true,
|
||||||
|
allowUnknownFields = true)
|
||||||
|
except SerializationError as exc:
|
||||||
|
debug "Failed to deserialize REST JSON data",
|
||||||
|
err = exc.formatMsg("<data>"),
|
||||||
|
data = string.fromBytes(value)
|
||||||
|
err("Serialization error")
|
||||||
|
else:
|
||||||
|
err("Content-Type not supported")
|
||||||
|
|
||||||
|
proc decodeBody*[T](t: typedesc[T],
|
||||||
|
body: ContentBody): Result[T, cstring] =
|
||||||
|
if body.contentType != ApplicationJsonMediaType:
|
||||||
|
return err("Unsupported content type")
|
||||||
|
let data =
|
||||||
|
try:
|
||||||
|
RestJson.decode(body.data, T,
|
||||||
|
requireAllFields = true,
|
||||||
|
allowUnknownFields = true)
|
||||||
|
except SerializationError as exc:
|
||||||
|
debug "Failed to deserialize REST JSON data",
|
||||||
|
err = exc.formatMsg("<data>"),
|
||||||
|
data = string.fromBytes(body.data)
|
||||||
|
return err("Unable to deserialize data")
|
||||||
|
except CatchableError:
|
||||||
|
return err("Unexpected deserialization error")
|
||||||
|
ok(data)
|
Loading…
Reference in New Issue