├── http.ts
├── controllers.ts
├── test
├── globals.d.ts
├── public
│ └── index.html
├── server.ts
├── Server.js.map
├── tsconfig.json
├── startup.js.map
├── startup.ts
├── controllers
│ └── UsersController.ts
└── Controllers
│ └── UsersController.js.map
├── src
├── middleware
│ ├── Filter.ts
│ ├── HttpResponseMessage.ts
│ ├── HttpMessageHandler.ts
│ ├── HttpRequestMessage.ts
│ └── RequestHandler.ts
├── security
│ ├── Identity.ts
│ └── Principal.ts
├── server
│ ├── Startup.ts
│ ├── StartOptions.ts
│ ├── AppBuilder.ts
│ ├── HttpConfiguration.ts
│ └── WebApp.ts
├── routing
│ ├── HttpRoute.ts
│ └── annotations
│ │ ├── Index.ts
│ │ ├── HttpPost.ts
│ │ ├── HttpPut.ts
│ │ ├── HttpDelete.ts
│ │ ├── Route.ts
│ │ ├── HttpGet.ts
│ │ └── RoutePrefix.ts
├── http
│ └── HttpStatusCode.ts
├── controllers
│ └── ApiController.ts
└── collections
│ ├── Collection.ts
│ ├── Dictionary2.ts
│ └── Dictionary.ts
├── security.ts
├── .vscode
├── settings.json
├── tasks.json
└── launch.json
├── collections.ts
├── .npmignore
├── server.ts
├── middleware.ts
├── typings.json
├── CHANGELOG.md
├── routing.ts
├── tsconfig.json
├── .gitignore
├── gulpfile.js
├── LICENSE
├── package.json
└── README.md
/http.ts:
--------------------------------------------------------------------------------
1 | export * from './src/http/HttpStatusCode';
2 |
--------------------------------------------------------------------------------
/controllers.ts:
--------------------------------------------------------------------------------
1 | export * from './src/controllers/ApiController';
2 |
--------------------------------------------------------------------------------
/test/globals.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/middleware/Filter.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | export interface IFilter {
4 |
5 | }
--------------------------------------------------------------------------------
/test/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World
4 |
5 |
--------------------------------------------------------------------------------
/security.ts:
--------------------------------------------------------------------------------
1 | export * from './src/security/Identity';
2 | export * from './src/security/Principal';
3 |
4 |
--------------------------------------------------------------------------------
/src/middleware/HttpResponseMessage.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | export class HttpResponseMessage {
4 |
5 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "files.autoSave": "afterDelay",
4 | }
--------------------------------------------------------------------------------
/collections.ts:
--------------------------------------------------------------------------------
1 | export * from './src/collections/Collection';
2 | export * from './src/collections/Dictionary';
3 | export * from './src/collections/Dictionary2';
4 |
--------------------------------------------------------------------------------
/src/security/Identity.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | export interface IIdentity {
4 | authenticationType: string,
5 | isAuthenticated: boolean,
6 | name: string
7 | }
--------------------------------------------------------------------------------
/src/server/Startup.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import {IAppBuilder} from "./AppBuilder";
4 |
5 | export interface IStartup {
6 | Configuration(IAppBuilder);
7 | }
8 |
--------------------------------------------------------------------------------
/src/security/Principal.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import {IIdentity} from "./Identity";
4 |
5 | export interface IPrincipal {
6 | identity: IIdentity;
7 | isInRole(role: string);
8 | }
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .vscode
2 |
3 | test/
4 | typings/
5 | hapi-webapi-*
6 |
7 | *.ts
8 | !*.d.ts
9 |
10 | .npmignore
11 |
12 | *.log
13 | *.tgz
14 |
15 | tsconfig.json
16 | typings.json
17 | npm-debug.log*
18 |
--------------------------------------------------------------------------------
/src/routing/HttpRoute.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import {IApiController} from "../controllers/ApiController";
4 |
5 | export interface IHttpRoute {
6 | handler: IApiController;
7 | routeTemplate: string;
8 | }
--------------------------------------------------------------------------------
/src/routing/annotations/Index.ts:
--------------------------------------------------------------------------------
1 | export * from "./HttpDelete";
2 | export * from "./HttpPut";
3 | export * from "./HttpGet";
4 | export * from "./HttpPost";
5 | export * from "./Route";
6 | export * from "./RoutePrefix";
7 |
--------------------------------------------------------------------------------
/src/server/StartOptions.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import {IDictionary2} from "../collections/Dictionary2";
4 | export class StartOptions {
5 | public port: number;
6 | public settings: IDictionary2;
7 | public cors: boolean;
8 | }
--------------------------------------------------------------------------------
/server.ts:
--------------------------------------------------------------------------------
1 | export * from './src/server/AppBuilder';
2 | export * from './src/server/HttpConfiguration';
3 | export * from './src/server/StartOptions';
4 | export * from './src/server/Startup';
5 | export * from './src/server/WebApp';
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/test/server.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import {WebApp, StartOptions} from '../server';
4 | import {Startup} from "./Startup";
5 |
6 | var options = new StartOptions();
7 | options.port = 4600;
8 |
9 | WebApp.Start(Startup, options);
--------------------------------------------------------------------------------
/middleware.ts:
--------------------------------------------------------------------------------
1 | export * from './src/middleware/Filter';
2 | export * from './src/middleware/HttpMessageHandler';
3 | export * from './src/middleware/HttpRequestMessage';
4 | export * from './src/middleware/HttpResponseMessage';
5 | export * from './src/middleware/RequestHandler';
6 |
7 |
8 |
--------------------------------------------------------------------------------
/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "globalDependencies": {
3 | "hapi": "registry:dt/hapi#13.0.0+20160417144856",
4 | "node": "registry:dt/node#4.0.0+20160412142033"
5 | },
6 | "dependencies": {
7 | "es6-promise": "registry:npm/es6-promise#3.0.0+20160211003958"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/middleware/HttpMessageHandler.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import {HttpRequestMessage} from "./HttpRequestMessage";
4 | import {HttpResponseMessage} from "./HttpResponseMessage";
5 |
6 | export abstract class HttpMessageHandler {
7 | public abstract sendAsync(request: HttpRequestMessage): HttpResponseMessage;
8 | }
--------------------------------------------------------------------------------
/test/Server.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"Server.js","sourceRoot":"","sources":["Server.ts"],"names":[],"mappings":"AAGA,YAAY,CAAC;AAEb,IAAO,MAAM,WAAW,cAAc,CAAC,CAAC;AACxC,wBAAsB,WAAW,CAAC,CAAA;AAElC,IAAI,OAAO,GAAG,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;AACxC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;AAEpB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAU,iBAAO,EAAE,OAAO,CAAC,CAAC"}
--------------------------------------------------------------------------------
/src/routing/annotations/HttpPost.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import "reflect-metadata";
4 |
5 | export function HttpPost() {
6 | return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor) => {
7 | //descriptor.enumerable = route;
8 | Reflect.defineMetadata("Method", 'POST', descriptor.value);
9 | return descriptor;
10 | };
11 | }
--------------------------------------------------------------------------------
/src/routing/annotations/HttpPut.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import "reflect-metadata";
4 |
5 | export function HttpPut() {
6 | return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor) => {
7 | //descriptor.enumerable = route;
8 | Reflect.defineMetadata("Method", 'PUT', descriptor.value);
9 | return descriptor;
10 | };
11 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 0.0.5 (2016-05-19)
2 |
3 | ### Bug Fixes
4 |
5 | * Updates dependencies, updates typings, disables good-console due to runtime error.
6 |
7 |
8 | # 0.0.1 (2016-03-06)
9 |
10 | ### Bug Fixes
11 |
12 | ### Features
13 |
14 | * **AppBuilder:** Adds static files support. ([4c35462](https://github.com/sondreb/hapi-webapi/commit/4c35462))
15 |
16 | ### BREAKING CHANGES
17 |
18 |
--------------------------------------------------------------------------------
/src/routing/annotations/HttpDelete.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import "reflect-metadata";
4 |
5 | export function HttpDelete() {
6 | return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor) => {
7 | //descriptor.enumerable = route;
8 | Reflect.defineMetadata("Method", 'DELETE', descriptor.value);
9 | return descriptor;
10 | };
11 | }
--------------------------------------------------------------------------------
/routing.ts:
--------------------------------------------------------------------------------
1 | export * from './src/routing/HttpRoute';
2 | export * from './src/routing/annotations/HttpDelete';
3 | export * from './src/routing/annotations/HttpGet';
4 | export * from './src/routing/annotations/HttpPost';
5 | export * from './src/routing/annotations/HttpPut';
6 | export * from './src/routing/annotations/Route';
7 | export * from './src/routing/annotations/RoutePrefix';
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/routing/annotations/Route.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import "reflect-metadata";
4 |
5 | export function Route(template: string) {
6 | return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor) => {
7 | //descriptor.enumerable = route;
8 | console.log('ROUTE DECORATOR!');
9 | Reflect.defineMetadata("Route", template, descriptor.value);
10 | return descriptor;
11 | };
12 | }
--------------------------------------------------------------------------------
/src/routing/annotations/HttpGet.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import "reflect-metadata";
4 |
5 | export function HttpGet() {
6 | return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor) => {
7 | //descriptor.enumerable = route;
8 | console.log('HTTP GET DECORATOR!');
9 | console.log(descriptor);
10 |
11 | //target.actions.add();
12 |
13 | Reflect.defineMetadata("Method", 'GET', descriptor.value);
14 | return descriptor;
15 | };
16 | }
--------------------------------------------------------------------------------
/src/http/HttpStatusCode.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | export enum HttpStatusCode {
4 | Continue = 100,
5 | OK = 200,
6 | Created = 201,
7 | Accepted = 202,
8 | NoContent = 204,
9 | MovedPermanently = 301,
10 | Moved = 301,
11 | Found = 302,
12 | Redirect = 302,
13 | BadRequest = 400,
14 | Unauthorized = 401,
15 | Forbidden = 403,
16 | NotFound = 404,
17 | MethodNotAllowed = 405,
18 | NotAcceptable = 406,
19 | InternalServerError = 500,
20 | NotImplemented = 501,
21 | ServiceUnavailable = 503
22 | };
--------------------------------------------------------------------------------
/src/routing/annotations/RoutePrefix.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import "reflect-metadata";
4 |
5 | export function RoutePrefix(prefix: string) {
6 | return function(target: Function) {
7 | Reflect.defineMetadata("RoutePrefix", prefix, target);
8 | //Reflect.defineMetadata("RoutePrefix", prefix, RoutePrefix, "method");
9 | //Reflect.defineMetadata("routeprefix", prefix, target, null);
10 |
11 | //console.log('Register RoutePrefix for service: "/' + prefix + '"');
12 | //console.log("Target: ", target);
13 | }
14 | }
--------------------------------------------------------------------------------
/test/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "target": "es6",
5 | "module": "commonjs",
6 | "watch": false,
7 | "experimentalDecorators": true,
8 | "emitDecoratorMetadata": true,
9 | "noImplicitAny": false,
10 | "removeComments": true,
11 | "preserveConstEnums": true,
12 | "inlineSourceMap": false,
13 | "sourceMap": false,
14 | "moduleResolution": "node"
15 | },
16 | "exclude": [
17 | "node_modules",
18 | "typings"
19 | ]
20 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "target": "es6",
5 | "module": "commonjs",
6 | "watch": false,
7 | "experimentalDecorators": true,
8 | "emitDecoratorMetadata": true,
9 | "noImplicitAny": false,
10 | "removeComments": true,
11 | "preserveConstEnums": true,
12 | "inlineSourceMap": false,
13 | "sourceMap": false,
14 | "moduleResolution": "node"
15 | },
16 | "exclude": [
17 | "node_modules",
18 | "typings",
19 | "test"
20 | ]
21 | }
--------------------------------------------------------------------------------
/src/middleware/HttpRequestMessage.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | export class HttpRequestMessage {
4 |
5 | constructor(hapiRequest: any) {
6 | this.hapiRequest = hapiRequest;
7 | }
8 |
9 | get requestUri(): any {
10 | return this.hapiRequest.url;
11 | }
12 |
13 | get method(): any {
14 | return this.hapiRequest.method.toUpperCase();
15 | }
16 |
17 | get headers(): any {
18 | return this.hapiRequest.headers;
19 | }
20 |
21 | get content(): any {
22 | return this.hapiRequest.raw.req;
23 | }
24 |
25 | get version(): string {
26 | return this.hapiRequest.raw.req.httpVersion;
27 | }
28 |
29 | //content: string;
30 | properties: Array;
31 | hapiRequest: any;
32 | }
33 |
--------------------------------------------------------------------------------
/test/startup.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"Startup.js","sourceRoot":"","sources":["Startup.ts"],"names":["Startup","Startup.Configuration"],"mappings":"AACA,YAAY,CAAC;AAEb,IAAO,MAAM,WAAW,cAAc,CAAC,CAAC;AACxC,gCAA8B,+BAA+B,CAAC,CAAA;AAE9D,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEvC;IACIA,aAAaA,CAACA,GAAuBA;QAEjCC,IAAIA,MAAMA,GAAGA,IAAIA,MAAMA,CAACA,iBAAiBA,EAAEA,CAACA;QAC5CA,GAAGA,CAACA,SAASA,CAACA,MAAMA,CAACA,CAACA;QAEtBA,MAAMA,CAACA,aAAaA,CAACA,EAAEA,KAAKA,EAAEA,eAAeA,EAAEA,WAAWA,EAAEA,GAAGA,CAACA,WAAWA,EAAEA,OAAOA,EAAEA,GAAGA,CAACA,OAAOA,EAAEA,CAACA,CAACA;QACrGA,MAAMA,CAACA,eAAeA,CAACA,EAAEA,KAAKA,EAAEA,qBAAqBA,GAAGA,GAAGA,CAACA,OAAOA,EAAEA,IAAIA,EAAEA,OAAOA,EAAEA,CAACA,CAACA;QAGtFA,GAAGA,CAACA,WAAWA,CAACA,GAAGA,CAACA,iCAAeA,CAACA,CAACA;QAErCA,GAAGA,CAACA,cAAcA,EAAEA,CAACA;IAGzBA,CAACA;AACLD,CAACA;AAhBY,eAAO,UAgBnB,CAAA"}
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.1.0",
3 | "command": "tsc",
4 | "isShellCommand": true,
5 | "args": [
6 | "-module",
7 | "commonjs",
8 | "--experimentalDecorators"
9 | ],
10 | "showOutput": "silent",
11 | "isWatching": false,
12 | "problemMatcher": "$tsc-watch"
13 | }
14 | /*
15 | {
16 | "version": "0.1.0",
17 | "command": "gulp",
18 | "isShellCommand": true,
19 | "args": [
20 | "--no-color"
21 | ],
22 | "tasks": [
23 | {
24 | "taskName": "build",
25 | "args": [],
26 | "isBuildCommand": true,
27 | "isWatching": false,
28 | "problemMatcher": [
29 | "$lessCompile",
30 | "$tsc",
31 | "$jshint"
32 | ]
33 | }
34 | ]
35 | }*/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | hapi-webapi-*
3 |
4 | *.d.ts
5 | *.js.map
6 | *.js
7 | !gulpfile.js
8 |
9 | typings/
10 | *.log
11 | *.tgz
12 |
13 | # Logs
14 | logs
15 | *.log
16 | npm-debug.log*
17 |
18 | # Runtime data
19 | pids
20 | *.pid
21 | *.seed
22 |
23 | # Directory for instrumented libs generated by jscoverage/JSCover
24 | lib-cov
25 |
26 | # Coverage directory used by tools like istanbul
27 | coverage
28 |
29 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
30 | .grunt
31 |
32 | # node-waf configuration
33 | .lock-wscript
34 |
35 | # Compiled binary addons (http://nodejs.org/api/addons.html)
36 | build/Release
37 |
38 | # Dependency directories
39 | node_modules
40 | jspm_packages
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional REPL history
46 | .node_repl_history
47 |
48 |
--------------------------------------------------------------------------------
/src/controllers/ApiController.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import {IPrincipal} from "../security/Principal";
4 | import {HttpRequestMessage} from "../middleware/HttpRequestMessage";
5 | import {HttpStatusCode} from "../http/HttpStatusCode";
6 |
7 | export interface IApiController {
8 | user: IPrincipal;
9 | actionContext: any;
10 | controllerContext: any;
11 | requestContext: any;
12 | request: HttpRequestMessage;
13 | }
14 |
15 | export class ApiController implements IApiController {
16 | constructor() {
17 | this.user = null;
18 | }
19 |
20 | user: IPrincipal
21 | actionContext: any;
22 | controllerContext: any;
23 | requestContext: any;
24 | request: HttpRequestMessage;
25 |
26 | protected ok() { };
27 |
28 | protected notFound() {
29 | return new Error();
30 | };
31 |
32 | protected statusCode(code: HttpStatusCode) { };
33 | protected internalServerError() { };
34 | }
--------------------------------------------------------------------------------
/test/startup.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import {IStartup, IAppBuilder, HttpConfiguration} from '../server';
4 | import {UsersController} from "./Controllers/UsersController";
5 |
6 | const pgk = require("../package.json");
7 |
8 | export class Startup implements IStartup {
9 | Configuration(app: IAppBuilder) {
10 |
11 | var config = new HttpConfiguration();
12 | app.useWebApi(config);
13 |
14 | config.enableSwagger({ title: 'Directory API', description: pgk.description, version: pgk.version });
15 | config.enableSwaggerUi({ title: 'API Documentation v' + pgk.version, path: '/docs' });
16 |
17 | // This is different from ASP.NET WebAPI, controllers needs to manually be registered.
18 | app.controllers.add(UsersController);
19 | //app.controllers.add(GroupsController);
20 |
21 | app.useWelcomePage();
22 | //app.useDirectoryBrowser('./public/', '/files/');
23 | //app.useStaticFiles('static');
24 | }
25 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Launch",
6 | "type": "node",
7 | "request": "launch",
8 | "program": "${workspaceRoot}/test/Server.js",
9 | "stopOnEntry": false,
10 | "args": [],
11 | "cwd": "${workspaceRoot}",
12 | "runtimeExecutable": null,
13 | "runtimeArgs": [
14 | "--nolazy"
15 | ],
16 | "env": {
17 | "NODE_ENV": "development"
18 | },
19 | "externalConsole": false,
20 | "sourceMaps": true,
21 | "outDir": null
22 | },
23 | {
24 | "name": "Attach",
25 | "type": "node",
26 | "request": "attach",
27 | "port": 5858,
28 | "sourceMaps": false,
29 | "outDir": null,
30 | "localRoot": "${workspaceRoot}",
31 | "remoteRoot": null
32 | }
33 | ]
34 | }
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var exec = require('child_process').exec;
3 | var dtsGenerator = require('dts-generator');
4 | var gulpSequence = require('gulp-sequence');
5 |
6 | var appName = (function (p) {
7 | return p.name;
8 | })(require('./package.json'));
9 |
10 | gulp.task('build', gulpSequence('compile', 'definition'));
11 |
12 | gulp.task('compile', function (cb) {
13 | exec('tsc --version', function (err, stdout, stderr) {
14 | console.log('TypeScript ', stdout);
15 | if (stderr) {
16 | console.log(stderr);
17 | }
18 | });
19 |
20 | return exec('tsc', function (err, stdout, stderr) {
21 | console.log(stdout);
22 | if (stderr) {
23 | console.log(stderr);
24 | }
25 | cb(err);
26 | });
27 | });
28 |
29 | gulp.task('definition', function(cb) {
30 | return dtsGenerator.default({
31 | name: appName,
32 | project: '.',
33 | out: './lib/index.d.ts',
34 | exclude: ['node_modules/**/*.d.ts', 'typings/**/*.d.ts']
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/controllers/UsersController.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import {ApiController} from '../../controllers';
4 | import {RoutePrefix, Route, HttpGet, HttpDelete, HttpPut, HttpPost} from '../../routing';
5 |
6 | @RoutePrefix("users")
7 | export class UsersController extends ApiController {
8 | @Route("{id}")
9 | @HttpGet() // Also supports @HttpPut, @HttpPost, @HttpDelete
10 | getUserById(id: string) {
11 |
12 | return "getUserById:" + id;
13 | }
14 |
15 | @Route("search")
16 | @HttpPost()
17 | searchUsers(id: string) {
18 | return this.notFound();
19 | }
20 |
21 | @Route("list")
22 | @HttpGet()
23 | list() {
24 | // Examples of request object values available:
25 | // Url object.
26 | console.log(this.request.requestUri);
27 |
28 | // HTTP version.
29 | console.log('HTTP Version: ' + this.request.version);
30 |
31 | // HTTP headers.
32 | console.log(this.request.headers);
33 |
34 | return "Hello World!";
35 | }
36 | }
--------------------------------------------------------------------------------
/test/Controllers/UsersController.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"UsersController.js","sourceRoot":"","sources":["UsersController.ts"],"names":["UsersController","UsersController.getUserById","UsersController.searchUsers","UsersController.list"],"mappings":"AACA,YAAY,CAAC;;;;;;;;;;AAEb,IAAO,MAAM,WAAW,iBAAiB,CAAC,CAAC;AAE3C,oCACqC,MAAM,CAAC,aAAa;IAGrDA,WAAWA,CAACA,EAAUA;QAElBC,MAAMA,CAACA,cAAcA,GAAGA,EAAEA,CAACA;IAC/BA,CAACA;IAIDD,WAAWA,CAACA,EAAUA;QAClBE,MAAMA,CAACA,IAAIA,CAACA,QAAQA,EAAEA,CAACA;IAC3BA,CAACA;IAIDF,IAAIA;QAGAG,OAAOA,CAACA,GAAGA,CAACA,IAAIA,CAACA,OAAOA,CAACA,UAAUA,CAACA,CAACA;QAGrCA,OAAOA,CAACA,GAAGA,CAACA,gBAAgBA,GAAGA,IAAIA,CAACA,OAAOA,CAACA,OAAOA,CAACA,CAACA;QAGrDA,OAAOA,CAACA,GAAGA,CAACA,IAAIA,CAACA,OAAOA,CAACA,OAAOA,CAACA,CAACA;QAElCA,MAAMA,CAACA,cAAcA,CAACA;IAC1BA,CAACA;AACLH,CAACA;AA5BG;IAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;IACpB,MAAM,CAAC,OAAO,EAAE;;;;GACjB,wCAAW,QAGV;AAED;IAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;IACtB,MAAM,CAAC,QAAQ,EAAE;;;;GAClB,wCAAW,QAEV;AAED;IAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;IACpB,MAAM,CAAC,OAAO,EAAE;;;;GACjB,iCAAI,QAYH;AA7BL;IAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC;;oBA8B3B;AA7BY,uBAAe,kBA6B3B,CAAA"}
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Sondre Bjellås
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/collections/Collection.ts:
--------------------------------------------------------------------------------
1 | //A typescript implementation of a generic Collection
2 | "use strict";
3 |
4 | export class Collection {
5 |
6 | // The underlying array data structure of the collection
7 | private _items = [];
8 |
9 | // Get the collection as an array
10 | public getItems() {
11 | return this._items;
12 | }
13 |
14 | // Get a specific item from a collection given it's index
15 | public getItem(index: number): T {
16 | return this._items[index];
17 | }
18 |
19 | // Length of the collection
20 | public count() { return this._items.length; }
21 |
22 | // Add an object to the collection
23 | public add(item: T) {
24 | this._items.push(item);
25 | }
26 |
27 | // Delete an object from the collection
28 | public delete(itemIndex: number) {
29 | this._items.splice(itemIndex, 1);
30 | }
31 |
32 | // Find the index of a given object in a collection
33 | public indexOfItem(obj: T, fromIndex?: number): number {
34 | if (fromIndex == null) {
35 | fromIndex = 0;
36 | } else if (fromIndex < 0) {
37 | fromIndex = Math.max(0, this._items.length + fromIndex);
38 | }
39 | for (var i = fromIndex, j = this._items.length; i < j; i++) {
40 | if (this._items[i] === obj)
41 | return i;
42 | }
43 | return -1;
44 | }
45 | }
--------------------------------------------------------------------------------
/src/collections/Dictionary2.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | export interface IDictionary2 {
4 | add(key: string, value: any): void;
5 | remove(key: string): void;
6 | containsKey(key: string): boolean;
7 | keys(): string[];
8 | values(): any[];
9 | }
10 |
11 | export class Dictionary2 implements IDictionary2 {
12 |
13 | private _keys: string[] = new Array();
14 | private _values: any[] = new Array();
15 |
16 | constructor(init: { key: string; value: any; }[]) {
17 |
18 | for (var x = 0; x < init.length; x++) {
19 | this[init[x].key] = init[x].value;
20 | this._keys.push(init[x].key);
21 | this._values.push(init[x].value);
22 | }
23 | }
24 |
25 | add(key: string, value: any) {
26 | this[key] = value;
27 | this._keys.push(key);
28 | this._values.push(value);
29 | }
30 |
31 | remove(key: string) {
32 | var index = this._keys.indexOf(key, 0);
33 | this._keys.splice(index, 1);
34 | this._values.splice(index, 1);
35 |
36 | delete this[key];
37 | }
38 |
39 | keys(): string[] {
40 | return this._keys;
41 | }
42 |
43 | values(): any[] {
44 | return this._values;
45 | }
46 |
47 | containsKey(key: string) {
48 | if (typeof this[key] === "undefined") {
49 | return false;
50 | }
51 |
52 | return true;
53 | }
54 |
55 | toLookup(): IDictionary2 {
56 | return this;
57 | }
58 | }
--------------------------------------------------------------------------------
/src/collections/Dictionary.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | export interface IDictionary {
4 | add(key: TKey, value: TValue): void;
5 | remove(key: TKey): void;
6 | containsKey(key: TKey): boolean;
7 | keys(): TKey[];
8 | values(): TValue[];
9 | }
10 |
11 | export class Dictionary {
12 |
13 | private _keys: TKey[] = new Array();
14 | private _values: TValue[] = new Array();
15 |
16 | /*
17 | constructor(init: { key: string; value: any; }[]) {
18 |
19 | for (var x = 0; x < init.length; x++) {
20 | this[init[x].key] = init[x].value;
21 | this._keys.push(init[x].key);
22 | this._values.push(init[x].value);
23 | }
24 | }*/
25 |
26 | add(key: TKey, value: TValue) {
27 | this[String(key)] = value;
28 | this._keys.push(key);
29 | this._values.push(value);
30 | }
31 |
32 | remove(key: TKey) {
33 | var index = this._keys.indexOf(key, 0);
34 | this._keys.splice(index, 1);
35 | this._values.splice(index, 1);
36 |
37 | delete this[String(key)];
38 | }
39 |
40 | keys(): TKey[] {
41 | return this._keys;
42 | }
43 |
44 | values(): TValue[] {
45 | return this._values;
46 | }
47 |
48 | containsKey(key: TKey) {
49 | if (typeof this[String(key)] === "undefined") {
50 | return false;
51 | }
52 |
53 | return true;
54 | }
55 |
56 | /*
57 | containsKey(key: TKey) {
58 | return this._keys.indexOf(key, 0) > -1;
59 | }*/
60 |
61 | /*
62 | toLookup(): IDictionary {
63 | return this;
64 | }*/
65 | }
--------------------------------------------------------------------------------
/src/middleware/RequestHandler.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import {HttpRequestMessage} from "./HttpRequestMessage"
4 | import {Promise} from "es6-promise";
5 |
6 | export class RequestHandler {
7 | type: any;
8 | method: string;
9 |
10 | constructor(type: any, method: string) {
11 |
12 | console.log('CONSTRUCTOR OF REQUEST HANDLER');
13 | console.log(type);
14 | console.log(method);
15 |
16 | this.type = type;
17 | this.method = method;
18 | }
19 |
20 | process(request, reply) {
21 | console.log('Processing Request...');
22 | var controller = new this.type();
23 |
24 | //console.log('Controller Instance:');
25 | //console.log(controller);
26 |
27 | // Encapsulate the request in WebAPI-similar request message.
28 | controller.request = new HttpRequestMessage(request);
29 |
30 | var parameters = [];
31 |
32 | // TODO: Register the parameter NAMES for controller methods so we can send correct params.
33 | for (var k in request.params) {
34 | console.log('Parameter: ' + k + ':' + request.params[k]);
35 | parameters.push(request.params[k]);
36 | /*if (request.params.hasOwnProperty(k)) {
37 | user[k] = request.params[k];
38 | }*/
39 | }
40 |
41 | if(request.payload){
42 | parameters.push(request.payload);
43 | }
44 |
45 | var response = controller[this.method](parameters);
46 | if(response instanceof Promise ){
47 | response.then(reply).catch(function(error){
48 | reply({error:error});
49 | });
50 | }
51 | reply(response);
52 | };
53 | }
54 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hapi-webapi",
3 | "version": "0.0.5",
4 | "description": "Implements abstraction for Hapi in TypeScript that makes it similar to ASP.NET WebAPI to implement APIs on Hapi.",
5 | "main": "index.js",
6 | "scripts": {
7 | "preinstall": "",
8 | "postinstall": "",
9 | "prepublish": "",
10 | "test": "tsc --project test; node test/test.js",
11 | "setup": "npm install && typings install",
12 | "build": "tsc",
13 | "package": "npm pack"
14 | },
15 | "author": {
16 | "name": "Sondre Bjellås",
17 | "email": "post-at-sondreb.com"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git://github.com/sondreb/hapi-webapi.git"
22 | },
23 | "bugs": {
24 | "url": "https://github.com/sondreb/hapi-webapi/issues"
25 | },
26 | "keywords": [
27 | "hapi",
28 | "webapi",
29 | "microservice",
30 | "api"
31 | ],
32 | "license": "MIT",
33 | "homepage": "https://github.com/sondreb/hapi-webapi#readme",
34 | "dependencies": {
35 | "blipp": "2.x.x",
36 | "glob": "7.x.x",
37 | "glue": "3.x.x",
38 | "good": "7.x.x",
39 | "good-console": "6.x.x",
40 | "hapi": "13.x.x",
41 | "hapi-api-version": "1.x.x",
42 | "hapi-auth-jwt2": "6.x.x",
43 | "hapi-swaggered": "2.x.x",
44 | "hapi-swaggered-ui": "2.x.x",
45 | "inert": "4.x.x",
46 | "joi": "8.x.x",
47 | "merge": "1.x.x",
48 | "plugo": "0.3.x",
49 | "reflect-metadata": "0.1.x",
50 | "vision": "4.x.x",
51 | "es6-promise": "3.x.x"
52 | },
53 | "devDependencies": {
54 | "dts-generator": "1.x.x",
55 | "code": "2.x.x",
56 | "eslint": "2.x.x",
57 | "gulp": "3.x.x",
58 | "lab": "10.x.x",
59 | "typescript": "1.x.x",
60 | "gulp-sequence": "0.4.x"
61 | },
62 | "eslintConfig": {
63 | "env": {
64 | "node": true,
65 | "es6": true
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/src/server/AppBuilder.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import {Collection} from "../collections/Collection";
4 | import {HttpConfiguration} from "./HttpConfiguration";
5 |
6 | export interface IAppBuilder {
7 | /* Consider moving these methods into separate "extensions" to this interface? */
8 | //userCors(corsOptions: any);
9 |
10 | configuration: HttpConfiguration;
11 |
12 | useDirectoryBrowser(localPath: string, requestPath: string);
13 | useJwtBearerAuthentication(jwtBearerAuthenticationOptions: any);
14 | useOAuthBearerAuthentication(oAuthBearerAuthenticationOptions: any);
15 | useStaticFiles(requestPath: string);
16 | useWelcomePage();
17 | useWebApi(config: HttpConfiguration);
18 | controllers: Collection;
19 | }
20 |
21 | export class AppBuilder implements IAppBuilder {
22 |
23 | private config: HttpConfiguration
24 |
25 | public get configuration(): HttpConfiguration {
26 | return this.config;
27 | }
28 |
29 | /** Not implemented. */
30 | /*public useCors(corsOptions: any) {
31 |
32 | }*/
33 |
34 | /** Not implemented. */
35 | public useDirectoryBrowser(localPath: string, requestPath: string) {
36 | if (this.config == undefined)
37 | {
38 | throw Error('Method must be called after useWebApi.');
39 | }
40 |
41 | this.config.properties.add('directory:browser', true);
42 | this.config.properties.add('directory:path', localPath);
43 | this.config.properties.add('directory:route', requestPath);
44 | }
45 |
46 | /** Not implemented. */
47 | public useJwtBearerAuthentication(jwtBearerAuthenticationOptions: any) {
48 |
49 | }
50 |
51 | /** Not implemented. */
52 | public useOAuthBearerAuthentication(oAuthBearerAuthenticationOptions: any) {
53 |
54 | }
55 |
56 | /** Not implemented */
57 | public useStaticFiles(requestPath: string) {
58 | if (this.config == undefined)
59 | {
60 | throw Error('Method must be called after useWebApi.');
61 | }
62 | }
63 |
64 | public useWelcomePage() {
65 |
66 | }
67 |
68 | public controllers: Collection = new Collection();
69 |
70 | public useWebApi(config: HttpConfiguration) {
71 | this.config = config;
72 | console.log('CONFIG!!!');
73 | console.log(this.config);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/server/HttpConfiguration.ts:
--------------------------------------------------------------------------------
1 | "use strict"
2 |
3 | const merge = require("merge");
4 |
5 | import {IDictionary, Dictionary} from "../collections/Dictionary";
6 | import {Collection} from "../collections/Collection";
7 |
8 | import {IFilter} from "../middleware/Filter";
9 | import {IHttpRoute} from "../routing/HttpRoute";
10 | import {WebApp} from "./WebApp";
11 |
12 | /** Represents a configuration of the API */
13 | export class HttpConfiguration {
14 |
15 | private swaggerOptions: any;
16 | private swaggerUiOptions: any;
17 |
18 | public app: WebApp;
19 |
20 | /** Properties populated during configuration that is used during api startup. */
21 | public properties: IDictionary = new Dictionary();
22 |
23 | /** Collection of filters applied to all incoming requests. */
24 | public filters: Collection;
25 |
26 | /** Ordered list of message handlers which will be invoked upon requests. */
27 | //public messageHandlers: Array;
28 | public messageHandlers: Collection;
29 |
30 | public services: Collection;
31 |
32 | /** Collection of routes discovered at runtime. */
33 | public routes: Collection;
34 |
35 | constructor() {
36 | this.swaggerOptions = {
37 | title: 'API',
38 | description: '',
39 | version: '0.0.1'
40 | };
41 |
42 | this.swaggerUiOptions = {
43 | path: '/swagger'
44 | };
45 | }
46 |
47 | /** Enables swagger API definition to be downloaded */
48 | public enableSwagger(options: any) {
49 | this.properties.add("swagger:enabled", true);
50 | this.swaggerOptions = merge(this.swaggerOptions, options);
51 | this.properties.add("swagger:options", this.swaggerOptions);
52 |
53 | //this.swaggerEnabled = true;
54 | //console.log('Default Swagger Options: ', this.swaggerOptions);
55 | //console.log('Configured Swagger Options: ', this.swaggerOptions);
56 | };
57 |
58 | /** Enables swagger UI to be accessible and used for API testing and documentation. */
59 | public enableSwaggerUi(options: any) {
60 | this.properties.add("swaggerui:enabled", true);
61 | this.swaggerUiOptions = merge(this.swaggerUiOptions, options);
62 | this.properties.add("swaggerui:options", this.swaggerUiOptions);
63 | };
64 |
65 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hapi-webapi 
2 | Implements an abstraction for [Hapi](https://github.com/hapijs/hapi) using TypeScript, that provides a
3 | similar pattern to the ASP.NET WebApi framework for implementing
4 | Apis on [Hapi](http://hapijs.com/).
5 |
6 | # Quickstart
7 |
8 | To get started quickly, you can clone the ['hapi-webapi-seed'](https://github.com/sondreb/hapi-webapi-seed) repository,
9 | which includes all files needed to get started with TypeScript and the hapi-webapi.
10 |
11 | # Getting started
12 |
13 | Start by creating a package.json:
14 |
15 | ```sh
16 | npm init
17 | ```
18 |
19 | Install hapi-webapi and save it to your package.json dependencies:
20 |
21 | ```sh
22 | npm install hapi-webapi --save
23 | ```
24 |
25 | Create a server.ts file with the following contents:
26 |
27 | ```js
28 | import {WebApp, StartOptions} from 'hapi-webapi/server';
29 | import {Startup} from "./Startup";
30 |
31 | var options = new StartOptions();
32 | options.port = 4600;
33 |
34 | //To enable CORS set options.cors to true. Default value is false
35 | options.cors = true;
36 |
37 | WebApp.Start(Startup, options);
38 | ```
39 |
40 | Create a startup.ts file with the following contents:
41 |
42 | ```js
43 | import {IStartup, IAppBuilder, HttpConfiguration} from 'hapi-webapi/server';
44 | import {UsersController} from "./Controllers/UsersController";
45 |
46 | const pgk = require("./package.json");
47 |
48 | export class Startup implements IStartup {
49 | Configuration(app: IAppBuilder) {
50 |
51 | var config = new HttpConfiguration();
52 | app.useWebApi(config);
53 |
54 | config.enableSwagger({ title: 'Directory API', description: pgk.description, version: pgk.version });
55 | config.enableSwaggerUi({ title: 'API Documentation v' + pgk.version, path: '/docs' });
56 |
57 | // This is different from ASP.NET WebAPI, controllers needs to manually be registered.
58 | app.controllers.add(UsersController);
59 |
60 | app.useWelcomePage();
61 | //app.useDirectoryBrowser('./public/', '/files/');
62 | //app.useStaticFiles('static');
63 | }
64 | }
65 | ```
66 |
67 | Create a controller.ts file with the following contents:
68 |
69 | ```js
70 | import {ApiController} from 'hapi-webapi/controllers';
71 | import {RoutePrefix, Route, HttpGet, HttpDelete, HttpPut, HttpPost} from 'hapi-webapi/routing';
72 |
73 | @RoutePrefix("users")
74 | export class UsersController extends ApiController {
75 | @Route("{id}")
76 | @HttpGet() // Also supports @HttpPut, @HttpPost, @HttpDelete
77 | getUserById(id: string) {
78 |
79 | return "getUserById:" + id;
80 | }
81 |
82 | @Route("search")
83 | @HttpPost()
84 | searchUsers(id: string) {
85 | return this.notFound();
86 | }
87 |
88 | @Route("list")
89 | @HttpGet()
90 | list() {
91 | // Examples of request object values available:
92 | // Url object.
93 | console.log(this.request.requestUri);
94 |
95 | // HTTP version.
96 | console.log('HTTP Version: ' + this.request.version);
97 |
98 | // HTTP headers.
99 | console.log(this.request.headers);
100 |
101 | return "Hello World!";
102 | }
103 | }
104 |
105 | ```
106 |
107 | Launch the application by running:
108 |
109 | ```sh
110 | npm start
111 | ```
112 |
113 | And open [localhost:4600](http://localhost:6500) or [localhost:4600/docs](http://localhost:4600/docs) for Swagger UI in your browser.
114 |
115 | ## Contributors
116 |
117 | [
](https://github.com/sondreb) | [
](https://github.com/kommundsen) | [
](https://github.com/SteffenVetrhus) |
118 | :---: |:---: |:---: |
119 | [sondreb](https://github.com/sondreb) |[kommundsen](https://github.com/kommundsen) |[SteffenVetrhus](https://github.com/SteffenVetrhus) |
120 |
121 | ## Change Log
122 |
123 | View the [change log](CHANGELOG.md) to keep up-to-date on API and project changes.
124 |
125 | ## License
126 |
127 | MIT © [Sondre Bjellås](http://sondreb.com)
128 |
--------------------------------------------------------------------------------
/src/server/WebApp.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import * as Hapi from 'hapi';
4 | import {Collection} from "../collections/Collection";
5 | import {RequestHandler} from "../middleware/RequestHandler";
6 | import {IAppBuilder, AppBuilder} from "./AppBuilder";
7 | import {StartOptions} from "./StartOptions";
8 | import {IStartup} from "./Startup";
9 |
10 | export class WebApp {
11 |
12 | private static activeModules(app: IAppBuilder): Collection {
13 |
14 | var modules = new Collection();
15 |
16 | modules.add({ type: require('good'), options: {
17 | ops: { interval: 1000}
18 | } });
19 |
20 | // Disable for now, returns runtime error.
21 | //modules.add({ type: require('good-console') });
22 | modules.add({ type: require('blipp'), options: {} });
23 |
24 | if (app.configuration.properties["swagger:enabled"] === true)
25 | {
26 | let options = app.configuration.properties["swagger:options"];
27 |
28 | console.log('Swagger is enabled: ' + options);
29 |
30 | modules.add({ type: require('hapi-swaggered'), options: {
31 | tags: options.tags,
32 | info: {
33 | title: options.title,
34 | description: options.description,
35 | version: options.version
36 | }
37 | }});
38 | }
39 |
40 | if (app.configuration.properties["swaggerui:enabled"] === true)
41 | {
42 | console.log('Swagger UI is enabled.');
43 |
44 | // Register inert and vision which swagger UI is dependent upon.
45 | modules.add({type: require('inert')});
46 | modules.add({type: require('vision')});
47 |
48 | let options = app.configuration.properties["swaggerui:options"];
49 |
50 | modules.add({ type: require('hapi-swaggered-ui'), options: {
51 | title: options.title,
52 | path: options.path,
53 | authorization: {
54 | field: 'apiKey',
55 | scope: 'query', // header works as well
56 | valuePrefix: 'bearer ',// prefix incase
57 | //defaultValue: 'token',
58 | placeholder: 'Enter your apiKey here'
59 | },
60 | swaggerOptions: {
61 | validatorUrl: null
62 | }
63 | }});
64 | }
65 |
66 | return modules;
67 | }
68 |
69 | static getMethods(obj) {
70 | var res = [];
71 | for (var m in obj) {
72 | console.log('LOOOOP!!');
73 | console.log(m);
74 |
75 | if (typeof obj[m] == "function") {
76 | res.push(m)
77 | }
78 | }
79 | return res;
80 | }
81 |
82 | static Start(startup: { new (): T; }, options: StartOptions) {
83 | //static Start(options: StartOptions) {
84 |
85 | //var t = new T();
86 | var start = new startup();
87 | console.log('START CONFIGURATION: ' + start);
88 |
89 | var appBuilder = new AppBuilder();
90 | start.Configuration(appBuilder);
91 |
92 | const server = new Hapi.Server();
93 | server.connection(
94 | {
95 | port: options.port,
96 | routes: { cors: options.cors}
97 | }
98 | );
99 |
100 | console.log('Count of controllers: ' + appBuilder.controllers.count());
101 |
102 | appBuilder.controllers.getItems().forEach(function(type) {
103 |
104 | console.log('Controller Type: ' + type);
105 | var controllerInstance = new type();
106 | console.log('Controller Instance: ' + controllerInstance);
107 |
108 | var routePrefix = Reflect.getMetadata("RoutePrefix", controllerInstance.constructor);
109 | console.log('routePrefix: ' + routePrefix);
110 |
111 | var methods = WebApp.getMethods(controllerInstance.constructor);
112 |
113 | var methodNames = Object.getOwnPropertyNames(type.prototype).filter(function(p) {
114 | if (p == 'constructor') {
115 | return false;
116 | }
117 |
118 | return typeof type.prototype[p] === 'function';
119 | })
120 |
121 | console.log('methodNames:');
122 | console.log(methodNames);
123 |
124 | methodNames.forEach(function(name) {
125 |
126 | //console.log(controllerInstance[name]);
127 | //console.log(Object.getOwnPropertyDescriptor(type, name));
128 | //console.log(Object.getOwnPropertyDescriptor(type.prototype, name));
129 | //console.log(Object.getOwnPropertyDescriptor(controllerInstance, name));
130 |
131 | var methodDescriptor = Object.getOwnPropertyDescriptor(type.prototype, name);
132 |
133 | var metaMethod = Reflect.getMetadata('Method', methodDescriptor.value);
134 | var metaRoute = Reflect.getMetadata('Route', methodDescriptor.value);
135 |
136 | console.log('Method: ' + metaMethod);
137 | console.log('Route: ' + metaRoute);
138 |
139 | //var metaMethod = Reflect.getMetadata("Method", methodDescriptor.value);
140 | //var metaRoute = Reflect.getMetadata("Route", methodDescriptor.value);
141 | //console.log('Method:' + metaMethod);
142 | //console.log('Route:' + metaRoute);
143 |
144 | // TODO: Do a safe route building here, supporting prefix with and without trailing /.
145 | var safeRoute = '/' + routePrefix + '/' + metaRoute;
146 |
147 | console.log('Safe Route: ' + safeRoute);
148 |
149 | var handler = new RequestHandler(type, name);
150 |
151 | server.route({
152 | method: metaMethod,
153 | path: safeRoute,
154 | config: {
155 | tags: ['api'],
156 | description: '[Should be read from decoration on API method]'
157 | },
158 | handler: function(request, reply) {
159 | // IMPORTANT: We can't bind the process method directly to the handler property, that will invalidate .this within the handler.
160 | handler.process(request, reply);
161 | }
162 | });
163 | });
164 | });
165 |
166 | var modules = WebApp.activeModules(appBuilder);
167 |
168 | modules.getItems().forEach(function(module) {
169 |
170 | let moduleRegistration : any = {
171 | register: module.type,
172 | };
173 |
174 | if (module.options)
175 | {
176 | console.log('ADDING OPTIONS');
177 | console.log(module.options);
178 | moduleRegistration.options = module.options;
179 | }
180 |
181 | server.register(moduleRegistration, (err) => {
182 | if (err) {
183 | console.error('Failed to load plugin:', err);
184 | }
185 | });
186 | });
187 |
188 | if (appBuilder.configuration.properties["directory:browser"] === true) {
189 |
190 | let browserPath = appBuilder.configuration.properties["directory:path"];
191 | let browserRoute = appBuilder.configuration.properties["directory:route"];
192 |
193 | server.route({
194 | method: 'GET',
195 | path: browserRoute,
196 | handler: {
197 | directory: {
198 | path: browserPath,
199 | listing: true
200 | }
201 | }
202 | });
203 | }
204 |
205 | server.start((err) => {
206 |
207 | if (err) {
208 | throw err;
209 | }
210 |
211 | console.log('✅ Server is listening on ' + server.info.uri.toLowerCase());
212 | });
213 | }
214 | }
215 |
--------------------------------------------------------------------------------