From d69a0206a74778b171dbfc351009f564aee62999 Mon Sep 17 00:00:00 2001 From: Emil Ivanichkov Date: Fri, 8 Mar 2024 15:37:52 +0200 Subject: [PATCH] feat(rest): Add common `serialization` utils --- .../rest/rest_serialization.nim | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/status_node_manager/rest/rest_serialization.nim diff --git a/src/status_node_manager/rest/rest_serialization.nim b/src/status_node_manager/rest/rest_serialization.nim new file mode 100644 index 0000000..68792ae --- /dev/null +++ b/src/status_node_manager/rest/rest_serialization.nim @@ -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 = 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 = string.fromBytes(body.data) + return err("Unable to deserialize data") + except CatchableError: + return err("Unexpected deserialization error") + ok(data)