chore: Allow text/plain content type descriptor for json formatted content body (#2209)

* Allow text/plain content type descriptor for json formatted content body. Refactored duplicated encode/decode functions for rest api

* Fix relay endpoint decodings of content bodies to accept text/plain

* Added support for content body decoder for checking media type if additional parameters are present

* Fix wrong usage of ContentTypeData - appeared only for tests
This commit is contained in:
NagyZoltanPeter 2023-11-14 16:59:53 +01:00 committed by GitHub
parent 2cb0989a28
commit 6d81e3841a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 132 additions and 337 deletions

View File

@ -13,6 +13,7 @@ import
import
../serdes,
../responses,
../rest_serdes,
./types
export types
@ -21,37 +22,9 @@ export types
logScope:
topics = "waku node rest admin api"
proc decodeBytes*(t: typedesc[seq[WakuPeer]], data: openArray[byte],
contentType: Opt[ContentTypeData]): RestResult[seq[WakuPeer]] =
if MediaType.init($contentType) != MIMETYPE_JSON:
error "Unsupported response contentType value", contentType = contentType
return err("Unsupported response contentType")
let decoded = decodeFromJsonBytes(seq[WakuPeer], data).valueOr:
return err("Invalid response from server, could not decode.")
return ok(decoded)
proc decodeBytes*(t: typedesc[string], value: openArray[byte],
contentType: Opt[ContentTypeData]): RestResult[string] =
if MediaType.init($contentType) != MIMETYPE_TEXT:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
var res: string
if len(value) > 0:
res = newString(len(value))
copyMem(addr res[0], unsafeAddr value[0], len(value))
return ok(res)
proc encodeBytes*(value: seq[string],
contentType: string): RestResult[seq[byte]] =
if MediaType.init(contentType) != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
let encoded = ?encodeIntoJsonBytes(value)
return ok(encoded)
return encodeBytesOf(value, contentType)
proc getPeers*():
RestResponse[seq[WakuPeer]]

View File

@ -21,6 +21,7 @@ import
../../../node/peer_manager,
../responses,
../serdes,
../rest_serdes,
./types
export types
@ -32,23 +33,6 @@ const ROUTE_ADMIN_V1_PEERS* = "/admin/v1/peers"
type PeerProtocolTuple = tuple[multiaddr: string, protocol: string, connected: bool]
func decodeRequestBody[T](contentBody: Option[ContentBody]) : Result[T, RestApiResponse] =
if contentBody.isNone():
return err(RestApiResponse.badRequest("Missing content body"))
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
if reqBodyContentType != MIMETYPE_JSON:
return err(RestApiResponse.badRequest("Wrong Content-Type, expected application/json"))
let reqBodyData = contentBody.get().data
let requestResult = decodeFromJsonBytes(T, reqBodyData)
if requestResult.isErr():
return err(RestApiResponse.badRequest("Invalid content body, could not decode. " &
$requestResult.error))
return ok(requestResult.get())
proc tuplesToWakuPeers(peers: var WakuPeers, peersTup: seq[PeerProtocolTuple]) =
for peer in peersTup:
peers.add(peer.multiaddr, peer.protocol, peer.connected)

View File

@ -11,6 +11,7 @@ import
import
../serdes,
../responses,
../rest_serdes,
./types
export types
@ -19,31 +20,8 @@ export types
logScope:
topics = "waku node rest debug_api"
proc decodeBytes*(t: typedesc[DebugWakuInfo], data: openArray[byte],
contentType: Opt[ContentTypeData]): RestResult[DebugWakuInfo] =
if MediaType.init($contentType) != MIMETYPE_JSON:
error "Unsupported respose contentType value", contentType = contentType
return err("Unsupported response contentType")
let decoded = ?decodeFromJsonBytes(DebugWakuInfo, data)
return ok(decoded)
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
proc debugInfoV1*(): RestResponse[DebugWakuInfo] {.rest, endpoint: "/debug/v1/info", meth: HttpMethod.MethodGet.}
proc decodeBytes*(t: typedesc[string], value: openArray[byte],
contentType: Opt[ContentTypeData]): RestResult[string] =
if MediaType.init($contentType) != MIMETYPE_TEXT:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
var res: string
if len(value) > 0:
res = newString(len(value))
copyMem(addr res[0], unsafeAddr value[0], len(value))
return ok(res)
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
proc debugVersionV1*(): RestResponse[string] {.rest, endpoint: "/debug/v1/version", meth: HttpMethod.MethodGet.}

View File

@ -16,6 +16,7 @@ import
../../../waku_core,
../serdes,
../responses,
../rest_serdes,
./types
export types
@ -25,52 +26,19 @@ logScope:
proc encodeBytes*(value: FilterSubscribeRequest,
contentType: string): RestResult[seq[byte]] =
if MediaType.init(contentType) != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
let encoded = ?encodeIntoJsonBytes(value)
return ok(encoded)
return encodeBytesOf(value, contentType)
proc encodeBytes*(value: FilterSubscriberPing,
contentType: string): RestResult[seq[byte]] =
if MediaType.init(contentType) != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
let encoded = ?encodeIntoJsonBytes(value)
return ok(encoded)
return encodeBytesOf(value, contentType)
proc encodeBytes*(value: FilterUnsubscribeRequest,
contentType: string): RestResult[seq[byte]] =
if MediaType.init(contentType) != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
let encoded = ?encodeIntoJsonBytes(value)
return ok(encoded)
return encodeBytesOf(value, contentType)
proc encodeBytes*(value: FilterUnsubscribeAllRequest,
contentType: string): RestResult[seq[byte]] =
if MediaType.init(contentType) != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
let encoded = ?encodeIntoJsonBytes(value)
return ok(encoded)
proc decodeBytes*(t: typedesc[FilterSubscriptionResponse],
value: openarray[byte],
contentType: Opt[ContentTypeData]):
RestResult[FilterSubscriptionResponse] =
if MediaType.init($contentType) != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
let decoded = ?decodeFromJsonBytes(FilterSubscriptionResponse, value)
return ok(decoded)
return encodeBytesOf(value, contentType)
proc filterSubscriberPing*(requestId: string):
RestResponse[FilterSubscriptionResponse]
@ -92,16 +60,6 @@ proc filterDeleteAllSubscriptions*(body: FilterUnsubscribeAllRequest):
RestResponse[FilterSubscriptionResponse]
{.rest, endpoint: "/filter/v2/subscriptions/all", meth: HttpMethod.MethodDelete.}
proc decodeBytes*(t: typedesc[FilterGetMessagesResponse],
data: openArray[byte],
contentType: Opt[ContentTypeData]): RestResult[FilterGetMessagesResponse] =
if MediaType.init($contentType) != MIMETYPE_JSON:
error "Unsupported response contentType value", contentType = contentType
return err("Unsupported response contentType")
let decoded = ?decodeFromJsonBytes(FilterGetMessagesResponse, data)
return ok(decoded)
proc filterGetMessagesV1*(contentTopic: string):
RestResponse[FilterGetMessagesResponse]
{.rest, endpoint: "/filter/v2/messages/{contentTopic}", meth: HttpMethod.MethodGet.}

View File

@ -24,6 +24,7 @@ import
../../handlers,
../serdes,
../responses,
../rest_serdes,
./types
export types
@ -44,23 +45,6 @@ const filterMessageCacheDefaultCapacity* = 30
type
MessageCache* = message_cache.MessageCache[ContentTopic]
func decodeRequestBody[T](contentBody: Option[ContentBody]) : Result[T, RestApiResponse] =
if contentBody.isNone():
return err(RestApiResponse.badRequest("Missing content body"))
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
if reqBodyContentType != MIMETYPE_JSON:
return err(RestApiResponse.badRequest("Wrong Content-Type, expected application/json"))
let reqBodyData = contentBody.get().data
let requestResult = decodeFromJsonBytes(T, reqBodyData)
if requestResult.isErr():
return err(RestApiResponse.badRequest("Invalid content body, could not decode. " &
$requestResult.error))
return ok(requestResult.get())
proc getErrorCause(err: filter_protocol_type.FilterSubscribeError): string =
## Retrieve proper error cause of FilterSubscribeError - due stringify make some parts of text double
@ -169,7 +153,7 @@ proc filterPostPutSubscriptionRequestHandler(
let peer = node.peerManager.selectPeer(WakuFilterSubscribeCodec).valueOr:
let handler = discHandler.valueOr:
return makeRestResponse(req.requestId, NoPeerNoDiscoError)
return makeRestResponse(req.requestId, NoPeerNoDiscoError)
let peerOp = (await handler()).valueOr:
return RestApiResponse.internalServerError($error)
@ -233,7 +217,7 @@ proc installFilterDeleteSubscriptionsHandler(
let peer = node.peerManager.selectPeer(WakuFilterSubscribeCodec).valueOr:
let handler = discHandler.valueOr:
return makeRestResponse(req.requestId, NoPeerNoDiscoError)
return makeRestResponse(req.requestId, NoPeerNoDiscoError)
let peerOp = (await handler()).valueOr:
return RestApiResponse.internalServerError($error)
@ -276,7 +260,7 @@ proc installFilterDeleteAllSubscriptionsHandler(
let peer = node.peerManager.selectPeer(WakuFilterSubscribeCodec).valueOr:
let handler = discHandler.valueOr:
return makeRestResponse(req.requestId, NoPeerNoDiscoError)
return makeRestResponse(req.requestId, NoPeerNoDiscoError)
let peerOp = (await handler()).valueOr:
return RestApiResponse.internalServerError($error)
@ -285,7 +269,7 @@ proc installFilterDeleteAllSubscriptionsHandler(
return makeRestResponse(req.requestId, NoPeerNoneFoundError)
let unsubFut = node.filterUnsubscribeAll(peer)
if not await unsubFut.withTimeout(futTimeoutForSubscriptionProcessing):
error "Failed to unsubscribe from contentFilters due to timeout!"
return makeRestResponse(req.requestId,
@ -310,7 +294,7 @@ proc installFilterPingSubscriberHandler(
let peer = node.peerManager.selectPeer(WakuFilterSubscribeCodec).valueOr:
let handler = discHandler.valueOr:
return makeRestResponse(requestId.get(), NoPeerNoDiscoError)
return makeRestResponse(requestId.get(), NoPeerNoDiscoError)
let peerOp = (await handler()).valueOr:
return RestApiResponse.internalServerError($error)

View File

@ -14,6 +14,7 @@ import
../../../waku_core,
../serdes,
../responses,
../rest_serdes,
./types
export types
@ -23,46 +24,19 @@ logScope:
proc encodeBytes*(value: FilterLegacySubscribeRequest,
contentType: string): RestResult[seq[byte]] =
if MediaType.init(contentType) != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
let encoded = ?encodeIntoJsonBytes(value)
return ok(encoded)
proc decodeBytes*(t: typedesc[string], value: openarray[byte],
contentType: Opt[ContentTypeData]): RestResult[string] =
if MediaType.init($contentType) != MIMETYPE_TEXT:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
var res: string
if len(value) > 0:
res = newString(len(value))
copyMem(addr res[0], unsafeAddr value[0], len(value))
return ok(res)
return encodeBytesOf(value, contentType)
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
proc filterPostSubscriptionsV1*(body: FilterLegacySubscribeRequest):
RestResponse[string]
proc filterPostSubscriptionsV1*(body: FilterLegacySubscribeRequest):
RestResponse[string]
{.rest, endpoint: "/filter/v1/subscriptions", meth: HttpMethod.MethodPost.}
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
proc filterDeleteSubscriptionsV1*(body: FilterLegacySubscribeRequest):
RestResponse[string]
proc filterDeleteSubscriptionsV1*(body: FilterLegacySubscribeRequest):
RestResponse[string]
{.rest, endpoint: "/filter/v1/subscriptions", meth: HttpMethod.MethodDelete.}
proc decodeBytes*(t: typedesc[FilterGetMessagesResponse],
data: openArray[byte],
contentType: Opt[ContentTypeData]): RestResult[FilterGetMessagesResponse] =
if MediaType.init($contentType) != MIMETYPE_JSON:
error "Unsupported response contentType value", contentType = contentType
return err("Unsupported response contentType")
let decoded = ?decodeFromJsonBytes(FilterGetMessagesResponse, data)
return ok(decoded)
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
proc filterGetMessagesV1*(contentTopic: string):
RestResponse[FilterGetMessagesResponse]
proc filterGetMessagesV1*(contentTopic: string):
RestResponse[FilterGetMessagesResponse]
{.rest, endpoint: "/filter/v1/messages/{contentTopic}", meth: HttpMethod.MethodGet.}

View File

@ -20,6 +20,7 @@ import
../../message_cache,
../serdes,
../responses,
../rest_serdes,
./types
export types
@ -38,23 +39,6 @@ const filterMessageCacheDefaultCapacity* = 30
type
MessageCache* = message_cache.MessageCache[ContentTopic]
func decodeRequestBody[T](contentBody: Option[ContentBody]) : Result[T, RestApiResponse] =
if contentBody.isNone():
return err(RestApiResponse.badRequest("Missing content body"))
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
if reqBodyContentType != MIMETYPE_JSON:
return err(RestApiResponse.badRequest("Wrong Content-Type, expected application/json"))
let reqBodyData = contentBody.get().data
let requestResult = decodeFromJsonBytes(T, reqBodyData)
if requestResult.isErr():
return err(RestApiResponse.badRequest("Invalid content body, could not decode. " &
$requestResult.error))
return ok(requestResult.get())
proc installFilterV1PostSubscriptionsV1Handler*(router: var RestRouter,
node: WakuNode,
cache: MessageCache) =

View File

@ -10,21 +10,10 @@ import
presto/[route, client]
import
../serdes,
../responses
../responses,
../rest_serdes
logScope:
topics = "waku node rest health_api"
proc decodeBytes*(t: typedesc[string], value: openArray[byte],
contentType: Opt[ContentTypeData]): RestResult[string] =
if MediaType.init($contentType) != MIMETYPE_TEXT:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
var res: string
if len(value) > 0:
res = newString(len(value))
copyMem(addr res[0], unsafeAddr value[0], len(value))
return ok(res)
proc healthCheck*(): RestResponse[string] {.rest, endpoint: "/health", meth: HttpMethod.MethodGet.}

View File

@ -16,6 +16,7 @@ import
../../../waku_core,
../serdes,
../responses,
../rest_serdes,
./types
export types
@ -25,24 +26,8 @@ logScope:
proc encodeBytes*(value: PushRequest,
contentType: string): RestResult[seq[byte]] =
if MediaType.init(contentType) != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
return encodeBytesOf(value, contentType)
let encoded = ?encodeIntoJsonBytes(value)
return ok(encoded)
proc decodeBytes*(t: typedesc[string], value: openarray[byte],
contentType: Opt[ContentTypeData]): RestResult[string] =
if MediaType.init($contentType) != MIMETYPE_TEXT:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
var res: string
if len(value) > 0:
res = newString(len(value))
copyMem(addr res[0], unsafeAddr value[0], len(value))
return ok(res)
proc sendPushRequest*(body: PushRequest):
RestResponse[string]

View File

@ -21,6 +21,7 @@ import
../../handlers,
../serdes,
../responses,
../rest_serdes,
./types
export types
@ -40,23 +41,6 @@ const NoPeerNoneFoundError = RestApiResponse.serviceUnavailable(
const ROUTE_LIGHTPUSH* = "/lightpush/v1/message"
func decodeRequestBody[T](contentBody: Option[ContentBody]) : Result[T, RestApiResponse] =
if contentBody.isNone():
return err(RestApiResponse.badRequest("Missing content body"))
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
if reqBodyContentType != MIMETYPE_JSON:
return err(RestApiResponse.badRequest("Wrong Content-Type, expected application/json"))
let reqBodyData = contentBody.get().data
let requestResult = decodeFromJsonBytes(T, reqBodyData)
if requestResult.isErr():
return err(RestApiResponse.badRequest("Invalid content body, could not decode. " &
$requestResult.error))
return ok(requestResult.get())
proc installLightPushRequestHandler*(
router: var RestRouter,
node: WakuNode,
@ -73,7 +57,7 @@ proc installLightPushRequestHandler*(
return decodedBody.error()
let req: PushRequest = decodedBody.value()
let msg = req.message.toWakuMessage().valueOr:
return RestApiResponse.badRequest("Invalid message: " & $error)

View File

@ -14,6 +14,7 @@ import
../../../waku_core,
../serdes,
../responses,
../rest_serdes,
./types
export types
@ -25,24 +26,7 @@ logScope:
proc encodeBytes*(value: seq[PubSubTopic],
contentType: string): RestResult[seq[byte]] =
if MediaType.init(contentType) != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
let encoded = ?encodeIntoJsonBytes(value)
return ok(encoded)
proc decodeBytes*(t: typedesc[string], value: openarray[byte],
contentType: Opt[ContentTypeData]): RestResult[string] =
if MediaType.init($contentType) != MIMETYPE_TEXT:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
var res: string
if len(value) > 0:
res = newString(len(value))
copyMem(addr res[0], unsafeAddr value[0], len(value))
return ok(res)
return encodeBytesOf(value, contentType)
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
proc relayPostSubscriptionsV1*(body: seq[PubsubTopic]): RestResponse[string] {.rest, endpoint: "/relay/v1/subscriptions", meth: HttpMethod.MethodPost.}
@ -52,22 +36,9 @@ proc relayPostAutoSubscriptionsV1*(body: seq[ContentTopic]): RestResponse[string
proc relayDeleteSubscriptionsV1*(body: seq[PubsubTopic]): RestResponse[string] {.rest, endpoint: "/relay/v1/subscriptions", meth: HttpMethod.MethodDelete.}
proc relayDeleteAutoSubscriptionsV1*(body: seq[ContentTopic]): RestResponse[string] {.rest, endpoint: "/relay/v1/auto/subscriptions", meth: HttpMethod.MethodDelete.}
proc decodeBytes*(t: typedesc[RelayGetMessagesResponse], data: openArray[byte], contentType: Opt[ContentTypeData]): RestResult[RelayGetMessagesResponse] =
if MediaType.init($contentType) != MIMETYPE_JSON:
error "Unsupported respose contentType value", contentType = contentType
return err("Unsupported response contentType")
let decoded = ?decodeFromJsonBytes(RelayGetMessagesResponse, data)
return ok(decoded)
proc encodeBytes*(value: RelayPostMessagesRequest,
contentType: string): RestResult[seq[byte]] =
if MediaType.init(contentType) != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
let encoded = ?encodeIntoJsonBytes(value)
return ok(encoded)
return encodeBytesOf(value, contentType)
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
proc relayGetMessagesV1*(pubsubTopic: string): RestResponse[RelayGetMessagesResponse] {.rest, endpoint: "/relay/v1/messages/{pubsubTopic}", meth: HttpMethod.MethodGet.}

View File

@ -20,6 +20,7 @@ import
../../handlers,
../serdes,
../responses,
../rest_serdes,
./types
from std/times import getTime
@ -55,16 +56,8 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
if contentBody.isNone():
return RestApiResponse.badRequest()
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
if reqBodyContentType != MIMETYPE_JSON:
return RestApiResponse.badRequest()
let reqBodyData = contentBody.get().data
let reqResult = decodeFromJsonBytes(seq[PubsubTopic], reqBodyData)
if reqResult.isErr():
return RestApiResponse.badRequest()
let req: seq[PubsubTopic] = reqResult.get()
let req: seq[PubsubTopic] = decodeRequestBody[seq[PubsubTopic]](contentBody).valueOr:
return error
# Only subscribe to topics for which we have no subscribed topic handlers yet
let newTopics = req.filterIt(not cache.isSubscribed(it))
@ -83,16 +76,8 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
if contentBody.isNone():
return RestApiResponse.badRequest()
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
if reqBodyContentType != MIMETYPE_JSON:
return RestApiResponse.badRequest()
let reqBodyData = contentBody.get().data
let reqResult = decodeFromJsonBytes(seq[PubsubTopic], reqBodyData)
if reqResult.isErr():
return RestApiResponse.badRequest()
let req: seq[PubsubTopic] = reqResult.get()
let req: seq[PubsubTopic] = decodeRequestBody[seq[PubsubTopic]](contentBody).valueOr:
return error
# Unsubscribe all handlers from requested topics
for pubsubTopic in req:
@ -139,21 +124,12 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
if contentBody.isNone():
return RestApiResponse.badRequest()
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
if reqBodyContentType != MIMETYPE_JSON:
return RestApiResponse.badRequest()
let reqWakuMessage: RelayWakuMessage = decodeRequestBody[RelayWakuMessage](contentBody).valueOr:
return error
let reqBodyData = contentBody.get().data
let reqResult = decodeFromJsonBytes(RelayPostMessagesRequest, reqBodyData)
if reqResult.isErr():
var message: WakuMessage = reqWakuMessage.toWakuMessage(version = 0).valueOr:
return RestApiResponse.badRequest()
let resMessage = reqResult.value.toWakuMessage(version = 0)
if resMessage.isErr():
return RestApiResponse.badRequest()
var message = resMessage.get()
# if RLN is mounted, append the proof to the message
if not node.wakuRlnRelay.isNil():
# append the proof to the message
@ -191,16 +167,8 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
if contentBody.isNone():
return RestApiResponse.badRequest()
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
if reqBodyContentType != MIMETYPE_JSON:
return RestApiResponse.badRequest()
let reqBodyData = contentBody.get().data
let reqResult = decodeFromJsonBytes(seq[ContentTopic], reqBodyData)
if reqResult.isErr():
return RestApiResponse.badRequest()
let req: seq[ContentTopic] = reqResult.get()
let req: seq[ContentTopic] = decodeRequestBody[seq[ContentTopic]](contentBody).valueOr:
return error
# Only subscribe to topics for which we have no subscribed topic handlers yet
let newTopics = req.filterIt(not cache.isSubscribed(it))
@ -219,16 +187,8 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
if contentBody.isNone():
return RestApiResponse.badRequest()
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
if reqBodyContentType != MIMETYPE_JSON:
return RestApiResponse.badRequest()
let reqBodyData = contentBody.get().data
let reqResult = decodeFromJsonBytes(seq[ContentTopic], reqBodyData)
if reqResult.isErr():
return RestApiResponse.badRequest()
let req: seq[ContentTopic] = reqResult.get()
let req: seq[ContentTopic] = decodeRequestBody[seq[ContentTopic]](contentBody).valueOr:
return error
# Unsubscribe all handlers from requested topics
for contentTopic in req:
@ -266,24 +226,15 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
if contentBody.isNone():
return RestApiResponse.badRequest()
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
if reqBodyContentType != MIMETYPE_JSON:
let req: RelayWakuMessage = decodeRequestBody[RelayWakuMessage](contentBody).valueOr:
return error
if req.contentTopic.isNone():
return RestApiResponse.badRequest()
let reqBodyData = contentBody.get().data
let reqResult = decodeFromJsonBytes(RelayPostMessagesRequest, reqBodyData)
if reqResult.isErr():
var message: WakuMessage = req.toWakuMessage(version = 0).valueOr:
return RestApiResponse.badRequest()
if reqResult.value.contentTopic.isNone():
return RestApiResponse.badRequest()
let resMessage = reqResult.value.toWakuMessage(version = 0)
if resMessage.isErr():
return RestApiResponse.badRequest()
var message = resMessage.get()
# if RLN is mounted, append the proof to the message
if not node.wakuRlnRelay.isNil():
# append the proof to the message

View File

@ -0,0 +1,79 @@
when (NimMajor, NimMinor) < (1, 4):
{.push raises: [Defect].}
else:
{.push raises: [].}
import
std/typetraits,
std/os,
stew/results,
chronicles,
serialization,
json_serialization,
json_serialization/std/options,
json_serialization/std/net,
json_serialization/std/sets,
presto/common
import
./serdes,
./responses
logScope:
topics = "waku node rest"
proc encodeBytesOf*[T](value: T,
contentType: string): RestResult[seq[byte]]=
let reqContentType = MediaType.init(contentType)
if reqContentType != MIMETYPE_JSON:
error "Unsupported contentType value", contentType = contentType, typ = value.type.name
return err("Unsupported contentType")
let encoded = ?encodeIntoJsonBytes(value)
return ok(encoded)
func decodeRequestBody*[T](contentBody: Option[ContentBody]) : Result[T, RestApiResponse] =
if contentBody.isNone():
return err(RestApiResponse.badRequest("Missing content body"))
let reqBodyContentType = contentBody.get().contentType.mediaType
if reqBodyContentType != MIMETYPE_JSON and reqBodyContentType != MIMETYPE_TEXT:
return err(RestApiResponse.badRequest("Wrong Content-Type, expected application/json or text/plain"))
let reqBodyData = contentBody.get().data
let requestResult = decodeFromJsonBytes(T, reqBodyData)
if requestResult.isErr():
return err(RestApiResponse.badRequest("Invalid content body, could not decode. " &
$requestResult.error))
return ok(requestResult.get())
proc decodeBytes*(t: typedesc[string], value: openarray[byte],
contentType: Opt[ContentTypeData]): RestResult[string] =
if MediaType.init($contentType) != MIMETYPE_TEXT:
error "Unsupported contentType value", contentType = contentType
return err("Unsupported contentType")
var res: string
if len(value) > 0:
res = newString(len(value))
copyMem(addr res[0], unsafeAddr value[0], len(value))
return ok(res)
proc decodeBytes*[T](t: typedesc[T],
data: openArray[byte],
contentType: Opt[ContentTypeData]): RestResult[T] =
let reqContentType = contentType.valueOr():
error "Unsupported response, missing contentType value"
return err("Unsupported response, missing contentType")
if reqContentType.mediaType != MIMETYPE_JSON and reqContentType.mediaType != MIMETYPE_TEXT:
error "Unsupported response contentType value", contentType = contentType
return err("Unsupported response contentType")
let decoded = ?decodeFromJsonBytes(T, data)
return ok(decoded)

View File

@ -3,7 +3,7 @@ when (NimMajor, NimMinor) < (1, 4):
else:
{.push raises: [].}
import
import
std/typetraits,
stew/results,
stew/byteutils,
@ -15,7 +15,8 @@ import
json_serialization/std/sets,
presto/common
logScope:
logScope:
topics = "waku node rest"
Json.createFlavor RestJson