mirror of
https://github.com/waku-org/nwaku.git
synced 2025-03-01 15:30:55 +00:00
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:
parent
2cb0989a28
commit
6d81e3841a
@ -13,6 +13,7 @@ import
|
|||||||
import
|
import
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses,
|
../responses,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
export types
|
export types
|
||||||
@ -21,37 +22,9 @@ export types
|
|||||||
logScope:
|
logScope:
|
||||||
topics = "waku node rest admin api"
|
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],
|
proc encodeBytes*(value: seq[string],
|
||||||
contentType: string): RestResult[seq[byte]] =
|
contentType: string): RestResult[seq[byte]] =
|
||||||
if MediaType.init(contentType) != MIMETYPE_JSON:
|
return encodeBytesOf(value, contentType)
|
||||||
error "Unsupported contentType value", contentType = contentType
|
|
||||||
return err("Unsupported contentType")
|
|
||||||
|
|
||||||
let encoded = ?encodeIntoJsonBytes(value)
|
|
||||||
return ok(encoded)
|
|
||||||
|
|
||||||
proc getPeers*():
|
proc getPeers*():
|
||||||
RestResponse[seq[WakuPeer]]
|
RestResponse[seq[WakuPeer]]
|
||||||
|
@ -21,6 +21,7 @@ import
|
|||||||
../../../node/peer_manager,
|
../../../node/peer_manager,
|
||||||
../responses,
|
../responses,
|
||||||
../serdes,
|
../serdes,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
export types
|
export types
|
||||||
@ -32,23 +33,6 @@ const ROUTE_ADMIN_V1_PEERS* = "/admin/v1/peers"
|
|||||||
|
|
||||||
type PeerProtocolTuple = tuple[multiaddr: string, protocol: string, connected: bool]
|
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]) =
|
proc tuplesToWakuPeers(peers: var WakuPeers, peersTup: seq[PeerProtocolTuple]) =
|
||||||
for peer in peersTup:
|
for peer in peersTup:
|
||||||
peers.add(peer.multiaddr, peer.protocol, peer.connected)
|
peers.add(peer.multiaddr, peer.protocol, peer.connected)
|
||||||
|
@ -11,6 +11,7 @@ import
|
|||||||
import
|
import
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses,
|
../responses,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
export types
|
export types
|
||||||
@ -19,31 +20,8 @@ export types
|
|||||||
logScope:
|
logScope:
|
||||||
topics = "waku node rest debug_api"
|
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)
|
# 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 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)
|
# 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.}
|
proc debugVersionV1*(): RestResponse[string] {.rest, endpoint: "/debug/v1/version", meth: HttpMethod.MethodGet.}
|
||||||
|
@ -16,6 +16,7 @@ import
|
|||||||
../../../waku_core,
|
../../../waku_core,
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses,
|
../responses,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
export types
|
export types
|
||||||
@ -25,52 +26,19 @@ logScope:
|
|||||||
|
|
||||||
proc encodeBytes*(value: FilterSubscribeRequest,
|
proc encodeBytes*(value: FilterSubscribeRequest,
|
||||||
contentType: string): RestResult[seq[byte]] =
|
contentType: string): RestResult[seq[byte]] =
|
||||||
if MediaType.init(contentType) != MIMETYPE_JSON:
|
return encodeBytesOf(value, contentType)
|
||||||
error "Unsupported contentType value", contentType = contentType
|
|
||||||
return err("Unsupported contentType")
|
|
||||||
|
|
||||||
let encoded = ?encodeIntoJsonBytes(value)
|
|
||||||
return ok(encoded)
|
|
||||||
|
|
||||||
proc encodeBytes*(value: FilterSubscriberPing,
|
proc encodeBytes*(value: FilterSubscriberPing,
|
||||||
contentType: string): RestResult[seq[byte]] =
|
contentType: string): RestResult[seq[byte]] =
|
||||||
if MediaType.init(contentType) != MIMETYPE_JSON:
|
return encodeBytesOf(value, contentType)
|
||||||
error "Unsupported contentType value", contentType = contentType
|
|
||||||
return err("Unsupported contentType")
|
|
||||||
|
|
||||||
let encoded = ?encodeIntoJsonBytes(value)
|
|
||||||
return ok(encoded)
|
|
||||||
|
|
||||||
proc encodeBytes*(value: FilterUnsubscribeRequest,
|
proc encodeBytes*(value: FilterUnsubscribeRequest,
|
||||||
contentType: string): RestResult[seq[byte]] =
|
contentType: string): RestResult[seq[byte]] =
|
||||||
if MediaType.init(contentType) != MIMETYPE_JSON:
|
return encodeBytesOf(value, contentType)
|
||||||
error "Unsupported contentType value", contentType = contentType
|
|
||||||
return err("Unsupported contentType")
|
|
||||||
|
|
||||||
let encoded = ?encodeIntoJsonBytes(value)
|
|
||||||
return ok(encoded)
|
|
||||||
|
|
||||||
proc encodeBytes*(value: FilterUnsubscribeAllRequest,
|
proc encodeBytes*(value: FilterUnsubscribeAllRequest,
|
||||||
contentType: string): RestResult[seq[byte]] =
|
contentType: string): RestResult[seq[byte]] =
|
||||||
if MediaType.init(contentType) != MIMETYPE_JSON:
|
return encodeBytesOf(value, contentType)
|
||||||
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)
|
|
||||||
|
|
||||||
proc filterSubscriberPing*(requestId: string):
|
proc filterSubscriberPing*(requestId: string):
|
||||||
RestResponse[FilterSubscriptionResponse]
|
RestResponse[FilterSubscriptionResponse]
|
||||||
@ -92,16 +60,6 @@ proc filterDeleteAllSubscriptions*(body: FilterUnsubscribeAllRequest):
|
|||||||
RestResponse[FilterSubscriptionResponse]
|
RestResponse[FilterSubscriptionResponse]
|
||||||
{.rest, endpoint: "/filter/v2/subscriptions/all", meth: HttpMethod.MethodDelete.}
|
{.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):
|
proc filterGetMessagesV1*(contentTopic: string):
|
||||||
RestResponse[FilterGetMessagesResponse]
|
RestResponse[FilterGetMessagesResponse]
|
||||||
{.rest, endpoint: "/filter/v2/messages/{contentTopic}", meth: HttpMethod.MethodGet.}
|
{.rest, endpoint: "/filter/v2/messages/{contentTopic}", meth: HttpMethod.MethodGet.}
|
||||||
|
@ -24,6 +24,7 @@ import
|
|||||||
../../handlers,
|
../../handlers,
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses,
|
../responses,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
export types
|
export types
|
||||||
@ -44,23 +45,6 @@ const filterMessageCacheDefaultCapacity* = 30
|
|||||||
type
|
type
|
||||||
MessageCache* = message_cache.MessageCache[ContentTopic]
|
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 =
|
proc getErrorCause(err: filter_protocol_type.FilterSubscribeError): string =
|
||||||
## Retrieve proper error cause of FilterSubscribeError - due stringify make some parts of text double
|
## Retrieve proper error cause of FilterSubscribeError - due stringify make some parts of text double
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import
|
|||||||
../../../waku_core,
|
../../../waku_core,
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses,
|
../responses,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
export types
|
export types
|
||||||
@ -23,24 +24,7 @@ logScope:
|
|||||||
|
|
||||||
proc encodeBytes*(value: FilterLegacySubscribeRequest,
|
proc encodeBytes*(value: FilterLegacySubscribeRequest,
|
||||||
contentType: string): RestResult[seq[byte]] =
|
contentType: string): RestResult[seq[byte]] =
|
||||||
if MediaType.init(contentType) != MIMETYPE_JSON:
|
return encodeBytesOf(value, contentType)
|
||||||
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)
|
|
||||||
|
|
||||||
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
|
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
|
||||||
proc filterPostSubscriptionsV1*(body: FilterLegacySubscribeRequest):
|
proc filterPostSubscriptionsV1*(body: FilterLegacySubscribeRequest):
|
||||||
@ -52,16 +36,6 @@ proc filterDeleteSubscriptionsV1*(body: FilterLegacySubscribeRequest):
|
|||||||
RestResponse[string]
|
RestResponse[string]
|
||||||
{.rest, endpoint: "/filter/v1/subscriptions", meth: HttpMethod.MethodDelete.}
|
{.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)
|
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
|
||||||
proc filterGetMessagesV1*(contentTopic: string):
|
proc filterGetMessagesV1*(contentTopic: string):
|
||||||
RestResponse[FilterGetMessagesResponse]
|
RestResponse[FilterGetMessagesResponse]
|
||||||
|
@ -20,6 +20,7 @@ import
|
|||||||
../../message_cache,
|
../../message_cache,
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses,
|
../responses,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
export types
|
export types
|
||||||
@ -38,23 +39,6 @@ const filterMessageCacheDefaultCapacity* = 30
|
|||||||
type
|
type
|
||||||
MessageCache* = message_cache.MessageCache[ContentTopic]
|
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,
|
proc installFilterV1PostSubscriptionsV1Handler*(router: var RestRouter,
|
||||||
node: WakuNode,
|
node: WakuNode,
|
||||||
cache: MessageCache) =
|
cache: MessageCache) =
|
||||||
|
@ -10,21 +10,10 @@ import
|
|||||||
presto/[route, client]
|
presto/[route, client]
|
||||||
import
|
import
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses
|
../responses,
|
||||||
|
../rest_serdes
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "waku node rest health_api"
|
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.}
|
proc healthCheck*(): RestResponse[string] {.rest, endpoint: "/health", meth: HttpMethod.MethodGet.}
|
||||||
|
@ -16,6 +16,7 @@ import
|
|||||||
../../../waku_core,
|
../../../waku_core,
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses,
|
../responses,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
export types
|
export types
|
||||||
@ -25,24 +26,8 @@ logScope:
|
|||||||
|
|
||||||
proc encodeBytes*(value: PushRequest,
|
proc encodeBytes*(value: PushRequest,
|
||||||
contentType: string): RestResult[seq[byte]] =
|
contentType: string): RestResult[seq[byte]] =
|
||||||
if MediaType.init(contentType) != MIMETYPE_JSON:
|
return encodeBytesOf(value, contentType)
|
||||||
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)
|
|
||||||
|
|
||||||
proc sendPushRequest*(body: PushRequest):
|
proc sendPushRequest*(body: PushRequest):
|
||||||
RestResponse[string]
|
RestResponse[string]
|
||||||
|
@ -21,6 +21,7 @@ import
|
|||||||
../../handlers,
|
../../handlers,
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses,
|
../responses,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
export types
|
export types
|
||||||
@ -40,23 +41,6 @@ const NoPeerNoneFoundError = RestApiResponse.serviceUnavailable(
|
|||||||
|
|
||||||
const ROUTE_LIGHTPUSH* = "/lightpush/v1/message"
|
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*(
|
proc installLightPushRequestHandler*(
|
||||||
router: var RestRouter,
|
router: var RestRouter,
|
||||||
node: WakuNode,
|
node: WakuNode,
|
||||||
|
@ -14,6 +14,7 @@ import
|
|||||||
../../../waku_core,
|
../../../waku_core,
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses,
|
../responses,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
export types
|
export types
|
||||||
@ -25,24 +26,7 @@ logScope:
|
|||||||
|
|
||||||
proc encodeBytes*(value: seq[PubSubTopic],
|
proc encodeBytes*(value: seq[PubSubTopic],
|
||||||
contentType: string): RestResult[seq[byte]] =
|
contentType: string): RestResult[seq[byte]] =
|
||||||
if MediaType.init(contentType) != MIMETYPE_JSON:
|
return encodeBytesOf(value, contentType)
|
||||||
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)
|
|
||||||
|
|
||||||
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
|
# 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.}
|
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 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 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,
|
proc encodeBytes*(value: RelayPostMessagesRequest,
|
||||||
contentType: string): RestResult[seq[byte]] =
|
contentType: string): RestResult[seq[byte]] =
|
||||||
if MediaType.init(contentType) != MIMETYPE_JSON:
|
return encodeBytesOf(value, contentType)
|
||||||
error "Unsupported contentType value", contentType = contentType
|
|
||||||
return err("Unsupported contentType")
|
|
||||||
|
|
||||||
let encoded = ?encodeIntoJsonBytes(value)
|
|
||||||
return ok(encoded)
|
|
||||||
|
|
||||||
# TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto)
|
# 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.}
|
proc relayGetMessagesV1*(pubsubTopic: string): RestResponse[RelayGetMessagesResponse] {.rest, endpoint: "/relay/v1/messages/{pubsubTopic}", meth: HttpMethod.MethodGet.}
|
||||||
|
@ -20,6 +20,7 @@ import
|
|||||||
../../handlers,
|
../../handlers,
|
||||||
../serdes,
|
../serdes,
|
||||||
../responses,
|
../responses,
|
||||||
|
../rest_serdes,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
from std/times import getTime
|
from std/times import getTime
|
||||||
@ -55,16 +56,8 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
|
|||||||
if contentBody.isNone():
|
if contentBody.isNone():
|
||||||
return RestApiResponse.badRequest()
|
return RestApiResponse.badRequest()
|
||||||
|
|
||||||
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
|
let req: seq[PubsubTopic] = decodeRequestBody[seq[PubsubTopic]](contentBody).valueOr:
|
||||||
if reqBodyContentType != MIMETYPE_JSON:
|
return error
|
||||||
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()
|
|
||||||
|
|
||||||
# Only subscribe to topics for which we have no subscribed topic handlers yet
|
# Only subscribe to topics for which we have no subscribed topic handlers yet
|
||||||
let newTopics = req.filterIt(not cache.isSubscribed(it))
|
let newTopics = req.filterIt(not cache.isSubscribed(it))
|
||||||
@ -83,16 +76,8 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
|
|||||||
if contentBody.isNone():
|
if contentBody.isNone():
|
||||||
return RestApiResponse.badRequest()
|
return RestApiResponse.badRequest()
|
||||||
|
|
||||||
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
|
let req: seq[PubsubTopic] = decodeRequestBody[seq[PubsubTopic]](contentBody).valueOr:
|
||||||
if reqBodyContentType != MIMETYPE_JSON:
|
return error
|
||||||
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()
|
|
||||||
|
|
||||||
# Unsubscribe all handlers from requested topics
|
# Unsubscribe all handlers from requested topics
|
||||||
for pubsubTopic in req:
|
for pubsubTopic in req:
|
||||||
@ -139,21 +124,12 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
|
|||||||
if contentBody.isNone():
|
if contentBody.isNone():
|
||||||
return RestApiResponse.badRequest()
|
return RestApiResponse.badRequest()
|
||||||
|
|
||||||
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
|
let reqWakuMessage: RelayWakuMessage = decodeRequestBody[RelayWakuMessage](contentBody).valueOr:
|
||||||
if reqBodyContentType != MIMETYPE_JSON:
|
return error
|
||||||
return RestApiResponse.badRequest()
|
|
||||||
|
|
||||||
let reqBodyData = contentBody.get().data
|
var message: WakuMessage = reqWakuMessage.toWakuMessage(version = 0).valueOr:
|
||||||
let reqResult = decodeFromJsonBytes(RelayPostMessagesRequest, reqBodyData)
|
|
||||||
if reqResult.isErr():
|
|
||||||
return RestApiResponse.badRequest()
|
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 RLN is mounted, append the proof to the message
|
||||||
if not node.wakuRlnRelay.isNil():
|
if not node.wakuRlnRelay.isNil():
|
||||||
# append the proof to the message
|
# append the proof to the message
|
||||||
@ -191,16 +167,8 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
|
|||||||
if contentBody.isNone():
|
if contentBody.isNone():
|
||||||
return RestApiResponse.badRequest()
|
return RestApiResponse.badRequest()
|
||||||
|
|
||||||
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
|
let req: seq[ContentTopic] = decodeRequestBody[seq[ContentTopic]](contentBody).valueOr:
|
||||||
if reqBodyContentType != MIMETYPE_JSON:
|
return error
|
||||||
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()
|
|
||||||
|
|
||||||
# Only subscribe to topics for which we have no subscribed topic handlers yet
|
# Only subscribe to topics for which we have no subscribed topic handlers yet
|
||||||
let newTopics = req.filterIt(not cache.isSubscribed(it))
|
let newTopics = req.filterIt(not cache.isSubscribed(it))
|
||||||
@ -219,16 +187,8 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
|
|||||||
if contentBody.isNone():
|
if contentBody.isNone():
|
||||||
return RestApiResponse.badRequest()
|
return RestApiResponse.badRequest()
|
||||||
|
|
||||||
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
|
let req: seq[ContentTopic] = decodeRequestBody[seq[ContentTopic]](contentBody).valueOr:
|
||||||
if reqBodyContentType != MIMETYPE_JSON:
|
return error
|
||||||
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()
|
|
||||||
|
|
||||||
# Unsubscribe all handlers from requested topics
|
# Unsubscribe all handlers from requested topics
|
||||||
for contentTopic in req:
|
for contentTopic in req:
|
||||||
@ -266,24 +226,15 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
|
|||||||
if contentBody.isNone():
|
if contentBody.isNone():
|
||||||
return RestApiResponse.badRequest()
|
return RestApiResponse.badRequest()
|
||||||
|
|
||||||
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
|
let req: RelayWakuMessage = decodeRequestBody[RelayWakuMessage](contentBody).valueOr:
|
||||||
if reqBodyContentType != MIMETYPE_JSON:
|
return error
|
||||||
|
|
||||||
|
if req.contentTopic.isNone():
|
||||||
return RestApiResponse.badRequest()
|
return RestApiResponse.badRequest()
|
||||||
|
|
||||||
let reqBodyData = contentBody.get().data
|
var message: WakuMessage = req.toWakuMessage(version = 0).valueOr:
|
||||||
let reqResult = decodeFromJsonBytes(RelayPostMessagesRequest, reqBodyData)
|
|
||||||
if reqResult.isErr():
|
|
||||||
return RestApiResponse.badRequest()
|
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 RLN is mounted, append the proof to the message
|
||||||
if not node.wakuRlnRelay.isNil():
|
if not node.wakuRlnRelay.isNil():
|
||||||
# append the proof to the message
|
# append the proof to the message
|
||||||
|
79
waku/waku_api/rest/rest_serdes.nim
Normal file
79
waku/waku_api/rest/rest_serdes.nim
Normal 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)
|
@ -15,6 +15,7 @@ import
|
|||||||
json_serialization/std/sets,
|
json_serialization/std/sets,
|
||||||
presto/common
|
presto/common
|
||||||
|
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "waku node rest"
|
topics = "waku node rest"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user