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();
}
### json handlers
appex json handlers are geared towards handling json based http requests. appex json handlers
are invoked via HTTP POST and expect JSON to be submitted with the request. POSTing null or invalid
JSON results in the request argument being null.
appex json handlers require the following signature:
- argument[0] - the appex context
- argument[1] - A optionally typed json request object.
- argument[2] - a optionally typed typescript callback with a single argument for the object response.
- returns - void (optional)
export function method(context, request, callback:(response) => void) : void {
callback(request);
}
### wildcard handlers
appex wildcard handlers allow for wildcard routing at a given module scope. In addition, wildcard handlers
support 'typed' url argument mapping, as denoted by the parameter annotation.
appex wildcard handlers require the following signature:
- name - 'wildcard'
- argument[0] - context
- argument[n] - 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 only supports type any (or none), string and number annotations. specifying any other type result
in this wildcard not being routed.
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) { }
}