From 7508df276d62df4c1d073f01070dc631bb7d594e Mon Sep 17 00:00:00 2001 From: Geod24 Date: Sat, 7 Mar 2015 02:29:44 +0100 Subject: [PATCH] [REST] Simplify @path handling Ultimately, we want to make @rootPathAttribute the default for interface (it's already the default behavior for methods), and remove the @rootPath attribute, because it's redundant with @path, and they currently don't overlap, @rootPath being dedicated to interfaces, and @path to method. This commit: - Document future deprecation of @rootPath and redefine @rootPath and @rootPathFromName in terms of @path; - Documents @path better; - Communicate the settings to the sub-interface; --- examples/rest/source/app.d | 1 + source/vibe/web/common.d | 61 ++++++++++++++------------------------ source/vibe/web/rest.d | 20 ++++++++----- 3 files changed, 35 insertions(+), 47 deletions(-) diff --git a/examples/rest/source/app.d b/examples/rest/source/app.d index 938c6f7753..10c904b17b 100644 --- a/examples/rest/source/app.d +++ b/examples/rest/source/app.d @@ -154,6 +154,7 @@ interface Example3API int getMyID(int id); } +@path("/") interface Example3APINested { /* In this example it will be available under "GET /nested_module/number" diff --git a/source/vibe/web/common.d b/source/vibe/web/common.d index c93a33dbba..e6f3f85fdf 100644 --- a/source/vibe/web/common.d +++ b/source/vibe/web/common.d @@ -260,7 +260,7 @@ unittest /** - UDA to defeine the ContentType for methods returning an InputStream or ubyte[] + UDA to define the ContentType for methods returning an InputStream or ubyte[] */ ContentTypeAttribute contentType(string data) { @@ -291,11 +291,20 @@ MethodAttribute method(HTTPMethod data) } /** - User Defined Attribute interface to force specific URL path n REST interface - for function in question. Path attribute is relative though, not absolute. + UDA to force a specific URL path for REST interfaces. + + This attribute can be applied either to an interface itself, in which + case it defines the root path for all methods within it, + or on any function, in which case it defines the relative path + of this method. + Path are always relative, even path on interfaces, as you can + see in the example below. + + See_Also: $(D rootPathFromName) for automatic name generation. Example: --- + @path("/foo") interface IAPI { @path("info2") getInfo(); @@ -305,8 +314,10 @@ MethodAttribute method(HTTPMethod data) shared static this() { + // Tie IAPI.getInfo to "GET /root/foo/info2" registerRestInterface!IAPI(new URLRouter(), new API(), "/root/"); - // now IAPI.getInfo is tied to "GET /root/info2" + // Or just to "GET /foo/info2" + registerRestInterface!IAPI(new URLRouter(), new API()); } --- */ @@ -319,51 +330,23 @@ PathAttribute path(string data) /** - UDA to define root URL prefix for annotated REST interface. - Empty path means deducing prefix from interface type name (see also rootPathFromName) + Will be deprecated in the next release. + Use @$(D path) instead. */ -RootPathAttribute rootPath(string path) +PathAttribute rootPath(string path) { if (!__ctfe) assert(false, onlyAsUda!__FUNCTION__); - return RootPathAttribute(path); -} -/// -unittest -{ - import vibe.http.router; - import vibe.web.rest; - - @rootPath("/oops") - interface IAPI - { - int getFoo(); - } - - class API : IAPI - { - int getFoo() - { - return 42; - } - } - - auto router = new URLRouter(); - registerRestInterface(router, new API()); - auto routes= router.getAllRoutes(); - - assert(routes[0].pattern == "/oops/foo" && routes[0].method == HTTPMethod.GET); + return PathAttribute(path); } -/** - Convenience alias - */ -@property RootPathAttribute rootPathFromName() +/// Convenience alias to generate a name from the interface's name. +@property PathAttribute rootPathFromName() { if (!__ctfe) assert(false, onlyAsUda!__FUNCTION__); - return RootPathAttribute(""); + return PathAttribute(""); } /// unittest diff --git a/source/vibe/web/rest.d b/source/vibe/web/rest.d index 9914597cd9..bc45baac95 100644 --- a/source/vibe/web/rest.d +++ b/source/vibe/web/rest.d @@ -79,7 +79,7 @@ void registerRestInterface(TImpl)(URLRouter router, TImpl instance, RestInterfac string url_prefix = settings.baseURL.path.toString(); - enum uda = findFirstUDA!(RootPathAttribute, I); + enum uda = findFirstUDA!(PathAttribute, I); static if (uda.found) { static if (uda.value.data == "") { auto path = "/" ~ adjustMethodStyle(I.stringof, settings.methodStyle); @@ -129,10 +129,12 @@ void registerRestInterface(TImpl)(URLRouter router, TImpl instance, RestInterfac ParameterTypeTuple!overload.length == 0, "Interfaces may only be returned from parameter-less functions!" ); + auto subSettings = settings.dup; + subSettings.baseURL = URL(concatURL(url_prefix, url, true)); registerRestInterface!RT( router, __traits(getMember, instance, method)(), - concatURL(url_prefix, url, true) + subSettings ); } else { // normal handler @@ -180,6 +182,7 @@ void registerRestInterface(TImpl)(URLRouter router, TImpl instance, string url_p */ unittest { + @path("/") interface IMyAPI { // GET /api/greeting @@ -287,7 +290,7 @@ class RestInterfaceClient(I) : I } URL url = settings.baseURL; - enum uda = findFirstUDA!(RootPathAttribute, I); + enum uda = findFirstUDA!(PathAttribute, I); static if (uda.found) { static if (uda.value.data == "") { url.path = Path(concatURL(url.path.toString(), adjustMethodStyle(I.stringof, settings.methodStyle), true)); @@ -474,6 +477,7 @@ class RestInterfaceClient(I) : I /// unittest { + @path("/") interface IMyApi { // GET /status @@ -1251,11 +1255,11 @@ unittest { enum FuncId = "vibe.web.rest.__unittestLXXXX_XXX.IGithubPR.getPullRequests"; enum msg = ": Path contains ':owner', but not parameter '_owner' defined."; - @rootPath("/repos/") - interface IGithubPR { - @path(":owner/:repo/pulls") - string getPullRequests(string owner, string repo); - } + @path("/repos/") + interface IGithubPR { + @path(":owner/:repo/pulls") + string getPullRequests(string owner, string repo); + } static assert(getInterfaceValidationError!(IGithubPR) && msg == getInterfaceValidationError!(IGithubPR)[FuncId.length..$], getInterfaceValidationError!(IGithubPR));