From e8d1484b3c5ca7b7b3f61abeb97d15b3518b4bb4 Mon Sep 17 00:00:00 2001 From: Simon-Pierre Vivier Date: Tue, 26 Sep 2023 15:53:46 -0400 Subject: [PATCH] feat: added RELAY openapi definitions (#2081) --- tests/wakunode_rest/test_rest_relay.nim | 14 +-- waku/waku_api/rest/relay/client.nim | 16 +-- waku/waku_api/rest/relay/handlers.nim | 42 ++++---- waku/waku_api/rest/relay/openapi.yaml | 134 ++++++++++++++++++++---- waku/waku_api/rest/relay/types.nim | 5 - 5 files changed, 149 insertions(+), 62 deletions(-) diff --git a/tests/wakunode_rest/test_rest_relay.nim b/tests/wakunode_rest/test_rest_relay.nim index be444c3e9..e3fc2130b 100644 --- a/tests/wakunode_rest/test_rest_relay.nim +++ b/tests/wakunode_rest/test_rest_relay.nim @@ -57,8 +57,7 @@ suite "Waku v2 Rest API - Relay": # When let client = newRestHttpClient(initTAddress(restAddress, restPort)) - let requestBody = RelayPostSubscriptionsRequest(pubSubTopics) - let response = await client.relayPostSubscriptionsV1(requestBody) + let response = await client.relayPostSubscriptionsV1(pubSubTopics) # Then check: @@ -111,8 +110,7 @@ suite "Waku v2 Rest API - Relay": # When let client = newRestHttpClient(initTAddress(restAddress, restPort)) - let requestBody = RelayDeleteSubscriptionsRequest(pubSubTopics) - let response = await client.relayDeleteSubscriptionsV1(requestBody) + let response = await client.relayDeleteSubscriptionsV1(pubSubTopics) # Then check: @@ -256,8 +254,7 @@ suite "Waku v2 Rest API - Relay": # When let client = newRestHttpClient(initTAddress(restAddress, restPort)) - let requestBody = RelayPostSubscriptionsRequest(contentTopics) - let response = await client.relayPostAutoSubscriptionsV1(requestBody) + let response = await client.relayPostAutoSubscriptionsV1(contentTopics) # Then check: @@ -306,8 +303,7 @@ suite "Waku v2 Rest API - Relay": # When let client = newRestHttpClient(initTAddress(restAddress, restPort)) - let requestBody = RelayDeleteSubscriptionsRequest(contentTopics) - let response = await client.relayDeleteAutoSubscriptionsV1(requestBody) + let response = await client.relayDeleteAutoSubscriptionsV1(contentTopics) # Then check: @@ -400,7 +396,7 @@ suite "Waku v2 Rest API - Relay": toSeq(node.wakuRelay.subscribedTopics).len == 1 # When - let response = await client.relayPostAutoMessagesV1(DefaultContentTopic, RelayWakuMessage( + let response = await client.relayPostAutoMessagesV1(RelayWakuMessage( payload: base64.encode("TEST-PAYLOAD"), contentTopic: some(DefaultContentTopic), timestamp: some(int64(2022)) diff --git a/waku/waku_api/rest/relay/client.nim b/waku/waku_api/rest/relay/client.nim index 46bdb6464..65f12e19d 100644 --- a/waku/waku_api/rest/relay/client.nim +++ b/waku/waku_api/rest/relay/client.nim @@ -45,12 +45,12 @@ proc decodeBytes*(t: typedesc[string], value: openarray[byte], return ok(res) # TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto) -proc relayPostSubscriptionsV1*(body: RelayPostSubscriptionsRequest): RestResponse[string] {.rest, endpoint: "/relay/v1/subscriptions", meth: HttpMethod.MethodPost.} -proc relayPostAutoSubscriptionsV1*(body: RelayPostSubscriptionsRequest): RestResponse[string] {.rest, endpoint: "/relay/v1/auto/subscriptions", meth: HttpMethod.MethodPost.} +proc relayPostSubscriptionsV1*(body: seq[PubsubTopic]): RestResponse[string] {.rest, endpoint: "/relay/v1/subscriptions", meth: HttpMethod.MethodPost.} +proc relayPostAutoSubscriptionsV1*(body: seq[ContentTopic]): RestResponse[string] {.rest, endpoint: "/relay/v1/auto/subscriptions", meth: HttpMethod.MethodPost.} # TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto) -proc relayDeleteSubscriptionsV1*(body: RelayDeleteSubscriptionsRequest): RestResponse[string] {.rest, endpoint: "/relay/v1/subscriptions", meth: HttpMethod.MethodDelete.} -proc relayDeleteAutoSubscriptionsV1*(body: RelayDeleteSubscriptionsRequest): RestResponse[string] {.rest, endpoint: "/relay/v1/auto/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 decodeBytes*(t: typedesc[RelayGetMessagesResponse], data: openArray[byte], contentType: Opt[ContentTypeData]): RestResult[RelayGetMessagesResponse] = if MediaType.init($contentType) != MIMETYPE_JSON: @@ -70,9 +70,9 @@ proc encodeBytes*(value: RelayPostMessagesRequest, return ok(encoded) # TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto) -proc relayGetMessagesV1*(topic: string): RestResponse[RelayGetMessagesResponse] {.rest, endpoint: "/relay/v1/messages/{topic}", meth: HttpMethod.MethodGet.} -proc relayGetAutoMessagesV1*(topic: string): RestResponse[RelayGetMessagesResponse] {.rest, endpoint: "/relay/v1/auto/messages/{topic}", meth: HttpMethod.MethodGet.} +proc relayGetMessagesV1*(pubsubTopic: string): RestResponse[RelayGetMessagesResponse] {.rest, endpoint: "/relay/v1/messages/{pubsubTopic}", meth: HttpMethod.MethodGet.} +proc relayGetAutoMessagesV1*(contentTopic: string): RestResponse[RelayGetMessagesResponse] {.rest, endpoint: "/relay/v1/auto/messages/{contentTopic}", meth: HttpMethod.MethodGet.} # TODO: Check how we can use a constant to set the method endpoint (improve "rest" pragma under nim-presto) -proc relayPostMessagesV1*(topic: string, body: RelayPostMessagesRequest): RestResponse[string] {.rest, endpoint: "/relay/v1/messages/{topic}", meth: HttpMethod.MethodPost.} -proc relayPostAutoMessagesV1*(topic: string, body: RelayPostMessagesRequest): RestResponse[string] {.rest, endpoint: "/relay/v1/auto/messages/{topic}", meth: HttpMethod.MethodPost.} +proc relayPostMessagesV1*(pubsubTopic: string, body: RelayPostMessagesRequest): RestResponse[string] {.rest, endpoint: "/relay/v1/messages/{pubsubTopic}", meth: HttpMethod.MethodPost.} +proc relayPostAutoMessagesV1*(body: RelayPostMessagesRequest): RestResponse[string] {.rest, endpoint: "/relay/v1/auto/messages", meth: HttpMethod.MethodPost.} diff --git a/waku/waku_api/rest/relay/handlers.nim b/waku/waku_api/rest/relay/handlers.nim index 6e74db8be..72631a227 100644 --- a/waku/waku_api/rest/relay/handlers.nim +++ b/waku/waku_api/rest/relay/handlers.nim @@ -15,7 +15,6 @@ import ../../../waku_node, ../../../waku_relay/protocol, ../../../waku_rln_relay, - ../../../waku_rln_relay/rln/wrappers, ../../../node/waku_node, ../../message_cache, ../../cache_handlers, @@ -42,9 +41,10 @@ const futTimeout* = 5.seconds # Max time to wait for futures #### Request handlers const ROUTE_RELAY_SUBSCRIPTIONSV1* = "/relay/v1/subscriptions" -const ROUTE_RELAY_MESSAGESV1* = "/relay/v1/messages/{topic}" +const ROUTE_RELAY_MESSAGESV1* = "/relay/v1/messages/{pubsubTopic}" const ROUTE_RELAY_AUTO_SUBSCRIPTIONSV1* = "/relay/v1/auto/subscriptions" -const ROUTE_RELAY_AUTO_MESSAGESV1* = "/relay/v1/auto/messages/{topic}" +const ROUTE_RELAY_AUTO_MESSAGESV1* = "/relay/v1/auto/messages/{contentTopic}" +const ROUTE_RELAY_AUTO_MESSAGESV1_NO_TOPIC* = "/relay/v1/auto/messages" proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: MessageCache[string]) = router.api(MethodPost, ROUTE_RELAY_SUBSCRIPTIONSV1) do (contentBody: Option[ContentBody]) -> RestApiResponse: @@ -60,11 +60,11 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes return RestApiResponse.badRequest() let reqBodyData = contentBody.get().data - let reqResult = decodeFromJsonBytes(RelayPostSubscriptionsRequest, reqBodyData) + let reqResult = decodeFromJsonBytes(seq[PubsubTopic], reqBodyData) if reqResult.isErr(): return RestApiResponse.badRequest() - let req: RelayPostSubscriptionsRequest = reqResult.get() + let req: seq[PubsubTopic] = reqResult.get() # Only subscribe to topics for which we have no subscribed topic handlers yet let newTopics = req.filterIt(not cache.isSubscribed(it)) @@ -88,11 +88,11 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes return RestApiResponse.badRequest() let reqBodyData = contentBody.get().data - let reqResult = decodeFromJsonBytes(RelayDeleteSubscriptionsRequest, reqBodyData) + let reqResult = decodeFromJsonBytes(seq[PubsubTopic], reqBodyData) if reqResult.isErr(): return RestApiResponse.badRequest() - let req: RelayDeleteSubscriptionsRequest = reqResult.get() + let req: seq[PubsubTopic] = reqResult.get() # Unsubscribe all handlers from requested topics for pubsubTopic in req: @@ -102,15 +102,15 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes # Successfully unsubscribed from all requested topics return RestApiResponse.ok() - router.api(MethodGet, ROUTE_RELAY_MESSAGESV1) do (topic: string) -> RestApiResponse: + router.api(MethodGet, ROUTE_RELAY_MESSAGESV1) do (pubsubTopic: string) -> RestApiResponse: # ## Returns all WakuMessages received on a PubSub topic since the # ## last time this method was called # ## TODO: ability to specify a return message limit # debug "get_waku_v2_relay_v1_messages", topic=topic - if topic.isErr(): + if pubsubTopic.isErr(): return RestApiResponse.badRequest() - let pubSubTopic = topic.get() + let pubSubTopic = pubsubTopic.get() let messages = cache.getMessages(pubSubTopic, clear=true) if messages.isErr(): @@ -125,10 +125,10 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes return resp.get() - router.api(MethodPost, ROUTE_RELAY_MESSAGESV1) do (topic: string, contentBody: Option[ContentBody]) -> RestApiResponse: - if topic.isErr(): + router.api(MethodPost, ROUTE_RELAY_MESSAGESV1) do (pubsubTopic: string, contentBody: Option[ContentBody]) -> RestApiResponse: + if pubsubTopic.isErr(): return RestApiResponse.badRequest() - let pubSubTopic = topic.get() + let pubSubTopic = pubsubTopic.get() # ensure the node is subscribed to the topic. otherwise it risks publishing # to a topic with no connected peers @@ -196,11 +196,11 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes return RestApiResponse.badRequest() let reqBodyData = contentBody.get().data - let reqResult = decodeFromJsonBytes(RelayPostSubscriptionsRequest, reqBodyData) + let reqResult = decodeFromJsonBytes(seq[ContentTopic], reqBodyData) if reqResult.isErr(): return RestApiResponse.badRequest() - let req: RelayPostSubscriptionsRequest = reqResult.get() + let req: seq[ContentTopic] = reqResult.get() # Only subscribe to topics for which we have no subscribed topic handlers yet let newTopics = req.filterIt(not cache.isSubscribed(it)) @@ -224,11 +224,11 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes return RestApiResponse.badRequest() let reqBodyData = contentBody.get().data - let reqResult = decodeFromJsonBytes(RelayDeleteSubscriptionsRequest, reqBodyData) + let reqResult = decodeFromJsonBytes(seq[ContentTopic], reqBodyData) if reqResult.isErr(): return RestApiResponse.badRequest() - let req: RelayDeleteSubscriptionsRequest = reqResult.get() + let req: seq[ContentTopic] = reqResult.get() # Unsubscribe all handlers from requested topics for contentTopic in req: @@ -238,15 +238,15 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes # Successfully unsubscribed from all requested topics return RestApiResponse.ok() - router.api(MethodGet, ROUTE_RELAY_AUTO_MESSAGESV1) do (topic: string) -> RestApiResponse: + router.api(MethodGet, ROUTE_RELAY_AUTO_MESSAGESV1) do (contentTopic: string) -> RestApiResponse: # ## Returns all WakuMessages received on a content topic since the # ## last time this method was called # ## TODO: ability to specify a return message limit # debug "get_waku_v2_relay_v1_auto_messages", topic=topic - if topic.isErr(): + if contentTopic.isErr(): return RestApiResponse.badRequest() - let contentTopic = topic.get() + let contentTopic = contentTopic.get() let messages = cache.getMessages(contentTopic, clear=true) if messages.isErr(): @@ -261,7 +261,7 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes return resp.get() - router.api(MethodPost, ROUTE_RELAY_AUTO_MESSAGESV1) do (topic: string, contentBody: Option[ContentBody]) -> RestApiResponse: + router.api(MethodPost, ROUTE_RELAY_AUTO_MESSAGESV1_NO_TOPIC) do (contentBody: Option[ContentBody]) -> RestApiResponse: # Check the request body if contentBody.isNone(): return RestApiResponse.badRequest() diff --git a/waku/waku_api/rest/relay/openapi.yaml b/waku/waku_api/rest/relay/openapi.yaml index 3b356bb31..9e20653ad 100644 --- a/waku/waku_api/rest/relay/openapi.yaml +++ b/waku/waku_api/rest/relay/openapi.yaml @@ -11,7 +11,7 @@ tags: description: Relay REST API for WakuV2 node paths: - /relay/v1/messages/{topic}: # Note the plural in messages + /relay/v1/messages/{pubsubTopic}: # Note the plural in messages get: # get_waku_v2_relay_v1_messages summary: Get the latest messages on the polled topic description: Get a list of messages that were received on a subscribed PubSub topic after the last time this method was called. @@ -20,7 +20,7 @@ paths: - relay parameters: - in: path - name: topic # Note the name is the same as in the path + name: pubsubTopic # Note the name is the same as in the path required: true schema: type: string @@ -32,7 +32,8 @@ paths: application/json: schema: $ref: '#/components/schemas/RelayGetMessagesResponse' - # TODO: Review the possible errors of this endpoint + '4XX': + description: Bad request. '5XX': description: Unexpected error. @@ -44,7 +45,7 @@ paths: - relay parameters: - in: path - name: topic # Note the name is the same as in the path + name: pubsubTopic # Note the name is the same as in the path description: The messages content topic required: true schema: @@ -57,7 +58,8 @@ paths: responses: '200': description: OK - # TODO: Review the possible errors of this endpoint + '4XX': + description: Bad request. '5XX': description: Unexpected error. @@ -72,7 +74,9 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/RelayPostSubscriptionsRequest' + type array: + items: + $ref: '#/components/schemas/PubsubTopic' responses: '200': description: OK @@ -80,7 +84,8 @@ paths: text/plain: schema: type: string - # TODO: Review the possible errors of this endpoint + '4XX': + description: Bad request. '5XX': description: Unexpected error. @@ -94,7 +99,9 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/RelayDeleteSubscriptionsRequest' + type array: + items: + $ref: '#/components/schemas/PubsubTopic' responses: '200': description: OK @@ -102,10 +109,109 @@ paths: text/plain: schema: type: string - # TODO: Review the possible errors of this endpoint + '4XX': + description: Bad request. '5XX': description: Unexpected error. + /relay/v1/auto/messages/{contentTopic}: # Note the plural in messages + get: # get_waku_v2_relay_v1_auto_messages + summary: Get the latest messages on the polled topic + description: Get a list of messages that were received on a subscribed Content topic after the last time this method was called. + operationId: getMessagesByTopic + tags: + - relay + parameters: + - in: path + name: contentTopic # Note the name is the same as in the path + required: true + schema: + type: string + description: The user ID + responses: + '200': + description: The latest messages on the polled topic. + content: + application/json: + schema: + $ref: '#/components/schemas/RelayGetMessagesResponse' + '4XX': + description: Bad request. + '5XX': + description: Unexpected error. + + /relay/v1/auto/messages: # Note the plural in messages + post: # post_waku_v2_relay_v1_auto_message + summary: Publish a message to be relayed + description: Publishes a message to be relayed on a Content topic. + operationId: postMessagesToTopic + tags: + - relay + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RelayPostMessagesRequest' + responses: + '200': + description: OK + '4XX': + description: Bad request. + '5XX': + description: Unexpected error. + + /relay/v1/auto/subscriptions: + post: # post_waku_v2_relay_v1_auto_subscriptions + summary: Subscribe a node to an array of topics + description: Subscribe a node to an array of Content topics. + operationId: postSubscriptions + tags: + - relay + requestBody: + content: + application/json: + schema: + type array: + items: + $ref: '#/components/schemas/ContentTopic' + responses: + '200': + description: OK + content: + text/plain: + schema: + type: string + '4XX': + description: Bad request. + '5XX': + description: Unexpected error. + + delete: # delete_waku_v2_relay_v1_auto_subscriptions + summary: Unsubscribe a node from an array of topics + description: Unsubscribe a node from an array of Content topics. + operationId: deleteSubscriptions + tags: + - relay + requestBody: + content: + application/json: + schema: + type array: + items: + $ref: '#/components/schemas/ContentTopic' + responses: + '200': + description: OK + content: + text/plain: + schema: + type: string + '4XX': + description: Bad request. + '5XX': + description: Unexpected error. + + components: schemas: PubSubTopic: @@ -135,14 +241,4 @@ components: RelayPostMessagesRequest: $ref: '#/components/schemas/RelayWakuMessage' - - RelayPostSubscriptionsRequest: - type: array - items: - $ref: '#/components/schemas/PubSubTopic' - - RelayDeleteSubscriptionsRequest: - type: array - items: - $ref: '#/components/schemas/PubSubTopic' \ No newline at end of file diff --git a/waku/waku_api/rest/relay/types.nim b/waku/waku_api/rest/relay/types.nim index f11ea40c5..76a5117b8 100644 --- a/waku/waku_api/rest/relay/types.nim +++ b/waku/waku_api/rest/relay/types.nim @@ -28,11 +28,6 @@ type RelayGetMessagesResponse* = seq[RelayWakuMessage] RelayPostMessagesRequest* = RelayWakuMessage -type - RelayPostSubscriptionsRequest* = seq[string] - RelayDeleteSubscriptionsRequest* = seq[string] - - #### Type conversion proc toRelayWakuMessage*(msg: WakuMessage): RelayWakuMessage =