feat(waku rest): Initial implementation of waku rest api

This commit is contained in:
Emil Ivanichkov 2024-03-13 14:49:12 +02:00 committed by Emil Ivanichkov
parent 21c3d92aa8
commit 618884c0e2
6 changed files with 127 additions and 5 deletions

View File

@ -0,0 +1,57 @@
import
# Nimble packages
chronicles,
presto/[route, segpath, server],
serialization, json_serialization,
# Local packages
./types,
../../[rest_constants, rest_serialization],
../../../waku,
../../../../../libs/waku_utils/waku_pair
proc wakuApiError(status: HttpCode, msg: string): RestApiResponse =
let data =
block:
var default: string
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.beginRecord()
writer.writeField("message", msg)
writer.endRecord()
stream.getOutput(string)
except SerializationError:
default
except IOError:
default
RestApiResponse.error(status, data, "application/json")
proc installWakuApiHandlers*(router: var RestRouter,
wakuHost: ref WakuHost) =
router.api(MethodPost, "/waku/pair"
) do (contentBody: Option[ContentBody]) -> RestApiResponse:
let wakuPairData =
block:
if contentBody.isNone():
return wakuApiError(Http404, EmptyRequestBodyError)
let dres = decodeBody(WakuPairRequestData, contentBody.get())
if dres.isErr():
return wakuApiError(Http400, InvalidWakuPairObjects)
dres.get()
try:
let wakuPairResult = await wakuPair(wakuHost[].rng,
wakuHost[].wakuNode,
wakuPairData.qr,
wakuPairData.qrMessageNameTag,
wakuPairData.pubSubTopic)
wakuHost.wakuNode = wakuPairResult.wakuNode
wakuHost.wakuHandshake = wakuPairResult.wakuHandshakeResult
notice "Waku pairing successful! Request fulfilled."
return RestApiResponse.response("Successful pairing", Http200, "application/json")
except:
return wakuApiError(Http500, "Internal Server Error")

View File

@ -0,0 +1,29 @@
import
# Nimble packages
chronicles,
presto/[route, segpath, client],
serialization, json_serialization,
stew/byteutils,
# Local packages
./types,
../../common,
../../rest_serialization
proc wakuPairPlain*(body: WakuPairRequestData): RestPlainResponse {.
rest, endpoint: "/waku/pair",
meth: MethodPost.}
proc wakuPair*(client: RestClientRef, wakuPairData: WakuPairRequestData) {.async.} =
notice "Initiating Waku Pair request..."
let
resp = await client.wakuPairPlain(wakuPairData)
respMsg = string.fromBytes(resp.data)
case resp.status:
of 200:
notice "Waku Pair request successful", body=respMsg
of 400, 401, 403, 404, 500:
notice "Waku Pair request failed", status=resp.status, body=respMsg
else:
raiseUnknownStatusError(resp)

View File

@ -0,0 +1,6 @@
import waku/waku_core
type WakuPairRequestData* = object
qr*: string
qrMessageNameTag*: string
pubSubTopic*: PubsubTopic

View File

@ -1,13 +1,14 @@
import
# Standard library
std/[typetraits],
presto/[client],
# Nimble packages
chronos, confutils, presto, metrics,
chronicles, stew/io2,
# Project modules
../config.nim
../config
func restValidate*(key: string, value: string): int =
0
@ -44,3 +45,8 @@ proc init*(T: type RestServerRef,
let server = res.get()
notice "Starting REST HTTP server", url = "http://" & $server.localAddress()
server
proc raiseUnknownStatusError*(resp: RestPlainResponse) {.
noreturn, raises: [RestError].} =
let msg = "Unknown response status error (" & $resp.status & ")"
raise newException(RestError, msg)

View File

@ -0,0 +1,5 @@
const
EmptyRequestBodyError* =
"Empty request body"
InvalidWakuPairObjects* =
"Invalid Waku pair objects found"

View File

@ -6,23 +6,42 @@ import
chronos, stew/byteutils,
presto/[route, segpath, server, client],
json_serialization,
serialization
serialization,
# Local modules
./apis/waku/types
const ApplicationJsonMediaType* = MediaType.init("application/json")
createJsonFlavor RestJson
RestJson.useDefaultSerializationFor(
auto
WakuPairRequestData
)
type
DecodeTypes* =
auto
WakuPairRequestData
type
EncodeTypes* =
auto
WakuPairRequestData
proc jsonResponsePlain*(t: typedesc[RestApiResponse],
data: auto): RestApiResponse =
let res =
block:
var default: seq[byte]
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.writeValue(data)
stream.getOutput(seq[byte])
except SerializationError:
default
except IOError:
default
RestApiResponse.response(res, Http200, "application/json")
proc encodeBytes*[T: EncodeTypes](value: T,
contentType: string): RestResult[seq[byte]] =