Skip to content

Commit 93aa996

Browse files
authored
Merge pull request #2806 from vibe-d/viastatus
Add viaStatus REST interface attribute.
2 parents 087499e + eab240d commit 93aa996

File tree

4 files changed

+56
-19
lines changed

4 files changed

+56
-19
lines changed

tests/rest/source/app.d

+15
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,8 @@ interface Example6API
395395
// Without a parameter, it will represent the entire body
396396
string postConcatBody(@viaBody() FooType obj);
397397

398+
int testStatus(@viaStatus out int status, @viaStatus out string status_phrase);
399+
398400
struct FooType {
399401
int a;
400402
string s;
@@ -440,6 +442,13 @@ override:
440442
{
441443
return postConcat(obj);
442444
}
445+
446+
int testStatus(out int status, out string status_phrase)
447+
{
448+
status = HTTPStatus.accepted;
449+
status_phrase = "Request accepted!";
450+
return 42;
451+
}
443452
}
444453

445454
unittest
@@ -644,6 +653,12 @@ void runTests(string url)
644653
assert(tester == "The cake is a lie", tester);
645654
assert(www == `Basic realm="Aperture"`.nullable, www.to!string);
646655
}
656+
657+
int status;
658+
string status_phrase;
659+
assert(api.testStatus(status, status_phrase) == 42);
660+
assert(status == HTTPStatus.accepted);
661+
assert(status_phrase == "Request accepted!");
647662
}
648663

649664
// Example 6 -- Query

web/vibe/web/common.d

+11-9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import vibe.http.common;
1111
import vibe.http.server : HTTPServerRequest;
1212
import vibe.data.json;
1313
import vibe.internal.meta.uda : onlyAsUda, UDATuple;
14+
import vibe.web.internal.rest.common : ParameterKind;
1415

