-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(rest-api-store): new rest api to retrieve store waku messages (#1611) #1630
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unsolicitated review, but hope it helps :)
Hey thanks ! I really appreciate it of course :) |
0ed647a
to
b9de7a5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Congratulations on your first PR! :D Approach here looks really good, but I'd like to spend some more time on a review tomorrow morning. Will leave a detailed review then.
docs/api/v2/rest-api.md
Outdated
|
||
### API Specification | ||
|
||
The HTTP REST API has been designed following the OpenAPI 3.0.3 standard specification format. The OpenAPI specification file can be found here: [TBD]() | ||
The HTTP REST API has been designed following the OpenAPI 3.0.3 standard specification format. The OpenAPI specification files can be found here: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For version-controlled documentation we generally use semantic breaks: generally this just means each sentence (or full clause) in a separate line. These breaks aren't visible in markdown renders, but does help with reviewing and maintaining docs.
@@ -0,0 +1,20 @@ | |||
# Node configuration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for including operator documentation in the PR! It's important to keep this up to date.
In general, we want every new page in the operator guide to be reachable from the landing page with a few clicks. In other words, it will be useful if this page is linked from somewhere else - I'd suggest just adding this to the configuration tutorials list in the configuration landing page
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, looks great to me 😁 ✅
Please check my comments.
|`--rest-admin` | Enable access to REST HTTP Admin API. | `false` | | ||
|`--rest-private` | Enable access to REST HTTP Private API. | `false` | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seeing these two command line options remembers me a question:
@jm-clius Shall we put each "namespaced" group of REST API endpoints behind a configuration flag (e.g., in this case,
--rest-store-client
) for configuration granularity purposes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think that's a good idea. We may just want to start by doing these as sub-commands (see: https://github.com/status-im/nim-confutils#using-sub-commands) which are only available when --rest
is enabled, in order to keep things a bit more simplified. We want to do this with other groups of config items as well, but now is a good time as ever to do this for the REST API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me. Let's tackle it in a follow-up PR :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I issued the next one:
#1652
waku/v2/node/rest/store/handlers.nim
Outdated
try: | ||
return Timestamp(parseInt(input)) | ||
except CatchableError as e: | ||
error "Error converting to Timestamp ", error=e.msg | ||
return Timestamp(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be a ValueError
, it is more specific. Additionally, we are not using the pythonic as ex
, we use: https://nim-lang.org/docs/system.html#getCurrentExceptionMsg
try: | |
return Timestamp(parseInt(input)) | |
except CatchableError as e: | |
error "Error converting to Timestamp ", error=e.msg | |
return Timestamp(0) | |
try: | |
return Timestamp(parseInt(input)) | |
except ValueError: | |
error "Error converting to Timestamp ", error= getCurrentExceptionMsg() | |
return Timestamp(0) |
This also applies to the rest of try/except
from this PR 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comment.
Actually, I realized that the management of time-parameters should be normalized, i.e. we have four possible time-parameters and the user needs a valid feedback for each of them.
waku/v2/node/rest/store/handlers.nim
Outdated
# The param must be in the format `(ip4|ip6)/tcp/p2p/$peerId` but URL-encoded | ||
proc parsePeerAddr(peerAddr: string): Result[RemotePeerInfo, string] = | ||
let parsedAddr = decodeUrl(peerAddr) | ||
debug "parsePeerAddr ", parsedAddr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging types directly without converting them to string, via $
, may lead to breaking the structured logging/json logging.
debug "parsePeerAddr ", parsedAddr | |
debug "parsePeerAddr ", parsed_addr = $parsedAddr |
waku/v2/node/rest/store/handlers.nim
Outdated
try: | ||
return Timestamp(parseInt(input)) | ||
except CatchableError as e: | ||
error "Error converting to Timestamp ", error=e.msg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not entirely convinced with this error
log level. We should be very selective when using the error log level (e.g., to avoid alarm fatigue: if everything is an error, nothing is an actual error).
If we return a default value, I don't see it as critical to being logged with an error level. I think I wouldn't log anything, but if you think this should be logged, then pick a level like debug
or trace
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I agree, I will pick debug
level in this case.
If this exception occurs, the problem comes from how the user sent the parameter, rather than an app error, so it is important to give good feedback to the user and just log in debug
.
waku/v2/node/rest/store/handlers.nim
Outdated
ascending: Option[string] | ||
) -> RestApiResponse: | ||
|
||
debug "REST-GET /store/v1/messages" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add the "peer address" to the log for debugging purposes.
waku/v2/node/rest/store/client.nim
Outdated
)) | ||
|
||
# If everything goes wrong | ||
return err("Unsupported contentType") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should cover our backs for the unknown. The more debug info that we have, the better 🙂
return err("Unsupported contentType") | |
return err("Unsupported contentType: " & $contentType) |
waku/v2/node/rest/store/handlers.nim
Outdated
let decodedPubsubTopic = decodeUrl(pubsubTopic.get()) | ||
if decodedPubsubTopic != "": | ||
parsedPubsubTopic = some(decodedPubsubTopic) | ||
debug "Setting pubsubTopic ", pubsub_topic=parsedPubsubTopic.get() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to be consistent with the logged fields name style: sometimes you use the snake_case
; others you use camelCase
(e.g., parsedAddr
). IMO, we should stick with snake_case
.
waku/v2/node/rest/store/handlers.nim
Outdated
# Parse ascending field | ||
var parsedAscending = true | ||
if ascending.isSome() and ascending.get() != "": | ||
parsedAscending = ascending.get() == "1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ascending
field must be true
or false
(default value is not present). We should avoid the 1/0 on/off yes/no true/false
support war.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Completely agree but I couldn't manage to use an Option[bool] given how the nim-presto library parses the route-api code, which only accepts string types:
For now I can only make it to handle "true" or "false" strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW. To review the generated documentation, here you can use redocly online to preview this OpenAPI specification file:
waku/v2/node/rest/store/openapi.yaml
Outdated
- name: ascending | ||
in: query | ||
schema: | ||
type: string | ||
description: > | ||
"1" for paging forward, "0" for paging backward | ||
example: '1' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not convinced with the 1
. In my opinion this should be a boolean: true
or false
.
From the OpenAPI docs: https://swagger.io/docs/specification/data-models/data-types/#boolean
type: boolean represents two values:
true
andfalse
. Note that truthy and falsy values such as"true"
,""
,0
ornull
are not considered boolean values.
- name: ascending | |
in: query | |
schema: | |
type: string | |
description: > | |
"1" for paging forward, "0" for paging backward | |
example: '1' | |
- name: ascending | |
in: query | |
schema: | |
type: boolean | |
description: > | |
"true" for paging forward, "false" for paging backward | |
example: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now I'd use 'string' as per #1630 (comment)
@@ -0,0 +1,534 @@ | |||
{.used.} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't find test_rest_store.nim
in https://github.com/waku-org/nwaku/blob/issue-1076-store-rest-api/tests/all_tests_v2.nim so not sure this test is being run with make test2
and consecuently in CI. Mind checking this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
@Ivansete-status For a test suite to be executed. It is required that a test suite file is imported by one of the all_tests_*.nim
files (in this case all_tests_v2.nim
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will get added in next commit. Thanks!
|
||
node.peerManager.addServicePeer(remotePeerInfo, | ||
WakuStoreCodec) | ||
peerSwitch.mount(node.wakuRelay) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure i understand this. node
and peerSwitch
are different libp2p peers right? So seems weird to me to mount the relay of one in the other, unless im missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Morning @alrevuelta , you are absolutely right that this code is superfluous. It was inspired by procSuite "Waku v2 JSON-RPC API - Store".
I will remove the wakuRelay references.
Thanks !
waku/v2/node/rest/store/handlers.nim
Outdated
|
||
# Checks whether the peerAddr parameter represents a valid p2p multiaddress. | ||
# The param must be in the format `(ip4|ip6)/tcp/p2p/$peerId` but URL-encoded | ||
proc parsePeerAddr(peerAddr: string): Result[RemotePeerInfo, string] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps move to utils/peers.nim?
since its very similar to parseRemotePeerInfo
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, will be in utils/peers.nim in the next commit. We are planning to modify the current parseRemotePeerInfo
in further PR's so that it doesn't raise any exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've now done a detailed read of the code and this LGTM. Well done and thanks (also for your insights here, @LNSD)!
waku/v2/node/rest/store/handlers.nim
Outdated
|
||
# Queries the store-node with the query parameters and | ||
# returns a RestApiResponse that is sent back to the api client. | ||
proc makeHistoryQuery(selfNode: WakuNode, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick, but perhaps something like performHistoryQuery
is a better proc name here? To me, make
sounds similar to create
. :)
78df82f
to
37edab1
Compare
…1611) * feat: new rest api based on the current store json-rpc api and following the same structure as the current relay rest api. * feat: the store api attend GET requests to retrieve historical messages * feat: unit tests. * feat: allow return message to rest-client in case error (4XX or 5XX) * chore: always allow to call the store api endpoints (only rest) without explicit storenode (#1575) * feat: always mounting the current node as storenode client
37edab1
to
bca0731
Compare
Thank you all for the reviews! Together we brought a good step forward. |
Issue
feat: HTTP REST API: Store Client API #1611
Comments
Possible enhancements
How to test it
Unit tests
Run the next commands from the repo root folder:
Manually
All commands from nwaku root folder.
Build the wakunode2:
Start a node "A".
Start a store node "B". This will store the messages.
Send a few messages to node "A".
Once both nodes are running, now send Store-Rest requests to node "A".
All the GET parameters should be passed URL-encoded.