Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript based REST interface client #1209

Merged
merged 8 commits into from
Sep 13, 2015
8 changes: 8 additions & 0 deletions examples/rest-js/dub.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "rest-js-example",
"description": "Simple dynamic web UI that accesses a REST interface",
"dependencies": {
"vibe-d": { "path": "../../" }
},
"versions": ["VibeDefaultMain"]
}
49 changes: 49 additions & 0 deletions examples/rest-js/source/app.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import vibe.web.rest;


// Defines a simple RESTful API
interface ITest {
// GET /compute_sum?a=...&b=...
@method(HTTPMethod.GET)
float computeSum(float a, float b);

// POST /to_console {"text": ...}
void postToConsole(string text);
}

// Local implementation that will be provided by the server
class Test : ITest {
import std.stdio;
float computeSum(float a, float b) { return a + b; }
void postToConsole(string text) { writeln(text); }
}

shared static this()
{
import vibe.core.log : logInfo;
import vibe.inet.url : URL;
import vibe.http.router : URLRouter;
import vibe.http.server : HTTPServerSettings, listenHTTP, staticTemplate;

// Set up the proper base URL, so that the JavaScript client
// will find our REST service
auto restsettings = new RestInterfaceSettings;
restsettings.baseURL = URL("http://127.0.0.1:8080/");

auto router = new URLRouter;
// Serve the generated JavaScript client at /test.js
router.get("/test.js", serveRestJSClient!ITest(restsettings));
// Serve an example page at /
// The page will use the test.js script to issue calls to the
// REST service.
router.get("/", staticTemplate!"index.dt");
// Finally register the REST interface defined above
router.registerRestInterface(new Test, restsettings);

auto settings = new HTTPServerSettings;
settings.port = 8080;
settings.bindAddresses = ["::1", "127.0.0.1"];
listenHTTP(settings, router);

logInfo("Please open http://127.0.0.1:8080/ in your browser.");
}
37 changes: 37 additions & 0 deletions examples/rest-js/views/index.dt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
doctype html
html
head
script(src="test.js")
script.
function computeSum() {
var a = document.getElementById('a').value;
var b = document.getElementById('b').value;

// perform the RESTful request using a simple function call,
// similar to RestInterfaceClient within D code
ITest.computeSum(a, b, function (r) {
// the result comes back asynchronously
document.getElementById('res').innerHTML = r;
});
}

function writeConsoleMessage() {
var text = document.getElementById('test').value;

// similar to the call above, but this time call a void
// function with no result
ITest.postToConsole(text);
}

body
h1 Calculator
input#a
| +
input#b
button(onclick="computeSum()") Compute sum
p Result:
span#res

h2 Console
input#test
button(onclick="writeConsoleMessage()") Write to console
12 changes: 8 additions & 4 deletions source/vibe/internal/meta/funcattr.d
Original file line number Diff line number Diff line change
Expand Up @@ -245,28 +245,32 @@ unittest {
/**
Processes the function return value using all @after modifiers.
*/
ReturnType!FUNCTION evaluateOutputModifiers(alias FUNCTION)(ReturnType!FUNCTION result)
ReturnType!FUNCTION evaluateOutputModifiers(alias FUNCTION, ARGS...)(ReturnType!FUNCTION result, ARGS args)
{
import std.string : format;
import std.traits : ParameterTypeTuple, ReturnType, fullyQualifiedName;
import std.typetuple : Filter;
import vibe.internal.meta.typetuple : Compare, Group;

alias output_attributes = Filter!(isOutputAttribute, __traits(getAttributes, FUNCTION));
foreach (OA; output_attributes) {
import std.typetuple : TypeTuple;

static assert (
Compare!(
Group!(ParameterTypeTuple!(OA.modificator)),
Group!(ReturnType!Function, StoredArgTypes.expand)
Group!(ReturnType!FUNCTION, ARGS)
),
format(
"Output attribute function '%s%s' argument list " ~
"does not match provided argument list %s",
fullyQualifiedName!(OA.modificator),
ParameterTypeTuple!(OA.modificator).stringof,
TypeTuple!(ReturnType!Function, StoredArgTypes.expand).stringof
TypeTuple!(ReturnType!FUNCTION, ARGS).stringof
)
);

result = OA.modificator(result, m_storedArgs);
result = OA.modificator(result, args);
}
return result;
}
Expand Down
17 changes: 8 additions & 9 deletions source/vibe/web/common.d
Original file line number Diff line number Diff line change
Expand Up @@ -451,13 +451,9 @@ package struct PathAttribute

/// Private struct describing the origin of a parameter (Query, Header, Body).
package struct WebParamAttribute {
enum Origin {
Body,
Header,
Query,
}
import vibe.web.internal.rest.common : ParameterKind;

Origin origin;
ParameterKind origin;
/// Parameter name
string identifier;
/// The meaning of this field depends on the origin.
Expand All @@ -482,9 +478,10 @@ package struct WebParamAttribute {
* ----
*/
WebParamAttribute bodyParam(string identifier, string field) {
import vibe.web.internal.rest.common : ParameterKind;
if (!__ctfe)
assert(false, onlyAsUda!__FUNCTION__);
return WebParamAttribute(WebParamAttribute.Origin.Body, identifier, field);
return WebParamAttribute(ParameterKind.body_, identifier, field);
}

/**
Expand All @@ -506,9 +503,10 @@ WebParamAttribute bodyParam(string identifier, string field) {
*/
WebParamAttribute headerParam(string identifier, string field)
{
import vibe.web.internal.rest.common : ParameterKind;
if (!__ctfe)
assert(false, onlyAsUda!__FUNCTION__);
return WebParamAttribute(WebParamAttribute.Origin.Header, identifier, field);
return WebParamAttribute(ParameterKind.header, identifier, field);
}

/**
Expand All @@ -530,9 +528,10 @@ WebParamAttribute headerParam(string identifier, string field)
*/
WebParamAttribute queryParam(string identifier, string field)
{
import vibe.web.internal.rest.common : ParameterKind;
if (!__ctfe)
assert(false, onlyAsUda!__FUNCTION__);
return WebParamAttribute(WebParamAttribute.Origin.Query, identifier, field);
return WebParamAttribute(ParameterKind.query, identifier, field);
}

/**
Expand Down
Loading