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.
### attributes
appex supports optional declarative attributes on 'exported' 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(context) {
}
attribute("submit", { verbs: ["post"] } );
export function submit(context) {
}
the following demonstrates attribute cascading:
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(context) {
context.response.writeHead(200, {'content-type' : 'text/plain'});
context.response.write( JSON.stringify(context.attribute, null, 4) );
context.response.end();
}
}
}
and for something more practical..
declare var attribute;
attribute('admin', { roles : ['administrators'] )
export module admin {
export function index(context) {
var user = context.user;
if(!user.isInRole( context.attribute.roles ) ) {
}
}
}
attributes can also be looked up by calling attribute( qualifier ).
declare var attribute;
export function index(context) {
var info = attribute('other');
context.response.write( JSON.stringify(info, null, 4) );
context.response.end();
}
attribute("other", { verbs: ["get"], message:'hello' } );
export function other(context) {
context.response.write(context.attribute.message);
context.response.end();
}
### wildcard handlers
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 ? syntax.
appex wildcard handlers require the following signature:
- name - 'wildcard'
- argument[0] - 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(context, year:number, month:number, day?:number) {
console.log(year);
console.log(month);
console.log(day);
context.response.write('my blog')
context.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.
### exporting functions
appex will only export functions prefix with the TypeScript 'export' declaration. Also, exported
functions that reside in non exported modules will not be routed. 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 (context) {
private_function();
private_module.public_method();
context.response.write('testing');
context.response.end();
}
### handling 404
Use wildcard functions to catch unhandled routes.
export function index (context) {
context.response.writeHead(404, {'content-type' : 'text/plain'});
context.response.write('home page');
context.response.end();
}
export function wildcard(context, path) {
context.response.writeHead(404, {'content-type' : 'text/plain'});
context.response.write(path + ' page not found');
context.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 (context) { }
export function about (context) { }
export function contact (context) { }
export module users {
export function login (context) { }
export function logout (context) { }
}