Socket
Socket
Sign inDemoInstall

@alterior/core

Package Overview
Dependencies
110
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.1 to 0.0.3

4

lib/args.ts

@@ -0,1 +1,5 @@

/**
* Abstracts the fetching of the application's arguments. This is most useful for testing,
* but could also be used if trying to host Alterior in a strange environment.
*/
export class ApplicationArgs {

@@ -2,0 +6,0 @@ public get() {

import 'reflect-metadata';
const getParameterNames = require('@avejidah/get-parameter-names');
import { AppOptions, ApplicationOptions, ApplicationInstance } from './application';
import { controllerClasses } from './controller';
import { Middleware, prepareMiddleware } from './middleware';
import { RouteReflector } from './route';
import { RouteReflector, RouteEvent } from './route';
import { ExpressRef } from './express';

@@ -150,12 +152,71 @@ import { HttpException } from './errors';

let routeParams = route.path.match(/:([A-Za-z][A-Za-z0-9]*)/);
// Do analysis of the controller method ahead of time so we can
// minimize the amount of overhead of actual web requests
let returnType = Reflect.getMetadata("design:returntype", controllerInstance.constructor.prototype, route.method);
let paramTypes = Reflect.getMetadata("design:paramtypes", controllerInstance.constructor.prototype, route.method);
let paramNames = getParameterNames(controllerInstance[route.method]);
let paramFactories = [];
if (paramTypes) {
for (let i = 0, max = paramNames.length; i < max; ++i) {
let paramName = paramNames[i];
let paramType = paramTypes[i];
let simpleTypes = [String, Number];
if (paramType === RouteEvent) {
paramFactories.push(ev => ev);
} else if (paramName === "body") {
paramFactories.push((ev : RouteEvent) => ev.request['body']);
} else if (paramName === "req" || paramName === "request") {
paramFactories.push((ev : RouteEvent) => ev.request);
} else if (paramName === "res" || paramName === "response") {
paramFactories.push((ev : RouteEvent) => ev.response);
} else if (routeParams.find(x => x == paramName) && simpleTypes.indexOf(paramType) >= 0) {
// This is a route parameter binding.
paramFactories.push((ev : RouteEvent) => ev.request.params[paramName]);
} else {
throw new Error(`Unable to provider parameter ${paramName} of type ${paramType.name}`);
}
}
} else {
paramFactories = [
(ev : RouteEvent) => ev.request,
(ev : RouteEvent) => ev.response
];
}
// Append the actual controller method
args.push((req, res) => {
if (!silent)
console.log(`[${new Date().toLocaleString()}] ${route.path} => ${controller.name}.${route.method}()`);
let result = controllerInstance[route.method](req, res);
// Execute our function by resolving the parameter factories into a set of parameters to provide to the
// function.
if (!result)
let ev = new RouteEvent(req, res);
let result;
try {
result = controllerInstance[route.method].apply(controllerInstance, paramFactories.map(x => x(ev)));
} catch (e) {
if (e.constructor === HttpException) {
let httpException = <HttpException>e;
res.status(httpException.statusCode).send(httpException.body);
} else {
res.status(500).send(JSON.stringify({
message: 'Failed to resolve this resource.',
error: e
}));
}
}
// Return value handling
if (result === undefined)
return;

@@ -181,2 +242,6 @@

});
} else if (result.constructor === String) {
res.status(200).send(result);
} else {
res.status(200).header('Content-Type', 'application/json').send(JSON.stringify(result));
}

@@ -183,0 +248,0 @@

import { controllerClasses, Controller as _Controller } from './controller';
import { Get, Post, Put, Patch, Delete, Options } from './route';
import { Get, Post, Put, Patch, Delete, Options, RouteEvent } from './route';
import { suite, test as it } from 'mocha-typescript';

@@ -7,2 +7,4 @@ import * as assert from 'assert';

import * as http from 'http';
import * as bodyParser from 'body-parser';
import { HttpException } from './errors';

@@ -131,2 +133,36 @@

@it 'should allow a method to return an explicit body value' (done) {
@_Controller()
class TestController {
@Get('/foo')
getX(req : express.Request, res : express.Response) {
return {foo:"we promised"};
}
}
@AppOptions({ port: 10001, silent: true,
autoRegisterControllers: false,
controllers: [TestController],
middleware: [
(req, res, next) => { res.header('Content-Type', 'application/json'); next(); }
]
})
class FakeApp {
}
bootstrap(FakeApp).then(app => {
supertest(app.express)
.get('/foo')
.expect(200, <any>{ foo: "we promised" })
.end((err, res) => {
app.stop();
if (err)
return done(err);
done();
});
});
}
@it 'should 500 when a method returns a promise that rejects' (done) {

@@ -200,2 +236,129 @@

@it 'should be reading parameter type metadata to discover how to provide parameters' (done) {
@_Controller()
class TestController {
@Get('/foo')
getX(res : express.Response, req : express.Request) { // note they are swapped
assert(res.send);
assert(req.path);
return Promise.resolve({ok: true});
}
}
@AppOptions({ port: 10001, silent: true,
autoRegisterControllers: false,
controllers: [TestController],
middleware: [
(req, res, next) => { res.header('Content-Type', 'application/json'); next(); }
]
})
class FakeApp {
}
bootstrap(FakeApp).then(app => {
supertest(app.express)
.get('/foo')
.expect(200, <any>{
ok: true
})
.end((err, res) => {
app.stop();
if (err)
return done(err);
done();
});
});
}
@it 'should be able to inject body when the body parsing middleware is used' (done) {
interface MyRequestType {
zoom : number;
}
@_Controller()
class TestController {
@Post('/foo')
getX(body : MyRequestType) {
assert(body.zoom === 123);
return Promise.resolve({ok: true});
}
}
@AppOptions({ port: 10001, silent: true,
autoRegisterControllers: false,
controllers: [TestController],
middleware: [
bodyParser.json(),
(req, res, next) => { res.header('Content-Type', 'application/json'); next(); }
]
})
class FakeApp {
}
bootstrap(FakeApp).then(app => {
supertest(app.express)
.post('/foo')
.send({
zoom: 123
})
.expect(200, <any>{
ok: true
})
.end((err, res) => {
app.stop();
if (err)
return done(err);
done();
});
});
}
@it 'should be able to inject RouteEvent instead of request/response' (done) {
interface MyRequestType {
zoom : number;
}
@_Controller()
class TestController {
@Post('/foo')
getX(ev : RouteEvent) {
assert(ev.request.path);
assert(ev.response.send);
return Promise.resolve({ok: true});
}
}
@AppOptions({ port: 10001, silent: true,
autoRegisterControllers: false,
controllers: [TestController],
middleware: [
bodyParser.json(),
(req, res, next) => { res.header('Content-Type', 'application/json'); next(); }
]
})
class FakeApp {
}
bootstrap(FakeApp).then(app => {
supertest(app.express)
.post('/foo')
.send({
zoom: 123
})
.expect(200, <any>{
ok: true
})
.end((err, res) => {
app.stop();
if (err)
return done(err);
done();
});
});
}
@it 'should support POST' (done) {

@@ -202,0 +365,0 @@

@@ -0,1 +1,2 @@

import * as express from 'express';

@@ -17,2 +18,12 @@ export class RouteReflector {

export class RouteEvent {
constructor(request : express.Request, response : express.Response) {
this.request = request;
this.response = response;
}
request : express.Request;
response : express.Response;
}
export interface RouteOptions {

@@ -19,0 +30,0 @@ middleware?: Function[];

7

package.json
{
"name": "@alterior/core",
"version": "0.0.1",
"version": "0.0.3",
"private": false,

@@ -9,4 +9,4 @@ "description": "An Express-based Typescript MVC framework using decorators and Angular 2 dependency injection.",

"repository": {
"type": "git",
"url": "https://github.com/rezonant/alterior-core.git"
"type": "git",
"url": "https://github.com/alterior-mvc/alterior.git"
},

@@ -23,2 +23,3 @@ "scripts": {

"@angular/core": "^2.0.0",
"@avejidah/get-parameter-names": "^0.3.2",
"body-parser": "^1.15.2",

@@ -25,0 +26,0 @@ "connect-mongo": "^1.3.2",

# Alterior
[![Build status on Travis CI](https://travis-ci.org/rezonant/alterior-core.svg?branch=master)](https://travis-ci.org/rezonant/alterior-core)
[![Build status on Travis CI](https://travis-ci.org/alterior-mvc/alterior.svg?branch=master)](https://travis-ci.org/alterior-mvc/alterior)
[![Join the chat at https://gitter.im/alterior-mvc/Lobby](https://badges.gitter.im/alterior-core/Lobby.svg)](https://gitter.im/alterior-mvc/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
An Express-based Typescript MVC framework using decorators and Angular 2 dependency injection.
An Express-based Typescript MVC framework using decorators and Angular 2 dependency injection.

@@ -36,3 +36,3 @@ ## Getting started

```typescript
import { Controller, Get } from '@alterior/core';
import { Controller, Get, RouteEvent } from '@alterior/core';
import * as express from 'express';

@@ -43,3 +43,3 @@

@Get('/foo')
public foo(req : express.Request, res : express.Response)
public foo(ev : RouteEvent)
{

@@ -50,3 +50,6 @@ res.status(200).send("/foo works!");

/**
* You can also return promises.
* You can also return promises, or
* request the Express request/response explicitly (note that this is
* based on the parameter name, see below for more information about
* route method parameters.
*/

@@ -59,10 +62,15 @@ @Get('/bar')

/**
* Those promises can reject
*/
@Get('/error')
public errorExample(req : express.Request, res : express.Response)
{
// Promises can reject
return Promise.reject(new HttpException(301, {message: "No, over there"}));
}
@Get('/error')
public errorExample(req : express.Request, res : express.Response)
{
// Values are OK too
return { nifty: 123};
}
}

@@ -74,2 +82,3 @@ ```

When using automatic discovery, the simplest way to ensure a controller gets loaded is with:
```typescript

@@ -94,2 +103,48 @@ import "foo";

## Route Parameters
Alterior inspects the parameters of controller methods to determine what values to provide. Firstly, parameters of type `RouteEvent` will be provided with an instance of that class which
contains the Express request and response objects.
```typescript
@Get('/do')
doThings(ev : RouteEvent) {
ev.response.status(404).send("Not found.");
}
```
Alternatively, parameters which are named `request` or `req` will also be fulfilled with the Express request. Likewise, `response` or `res`
can be used to get the response object. Note that using `RouteEvent` is preferred and recommended since it is a type-based rule.
```typescript
@Get('/do')
doThings(req : express.Request, res : express.Response) {
res.status(404).send("Not found.");
}
```
Also, parameters named `body` will be filled with the value of `request.body`, which is useful since you can set the type of the parameter to whatever you
need to, such as an interface describing the expected fields that clients can send. When combined with value returns, you can achieve a very natural style:
```typescript
interface MyRequestType {
action : string;
foo? : number;
}
@Get('/do')
doThings(body : MyRequestType) {
return {status: "success"};
}
```
## HTTP Exceptions
The `HttpException` class is included to signal Alterior to send certain HTTP status codes and responses back to the client when exceptional circumstances occur.
```typescript
// Perhaps we couldn't contact a microservice needed to fulfill the request.
throw new HttpException(502, "Service is not available");
```
## Dependency Injection

@@ -206,2 +261,6 @@

This is Angular 2's dependency injector, so you can define your own services just as you would in Angular.
You can add providers at the bootstrap, app-class or controller levels.
You can add providers at the bootstrap, or app-class levels.
## That's great but how do you pronounce this?
Alterior is pronounced like "ulterior" but with an A. We know it's not a proper word :-)

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc