appex is a nodejs web api framework built on top of the TypeScript programming language. It enables
developers to develop RESTful service endpoints by writing TypeScript functions, as well as providing
reflection / type and interface meta data derived from the languages type system.
### wildcard handlers
Wildcard handlers resolve their urls to their current module scope + url.
appex wildcard handlers allow for wildcard routing at a given module scope. Wildcard handlers
support 'typed' url argument mapping, as denoted by the arguments annotation.
In addition, wildcard handlers also support optional arguments. As specific with TypeScript's '?' on argument names.
appex wildcard handlers require the following signature:
- name - 'wildcard'
- argument[0] - app context
- argument[n] - 1 or more arguments to be mapped from the url
- returns - void (optional)
declare var console;
export module blogs {
export function wildcard(app, year:number, month:number, day?:number) {
console.log(year);
console.log(month);
console.log(day);
app.response.write('my blog')
app.response.end();
}
}
export function index(app) {
app.response.write('home page');
app.response.end();
}
export function wildcard(app, path) {
app.response.writeHead(404, {'content-type' : 'text/plain'});
app.response.write(path + ' not found');
app.response.end();
}
note: appex supports boolean, number, string and any annotations on wildcard arguments. if no annotation
is specified, appex interprets the argument as a string. the type 'any' is also interpreted as string.
note: wildcard functions should be declared last in any module scope. this ensures other routes
will be matched first.
### attributes
appex supports a cascading attributute scheme on modules and functions. Attributes are declaritive meta data
you can associate with appex handlers to describe characteristics on given routes. Attributes are analogous to .net attributes,
however, they also have a cascading behaviour that can be used to apply metadata for an entire scope. A concept similar to
cascading stylesheets rules.
By default, appex uses attributes for HTTP VERB matching:
declare var attribute;
attribute("contact", { verbs: ["get"] } );
export function contact(app) {
}
attribute("submit", { verbs: ["post"] } );
export function submit(app) {
}
the following demonstrates attribute cascading behavior.
declare var attribute;
attribute('foo', {a : 10})
export module foo {
attribute('foo.bar', {b : 20})
export module bar {
attribute('foo.bar.index', {c : 30})
export function index(app) {
app.response.writeHead(200, {'content-type' : 'text/plain'});
app.response.write( JSON.stringify(app.attribute, null, 4) );
app.response.end();
}
}
}
and for something more practical..
declare var attribute;
attribute('admin', { roles : ['administrators'] )
export module admin {
export function index(app) {
var user = app.user;
if(!user.isInRole( app.attribute.roles ) ) {
}
}
}
attributes can also be looked up by calling attribute( qualifier ).
declare var attribute;
attribute("other", { verbs: ["get"], message:'hello' } );
export function other(app) {
app.response.write(app.attribute.message);
app.response.end();
}
export function index(app) {
var info = attribute('other');
app.response.write( JSON.stringify(info, null, 4) );
app.response.end();
}
### exporting functions
appex will only route functions prefix with the TypeScript 'export' declarer. This rule
also applied to modules. Developers can use this to infer notions of public and private
at the http level.
consider the following example:
module private_module {
export function public_method () { }
function private_method() { }
}
function private_function() { }
export function public_function (app) {
private_function();
private_module.public_method();
app.response.write('testing');
app.response.end();
}
### handling 404
Use wildcard functions to catch unhandled routes.
export function index (app) {
app.response.writeHead(404, {'content-type' : 'text/plain'});
app.response.write('home page');
app.response.end();
}
export function wildcard(app, path) {
app.response.writeHead(404, {'content-type' : 'text/plain'});
app.response.write(path + ' page not found');
app.response.end();
}
### structuring projects
appex includes TypeScript's ability to reference source files with the 'reference' element. appex
will traverse each source files references and include it as part of the compilation.
Developers can use this functionality to logically split source files into reusable components of
functionality, as demonstrated below.
var appex = require('appex');
var app = appex ({ program : './index.ts' });
app.listen(3000);
export function index (app) { }
export function about (app) { }
export function contact (app) { }
export module users {
export function login (app) { }
export function logout (app) { }
}