From 3c6906aed040aba8c543567b7cefb8a4c09fc63f Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Tue, 18 Jul 2017 16:20:32 +0200 Subject: [PATCH] Auto-(de)serialize Json for vibe.web.web --- tests/vibe.web.web/source/app.d | 38 +++++++++++++++++++++++++++------ web/vibe/web/web.d | 16 ++++++++++++-- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/tests/vibe.web.web/source/app.d b/tests/vibe.web.web/source/app.d index 51fafb3a38..3a7e5f22d5 100644 --- a/tests/vibe.web.web/source/app.d +++ b/tests/vibe.web.web/source/app.d @@ -2,6 +2,7 @@ module app; import vibe.core.core; import vibe.core.log; +import vibe.data.json; import vibe.http.client; import vibe.http.router; import vibe.http.server; @@ -10,6 +11,19 @@ import std.format : format; // TODO: test the various parameter and return type combinations, as well as all attributes +struct MyStruct +{ + int foo = 2; +} + +class Service { + @noRoute void getFoo(HTTPServerResponse res) { res.writeBody("oops"); } + void getBar(HTTPServerResponse res) { res.writeBody("ok"); } + // for POST/PUT requests: incoming objects are automatically serialized to Json + // by default an unknown return type is serialized to Json + auto postStruct(MyStruct st) { return st.foo + 3; } +} + shared static this() { auto settings = new HTTPServerSettings; @@ -21,7 +35,18 @@ shared static this() runTask({ scope (exit) exitEventLoop(); - + void postJson(V)(string url, V[string] payload, HTTPStatus expected, scope void delegate(scope HTTPClientResponse res) expectedHandler) { + requestHTTP("http://127.0.0.1:9132"~url, + (scope req) { + req.method = HTTPMethod.POST; + req.writeJsonBody(payload); + }, + (scope res) { + assert(res.statusCode == expected, format("Unexpected status code for %s: %s", url, res.statusCode)); + expectedHandler(res); + } + ); + } void test(string url, HTTPStatus expected) { requestHTTP("http://" ~ serverAddr.toString ~ url, (scope req) { @@ -34,11 +59,12 @@ shared static this() } test("/foo", HTTPStatus.notFound); test("/bar", HTTPStatus.ok); + + postJson("/struct", ["foo": 5], HTTPStatus.ok, (scope res) { + auto j = res.readJson; + assert(j.get!int == 8); + }); + logInfo("All web tests succeeded."); }); } - -class Service { - @noRoute void getFoo(HTTPServerResponse res) { res.writeBody("oops"); } - void getBar(HTTPServerResponse res) { res.writeBody("ok"); } -} diff --git a/web/vibe/web/web.d b/web/vibe/web/web.d index 18028764a0..e3d2220169 100644 --- a/web/vibe/web/web.d +++ b/web/vibe/web/web.d @@ -923,8 +923,18 @@ private void handleRequest(string M, alias overload, C, ERROR...)(HTTPServerRequ } else static if (is(PT == bool)) { params[i] = param_names[i] in req.form || param_names[i] in req.query; } else { + import std.algorithm.comparison : among; + enum has_default = !is(default_values[i] == void); - ParamResult pres = readFormParamRec(req, params[i], param_names[i], !has_default, nested_style, err); + ParamResult pres = void; + // For POST/PUT requests, parameters are usually sent via JSON + if (req.method.among(HTTPMethod.POST, HTTPMethod.PUT) && req.json.type != Json.Type.undefined && i == 0) { + params[i].setVoid(req.json.deserializeJson!PT); + pres = ParamResult.ok; + } else { + // otherwise try to read the parameters from a query forms + pres = readFormParamRec(req, params[i], param_names[i], !has_default, nested_style, err); + } static if (has_default) { if (pres == ParamResult.skipped) params[i].setVoid(default_values[i]); @@ -1021,7 +1031,9 @@ private void handleRequest(string M, alias overload, C, ERROR...)(HTTPServerRequ res.writeBody(ret); } } else { - static assert(is(RET == void), M~": Only InputStream, Json and void are supported as return types for route methods."); + // Serialize to Json by default + static if (!is(RET : void)) + res.writeJsonBody(ret); } } } catch (Exception ex) {