aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--nimtwirp/generator.nim39
-rw-r--r--nimtwirp/nimtwirp.nim17
3 files changed, 48 insertions, 10 deletions
diff --git a/README.md b/README.md
index 133c826..183e89f 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ See the `example` directory for an example.
- [x] server generation from protobuf Service definition
- [x] client generation from protobuf Service definition
- [x] protobuf input/output
-- [ ] json input/output
+- [x] json input/output
- [x] asynchronous server
- [x] synchronous client
- [x] can serve multiple services easily (see [examples/multiservice](examples/multiservice))
diff --git a/nimtwirp/generator.nim b/nimtwirp/generator.nim
index e3f94b2..1ad9b96 100644
--- a/nimtwirp/generator.nim
+++ b/nimtwirp/generator.nim
@@ -54,7 +54,7 @@ proc new{service.name}*(): {service.name} =
new(result)
proc handleRequest*(service: {service.name}, req: Request): Future[nimtwirp.Response] {{.async.}} =
- let (_, methodName) = validateRequest(req, {service.name}Prefix)
+ let (contentType, methodName) = validateRequest(req, {service.name}Prefix)
"""
@@ -64,9 +64,20 @@ proc handleRequest*(service: {service.name}, req: Request): Future[nimtwirp.Resp
ifel = "elif"
result &= &"""
{ifel} methodName == "{meth.name}":
- let inputMsg = new{meth.inputType}(req.body)
+ var inputMsg: {meth.inputType}
+
+ if contentType == "application/protobuf":
+ inputMsg = new{meth.inputType}(req.body)
+ elif contentType == "application/json":
+ let node = parseJson(req.body)
+ inputMsg = parse{meth.inputType}(node)
+
let outputMsg = await {meth.name}(service, inputMsg)
- return nimtwirp.newResponse(serialize(outputMsg))
+
+ if contentType == "application/protobuf":
+ return nimtwirp.newResponse(serialize(outputMsg))
+ elif contentType == "application/json":
+ return nimtwirp.newResponse(toJson(outputMsg))
"""
result &= &"""
@@ -81,10 +92,15 @@ proc genClient(service: Service, prefix: string): string =
type
{service.name}Client* = ref object of nimtwirp.Client
-proc new{service.name}Client*(address: string): {service.name}Client =
+proc new{service.name}Client*(address: string, kind = ClientKind.Protobuf): {service.name}Client =
new(result)
result.client = newHttpClient()
- result.client.headers = newHttpHeaders({{"Content-Type": "application/protobuf"}})
+ result.kind = kind
+ case kind
+ of ClientKind.Protobuf:
+ result.client.headers = newHttpHeaders({{"Content-Type": "application/protobuf"}})
+ of ClientKind.Json:
+ result.client.headers = newHttpHeaders({{"Content-Type": "application/json"}})
result.address = address
"""
@@ -92,9 +108,18 @@ proc new{service.name}Client*(address: string): {service.name}Client =
for meth in service.methods:
result &= &"""
proc {meth.name}*(client: {service.name}Client, req: {meth.inputType}): {meth.outputType} =
- let body = serialize(req)
+ var body: string
+ case client.kind
+ of ClientKind.Protobuf:
+ body = serialize(req)
+ of ClientKind.Json:
+ body = $toJson(req)
let resp = request(client, {service.name}Prefix, "{meth.name}", body)
- result = new{meth.outputType}(resp.body)
+ case client.kind
+ of ClientKind.Protobuf:
+ result = new{meth.outputType}(resp.body)
+ of ClientKind.Json:
+ result = parse{meth.outputType}(parseJson(resp.body))
"""
diff --git a/nimtwirp/nimtwirp.nim b/nimtwirp/nimtwirp.nim
index f3fa29d..242e2f1 100644
--- a/nimtwirp/nimtwirp.nim
+++ b/nimtwirp/nimtwirp.nim
@@ -23,6 +23,11 @@ type
Client* = ref object of RootObj
client*: HttpClient
address*: string
+ kind*: ClientKind
+
+ ClientKind* {.pure.} = enum
+ Protobuf
+ Json
proc respond*(req: asynchttpserver.Request, resp: nimtwirp.Response): Future[void] =
req.respond(resp.code, resp.body, resp.headers)
@@ -46,6 +51,13 @@ proc newResponse*(body: string): nimtwirp.Response =
result.body = body
result.headers = newHttpHeaders({"Content-Type": "application/protobuf"})
+proc newResponse*(node: JsonNode): nimtwirp.Response =
+ new(result)
+ result.code = Http200
+ result.body = newStringOfCap(512)
+ toUgly(result.body, node)
+ result.headers = newHttpHeaders({"Content-Type": "application/json"})
+
proc handleHttpRequest(request: asynchttpserver.Request, handler: ServeHandlerProc) {.async.} =
var fut = handler(request)
@@ -124,9 +136,10 @@ proc validateRequest*(request: asynchttpserver.Request, prefix: string): tuple[c
result.contentType = getOrDefault(request.headers, "Content-Type")
- if result.contentType != "application/protobuf":
+ if result.contentType != "application/protobuf" and
+ result.contentType != "application/json":
raise newTwirpError(TwirpInternal,
- "expected Content-Type to be application/protobuf instead of " &
+ "expected Content-Type to be application/protobuf or application/json instead of " &
result.contentType)
if not startsWith(request.url.path, prefix):