1516
import std.meta : AliasSeq;
1617
static import std.utf;
@@ -686,8 +687,6 @@ package struct NoRouteAttribute {}
686687
* and the parameter (identifier) name of the function.
687688
*/
688689
public struct WebParamAttribute {
689-
import vibe.web.internal.rest.common : ParameterKind;
690-
691690
/// The type of the WebParamAttribute
692691
ParameterKind origin;
693692
/// Parameter name (function parameter name).
@@ -722,7 +721,6 @@ public struct WebParamAttribute {
722721
*/
723722
WebParamAttribute viaBody(string field = null)
724723
@safe {
725-
import vibe.web.internal.rest.common : ParameterKind;
726724
if (!__ctfe)
727725
assert(false, onlyAsUda!__FUNCTION__);
728726
return WebParamAttribute(ParameterKind.body_, null, field);
@@ -735,7 +733,6 @@ in {
735733
}
736734
do
737735
{
738-
import vibe.web.internal.rest.common : ParameterKind;
739736
if (!__ctfe)
740737
assert(false, onlyAsUda!__FUNCTION__);
741738
return WebParamAttribute(ParameterKind.body_, identifier, field);
@@ -744,7 +741,6 @@ do
744741
/// ditto
745742
WebParamAttribute bodyParam(string identifier)
746743
@safe {
747-
import vibe.web.internal.rest.common : ParameterKind;
748744
if (!__ctfe)
749745
assert(false, onlyAsUda!__FUNCTION__);
750746
return WebParamAttribute(ParameterKind.body_, identifier, "");
@@ -774,7 +770,6 @@ WebParamAttribute bodyParam(string identifier)
774770
*/
775771
WebParamAttribute viaHeader(string field)
776772
@safe {
777-
import vibe.web.internal.rest.common : ParameterKind;
778773
if (!__ctfe)
779774
assert(false, onlyAsUda!__FUNCTION__);
780775
return WebParamAttribute(ParameterKind.header, null, field);
@@ -783,7 +778,6 @@ WebParamAttribute viaHeader(string field)
783778
/// Ditto
784779
WebParamAttribute headerParam(string identifier, string field)
785780
@safe {
786-
import vibe.web.internal.rest.common : ParameterKind;
787781
if (!__ctfe)
788782
assert(false, onlyAsUda!__FUNCTION__);
789783
return WebParamAttribute(ParameterKind.header, identifier, field);
@@ -813,7 +807,6 @@ WebParamAttribute headerParam(string identifier, string field)
813807
*/
814808
WebParamAttribute viaQuery(string field)
815809
@safe {
816-
import vibe.web.internal.rest.common : ParameterKind;
817810
if (!__ctfe)
818811
assert(false, onlyAsUda!__FUNCTION__);
819812
return WebParamAttribute(ParameterKind.query, null, field);
@@ -822,12 +815,21 @@ WebParamAttribute viaQuery(string field)
822815
/// Ditto
823816
WebParamAttribute queryParam(string identifier, string field)
824817
@safe {
825-
import vibe.web.internal.rest.common : ParameterKind;
826818
if (!__ctfe)
827819
assert(false, onlyAsUda!__FUNCTION__);
828820
return WebParamAttribute(ParameterKind.query, identifier, field);
829821
}
830822

823+
824+
/** Declares a parameter to be transmitted via the HTTP status code or phrase.
825+
826+
This attribute can be applied to one or two `out` parameters of type
827+
`HTTPStatus`/`int` or `string`. The values of those parameters correspond
828+
to the HTTP status code or phrase, depending on the type.
829+
*/
830+
enum viaStatus = WebParamAttribute(ParameterKind.status);
831+
832+
831833
/**
832834
Determines the naming convention of an identifier.
833835
*/

web/vibe/web/internal/rest/common.d

+4-1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ import std.traits : hasUDA;
199199
case ParameterKind.internal: route.internalParameters ~= pi; break;
200200
case ParameterKind.attributed: route.attributedParameters ~= pi; break;
201201
case ParameterKind.auth: route.authParameters ~= pi; break;
202+
case ParameterKind.status: route.statusParameters ~= pi; break;
202203
}
203204
}
204205

@@ -437,6 +438,7 @@ struct Route {
437438
Parameter[] attributedParameters;
438439
Parameter[] internalParameters;
439440
Parameter[] authParameters;
441+
Parameter[] statusParameters;
440442
}
441443

442444
struct PathPart {
@@ -474,7 +476,8 @@ enum ParameterKind {
474476
header, // req.header[]
475477
attributed, // @before
476478
internal, // req.params[]
477-
auth // @authrorized!T
479+
auth, // @authrorized!T
480+
status // res.statusCode/res.statusPhrase
478481
}
479482

480483
struct SubInterface {

web/vibe/web/rest.d

+26-9
Original file line numberDiff line numberDiff line change
@@ -1623,13 +1623,20 @@ private HTTPServerRequestDelegate jsonMethodHandler(alias Func, size_t ridx, T)(
16231623
handleCors();
16241624
foreach (i, P; PTypes) {
16251625
static if (sroute.parameters[i].isOut) {
1626-
static assert (sroute.parameters[i].kind == ParameterKind.header);
1627-
static if (isInstanceOf!(Nullable, typeof(params[i]))) {
1628-
if (!params[i].isNull)
1626+
static if (sroute.parameters[i].kind == ParameterKind.header) {
1627+
static if (isInstanceOf!(Nullable, typeof(params[i]))) {
1628+
if (!params[i].isNull)
1629+
res.headers[route.parameters[i].fieldName] = to!string(params[i]);
1630+
} else {
16291631
res.headers[route.parameters[i].fieldName] = to!string(params[i]);
1630-
} else {
1631-
res.headers[route.parameters[i].fieldName] = to!string(params[i]);
1632-
}
1632+
}
1633+
} else static if (sroute.parameters[i].kind == ParameterKind.status) {
1634+
static if (is(typeof(params[i]) == HTTPStatus) || is(typeof(params[i]) == int))
1635+
res.statusCode = params[i];
1636+
else static if (is(typeof(params[i]) == string))
1637+
res.statusPhrase = params[i];
1638+
else static assert(false, "`@viaStatus` parameters must be of type `HTTPStatus`/`int` or `string`");
1639+
} else static assert (false, "`out` parameters must be annotated with either `@viaHeader` or `@viaStatus`");
16331640
}
16341641
}
16351642
}
@@ -1855,6 +1862,8 @@ private auto executeClientMethod(I, size_t ridx, ARGS...)
18551862
InetHeaderMap headers;
18561863
InetHeaderMap reqhdrs;
18571864
InetHeaderMap opthdrs;
1865+
HTTPStatus status_code;
1866+
string status_phrase;
18581867

18591868
string url_prefix;
18601869

@@ -1930,15 +1939,21 @@ private auto executeClientMethod(I, size_t ridx, ARGS...)
19301939
foreach (i, PT; PTT) {
19311940
enum sparam = sroute.parameters[i];
19321941
auto fieldname = route.parameters[i].fieldName;
1933-
static if (sparam.kind == ParameterKind.header) {
1934-
static if (sparam.isOut) {
1942+
static if (sparam.isOut) {
1943+
static if (sparam.kind == ParameterKind.header) {
19351944
static if (isInstanceOf!(Nullable, PT)) {
19361945
ARGS[i] = to!(TemplateArgsOf!PT)(
19371946
opthdrs.get(fieldname, null));
19381947
} else {
19391948
if (auto ptr = fieldname in reqhdrs)
19401949
ARGS[i] = to!PT(*ptr);
19411950
}
1951+
} else static if (sparam.kind == ParameterKind.status) {
1952+
static if (is(PT == HTTPStatus) || is(PT == int)) {
1953+
ARGS[i] = status_code;
1954+
} else static if (is(PT == string)) {
1955+
ARGS[i] = status_phrase;
1956+
}
19421957
}
19431958
}
19441959
}
@@ -1964,6 +1979,8 @@ private auto executeClientMethod(I, size_t ridx, ARGS...)
19641979
auto ret = request(URL(intf.baseURL), request_filter, request_body_filter,
19651980
sroute.method, url, headers, query.data, body_, reqhdrs, opthdrs,
19661981
intf.settings.httpClientSettings);
1982+
status_code = cast(HTTPStatus)ret.statusCode;
1983+
status_phrase = ret.statusPhrase;
19671984

19681985
static if (is(RT == InputStream)) {
19691986
return ret.bodyReader.asInterface!InputStream;
@@ -2438,7 +2455,7 @@ do {
24382455
static if (Attr.length != 1) {
24392456
if (hack) return "%s: Parameter '%s' cannot be %s"
24402457
.format(FuncId, PN[i], SC & PSC.out_ ? "out" : "ref");
2441-
} else static if (Attr[0].origin != ParameterKind.header) {
2458+
} else static if (Attr[0].origin != ParameterKind.header && Attr[0].origin != ParameterKind.status) {
24422459
if (hack) return "%s: %s parameter '%s' cannot be %s"
24432460
.format(FuncId, Attr[0].origin, PN[i],
24442461
SC & PSC.out_ ? "out" : "ref");

0 commit comments

Comments
 (0)