Added registerHandlers method.
Build and Test Module / build-and-test (push) Successful in 12s
Details
Build and Test Module / build-and-test (push) Successful in 12s
Details
This commit is contained in:
parent
c1756fa648
commit
458ed2d75f
|
|
@ -204,6 +204,35 @@ class PathHandler : HttpRequestHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds mappings to this path handler which correspond to functions defined
|
||||
* in the given symbol which have been annotated with the `@PathMapping`
|
||||
* attribute.
|
||||
*/
|
||||
void registerHandlers(alias symbol)() {
|
||||
static assert(
|
||||
__traits(isModule, symbol),
|
||||
"PathHandler.registerHandlers can only be called with a module."
|
||||
);
|
||||
import std.conv: to;
|
||||
HttpRequestHandler handlerRef;
|
||||
static foreach (i, mem; __traits(allMembers, symbol)) {
|
||||
static if (isValidHandlerRegistrationTarget!(__traits(getMember, symbol, mem))) {
|
||||
mixin("alias target" ~ i.to!string ~ " = __traits(getMember, symbol, mem);");
|
||||
static foreach (attr; __traits(getAttributes, mixin("target" ~ i.to!string))) {
|
||||
static if (is(typeof(attr) == PathMapping)) {
|
||||
debugF!"Registered handler: %s -> %s"(
|
||||
attr,
|
||||
__traits(fullyQualifiedName, mixin("target" ~ i.to!string))
|
||||
);
|
||||
handlerRef = HttpRequestHandler.of(mixin("&target" ~ i.to!string));
|
||||
this.addMapping(attr.method, attr.pattern, handlerRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the handler to use to handle a given request, using our list of
|
||||
* pre-configured mappings.
|
||||
|
|
@ -235,6 +264,40 @@ class PathHandler : HttpRequestHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined attribute that, when added to a function, allows that
|
||||
* function to be registered automatically by a path handler when you call
|
||||
* its `registerHandlers` method on the module containing the function.
|
||||
*/
|
||||
struct PathMapping {
|
||||
/**
|
||||
* The HTTP method that the mapping accepts.
|
||||
*/
|
||||
HttpMethod method;
|
||||
/**
|
||||
* The path pattern for the mapping.
|
||||
*/
|
||||
string pattern;
|
||||
}
|
||||
|
||||
private bool isValidHandlerRegistrationTarget(alias symbol)() {
|
||||
import std.traits;
|
||||
static if (isFunction!(symbol)) {
|
||||
alias params = Parameters!(symbol);
|
||||
static if (params.length == 2) {
|
||||
alias paramStorageClasses = ParameterStorageClassTuple!(symbol);
|
||||
return is(params[0] == ServerHttpRequest) && is(params[1] == ServerHttpResponse) &&
|
||||
paramStorageClasses[0] == ParameterStorageClass.ref_ &&
|
||||
paramStorageClasses[1] == ParameterStorageClass.ref_ &&
|
||||
is(ReturnType!(symbol) == void);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Test PathHandler.setNotFoundHandler
|
||||
unittest {
|
||||
import std.exception;
|
||||
|
|
@ -296,3 +359,40 @@ unittest {
|
|||
auto result9 = generateHandledData(HttpMethod.POST, "/api/do-something");
|
||||
assert(result9.response.status == HttpStatus.OK);
|
||||
}
|
||||
|
||||
// Test registerHandlers
|
||||
unittest {
|
||||
import handy_http_handlers.path_handler_sample_module;
|
||||
|
||||
class C {}
|
||||
|
||||
PathHandler ph = new PathHandler();
|
||||
ph.registerHandlers!(handy_http_handlers.path_handler_sample_module);
|
||||
|
||||
// Verify that the handlers defined in the module were actually added.
|
||||
ServerHttpRequest req1 = ServerHttpRequestBuilder()
|
||||
.withMethod("GET")
|
||||
.withUrl("/h1")
|
||||
.build();
|
||||
ServerHttpResponse resp1 = ServerHttpResponseBuilder().build();
|
||||
ph.handle(req1, resp1);
|
||||
assert(resp1.status == HttpStatus.OK);
|
||||
|
||||
ServerHttpRequest req2 = ServerHttpRequestBuilder()
|
||||
.withMethod("POST")
|
||||
.withUrl("/h2")
|
||||
.build();
|
||||
ServerHttpResponse resp2 = ServerHttpResponseBuilder().build();
|
||||
ph.handle(req2, resp2);
|
||||
assert(resp2.status == HttpStatus.OK);
|
||||
|
||||
// Verify that other stuff returns a 404.
|
||||
ServerHttpRequest req3 = ServerHttpRequestBuilder()
|
||||
.withMethod("GET")
|
||||
.withUrl("/h2")
|
||||
.build();
|
||||
ServerHttpResponse resp3 = ServerHttpResponseBuilder().build();
|
||||
ph.handle(req3, resp3);
|
||||
assert(resp3.status == HttpStatus.NOT_FOUND);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* This module defines some path mapping functions to help test the path
|
||||
* handler's function for registering annotated functions.
|
||||
*/
|
||||
module handy_http_handlers.path_handler_sample_module;
|
||||
|
||||
version(unittest) {
|
||||
|
||||
import handy_http_primitives;
|
||||
import handy_http_handlers.path_handler;
|
||||
|
||||
@PathMapping(HttpMethod.GET, "/h1")
|
||||
void h1(ref ServerHttpRequest request, ref ServerHttpResponse response) {
|
||||
response.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
@PathMapping(HttpMethod.POST, "/h2")
|
||||
void h2(ref ServerHttpRequest request, ref ServerHttpResponse response) {
|
||||
response.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue