Skip to content

Commit 3da310e

Browse files
author
hirsch88
committed
Merge branch 'release/2.0.0-beta.6'
2 parents 87e29b1 + e4faa9e commit 3da310e

22 files changed

+566
-298
lines changed

.env.example

+9-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#
44
APP_NAME="express-typescript-boilerplate"
55
APP_ENV="local"
6-
APP_HOST="http://localhost"
6+
APP_HOST="http://localhost:3000"
77
APP_URL_PREFIX="/api"
88
APP_PORT=3000
99

@@ -13,6 +13,12 @@ APP_PORT=3000
1313
LOG_LEVEL="debug"
1414
LOG_ADAPTER="winston"
1515

16+
#
17+
# APPLICATION
18+
#
19+
APP_BASIC_USER="admin"
20+
APP_BASIC_PASSWORD="1234"
21+
1622
#
1723
# API Info
1824
#
@@ -23,14 +29,14 @@ API_INFO_ROUTE="/info"
2329
# Swagger Documentation
2430
#
2531
SWAGGER_ENABLED=true
26-
SWAGGER_ROUTE="/docs"
32+
SWAGGER_ROUTE="/swagger"
2733
SWAGGER_FILE="/src/api/swagger.json"
2834

2935
#
3036
# Monitor
3137
#
3238
MONITOR_ENABLED=true
33-
MONITOR_ROUTE="/status"
39+
MONITOR_ROUTE="/monitor"
3440

3541
#
3642
# DATABASE
@@ -53,5 +59,4 @@ DB_SEEDS_DIR="./src/database/seeds"
5359
#
5460
# Auth0
5561
#
56-
# AUTH0_HOST="https://w3tecch.auth0.com"
5762
AUTH0_HOST="http://localhost:3333"

.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ node_js:
44
install:
55
- yarn install
66
scripts:
7-
- npm test
8-
- npm run build
7+
- nps test
8+
- nps build
99
notifications:
1010
email: false

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Try it!! We are happy to hear your feedback or any kind of new features.
3535
- **Easy Exception Handling** with our own simple and easy to adopt logic. You will love it.
3636
- **Easy Data Seeding** with our own factories.
3737
- **Custom Commands** are also available in our setup and really easy to use or even extend.
38+
- **Custom Validators** to validate your request even better and stricter. [custom-validation-classes](https://github.com/pleerock/class-validator#custom-validation-classes)
3839
- **Scaffolding Commands** will speed up your development tremendously as you should focus on business code and not scaffolding.
3940
- **Smart Validation** thanks to [class-validator](https://github.com/pleerock/class-validator) with some nice annotations.
4041
- **API Documentation** thanks to [swagger](http://swagger.io/).
@@ -152,7 +153,7 @@ All script are defined in the package.json file, but the most important ones are
152153
* There is also a vscode task for this called `lint`.
153154

154155
### Tests
155-
* Run the unit tests using `npm test` (There is also a vscode task for this called `test`).
156+
* Run the unit tests using `nps test` (There is also a vscode task for this called `test`).
156157
* Run the e2e tests using `nps test:e2e` and don't forget to start your application and your [Auth0 Mock Server](https://github.com/hirsch88/auth0-mock-server).
157158

158159
### Running in dev mode
@@ -185,6 +186,7 @@ All the templates for the commands are located in `src/console/templates`.
185186
* `npm run console make:request <file>` - Generates a basic request.
186187
* `npm run console make:listener <file>` - Generates a basic listener.
187188
* `npm run console make:exception <file>` - Generates a basic exception.
189+
* `npm run console make:validator <file>` - Generates a custom validator.
188190
* `npm run console update:targets <file>` - Reads all the API files and generate a new `constants/Targets.ts` file out of it.
189191

190192
**Example**
@@ -230,6 +232,7 @@ The route prefix is `/api` by default, but you can change this in the .env file.
230232
| **src/api/repositories/** | Repository / DB layer |
231233
| **src/api/requests/** | Request bodys with validations |
232234
| **src/api/services/** | Service layer |
235+
| **src/api/validators/** | Custom validators, which can be used in the request classes |
233236
| **src/api/** swagger.json | Swagger documentation |
234237
| **src/console/** | Command line scripts |
235238
| **src/config/** | Configurations like database or logger |

appveyor.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ install:
66
- yarn install
77

88
build_script:
9-
- npm run build
9+
- nps build
1010

1111
test_script:
12-
- npm test
12+
- nps test

package.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
{
22
"name": "express-typescript-boilerplate",
3-
"version": "2.0.0-beta.5",
3+
"version": "2.0.0-beta.6",
44
"description": "A delightful way to building a RESTful API with NodeJs & TypeScript",
55
"main": "src/app.ts",
6+
"engines": {
7+
"node": "8.2.1"
8+
},
69
"scripts": {
710
"start": "node dist/app.js",
811
"test": "nps test",
@@ -60,6 +63,7 @@
6063
"@types/request": "^2.0.7",
6164
"@types/request-promise": "^4.1.39",
6265
"@types/serve-favicon": "^2.2.29",
66+
"@types/uuid": "^3.4.3",
6367
"@types/winston": "^2.3.7",
6468
"body-parser": "^1.18.2",
6569
"bookshelf": "^0.10.4",
@@ -72,6 +76,7 @@
7276
"cors": "^2.8.4",
7377
"dotenv": "^4.0.0",
7478
"express": "^4.16.2",
79+
"express-basic-auth": "^1.1.3",
7580
"express-status-monitor": "^1.0.1",
7681
"faker": "^4.1.0",
7782
"figlet": "^1.2.0",
@@ -99,6 +104,7 @@
99104
"ts-node": "^3.3.0",
100105
"tslint": "^5.8.0",
101106
"typescript": "^2.6.1",
107+
"uuid": "^3.1.0",
102108
"wait-on": "^2.0.2",
103109
"winston": "^2.4.0"
104110
},

src/api/requests/user/UserCreateRequest.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { IsEmail, IsNotEmpty } from 'class-validator';
1+
import { IsEmail, IsNotEmpty, Validate } from 'class-validator';
22
import { RequestBody } from '../../../core/api/RequestBody';
3+
import { EndsWithValidator } from '../../Validators/EndsWithValidator';
34

45
/**
56
* This class is used for create request. Create a new instance
@@ -20,6 +21,7 @@ export class UserCreateRequest extends RequestBody {
2021

2122
@IsNotEmpty()
2223
@IsEmail()
24+
@Validate(EndsWithValidator, ['@gmail.com', '@w3tec.ch'])
2325
public email: string;
2426

2527
public picture: string;

src/api/requests/user/UserUpdateRequest.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { IsEmail, IsNotEmpty } from 'class-validator';
1+
import { IsEmail, IsNotEmpty, Validate } from 'class-validator';
22
import { RequestBody } from '../../../core/api/RequestBody';
3+
import { EndsWithValidator } from '../../Validators/EndsWithValidator';
34

45
/**
56
* This class is used for update request. Create a new instance
@@ -19,6 +20,7 @@ export class UserUpdateRequest extends RequestBody {
1920
public lastName: string;
2021

2122
@IsEmail()
23+
@Validate(EndsWithValidator, ['@gmail.com', '@w3tec.ch'])
2224
public email: string;
2325

2426
@IsNotEmpty()
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as _ from 'lodash';
2+
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';
3+
4+
5+
@ValidatorConstraint({ name: 'endsWith', async: false })
6+
export class EndsWithValidator implements ValidatorConstraintInterface {
7+
8+
public validate(text: string, args: ValidationArguments): boolean {
9+
for (const ending of args.constraints) {
10+
if (_.endsWith(text, ending)) {
11+
return true;
12+
}
13+
}
14+
return false;
15+
}
16+
17+
public defaultMessage(args: ValidationArguments): string {
18+
return 'Incorrect suffix';
19+
}
20+
21+
}

src/app.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212

1313
import 'reflect-metadata';
1414
import { App } from './core/App';
15-
import { CustomConfig } from './config/CustomConfig';
15+
import { CustomHeaderConfig } from './config/CustomHeaderConfig';
1616

1717
export const app = new App();
1818

1919

2020
// Here you can add more custom configurations
21-
app.configure(new CustomConfig());
21+
app.configure(new CustomHeaderConfig());
2222

2323
// Launch the server with all his awesome features.
2424
app.bootstrap();

src/config/CustomConfig.ts

-20
This file was deleted.

src/config/CustomHeaderConfig.ts

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* config.Custom
3+
* ------------------------------------
4+
*
5+
* Define all log adapters for this application and chose one.
6+
*/
7+
8+
import * as express from 'express';
9+
import * as uuid from 'uuid';
10+
11+
import { Logger } from '../core/Logger';
12+
import { App, Configurable } from '../core/App';
13+
import { Environment } from '../core/helpers/Environment';
14+
15+
16+
export class CustomHeaderConfig implements Configurable {
17+
18+
private log = new Logger(__filename);
19+
20+
public configure(app: App): void {
21+
this.log.debug('Add custom headers');
22+
23+
app.Express.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
24+
res.setHeader('X-API-VERSION', Environment.getPkg().version);
25+
res.setHeader('X-Request-Id', uuid.v4());
26+
next();
27+
});
28+
29+
}
30+
}
31+

src/console/MakeValidatorCommand.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* MakeValidatorCommand
3+
* -------------------------------------
4+
*
5+
*/
6+
import { AbstractMakeCommand } from './lib/AbstractMakeCommand';
7+
8+
9+
export class MakeValidatorCommand extends AbstractMakeCommand {
10+
11+
public static command = 'make:validator';
12+
public static description = 'Generate new validator';
13+
14+
public type = 'Validator';
15+
public suffix = 'Validator';
16+
public template = 'validator.hbs';
17+
public target = 'api/validators';
18+
public updateTargets = false;
19+
20+
}

src/console/templates/validator.hbs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';
2+
3+
4+
@ValidatorConstraint({ name: '{{name.normal}}', async: false })
5+
export class {{name.capitalize}}Validator implements ValidatorConstraintInterface {
6+
7+
public validate(text: string, args: ValidationArguments): boolean {
8+
// Place your validation here
9+
return true;
10+
}
11+
12+
public defaultMessage(args: ValidationArguments): string {
13+
// Error message if the validation fails
14+
return 'Incorrect value';
15+
}
16+
17+
}

src/core/ApiInfo.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ export class ApiInfo {
1010
return process.env.APP_URL_PREFIX + process.env.API_INFO_ROUTE;
1111
}
1212

13-
public setup(app: express.Application): void {
13+
public setup(application: express.Application): void {
1414
if (Environment.isTruthy(process.env.API_INFO_ENABLED)) {
15-
app.get(
15+
application.get(
1616
ApiInfo.getRoute(),
1717
// @ts-ignore: False type definitions from express
1818
(req: myExpress.Request, res: myExpress.Response) => {
@@ -22,11 +22,11 @@ export class ApiInfo {
2222
};
2323
if (Environment.isTruthy(process.env.SWAGGER_ENABLED)) {
2424
links.links['swagger'] =
25-
`${app.get('host')}:${app.get('port')}${SwaggerUI.getRoute()}`;
25+
`${application.get('host')}${SwaggerUI.getRoute()}`;
2626
}
2727
if (Environment.isTruthy(process.env.MONITOR_ENABLED)) {
2828
links.links['monitor'] =
29-
`${app.get('host')}:${app.get('port')}${ApiMonitor.getRoute()}`;
29+
`${application.get('host')}${ApiMonitor.getRoute()}`;
3030
}
3131
return res.json({
3232
name: pkg.name,

src/core/ApiMonitor.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as express from 'express';
22
import * as monitor from 'express-status-monitor';
33
import { Environment } from './helpers/Environment';
4+
import { BasicAuthentication } from './BasicAuthentication';
45

56

67
export class ApiMonitor {
@@ -12,7 +13,7 @@ export class ApiMonitor {
1213
public setup(app: express.Application): void {
1314
if (Environment.isTruthy(process.env.MONITOR_ENABLED)) {
1415
app.use(monitor());
15-
app.get(ApiMonitor.getRoute(), monitor().pageRoute);
16+
app.get(ApiMonitor.getRoute(), BasicAuthentication(), monitor().pageRoute);
1617
}
1718
}
1819
}

src/core/BasicAuthentication.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as basicAuth from 'express-basic-auth';
2+
3+
4+
export const BasicAuthentication = (): any => {
5+
return basicAuth({
6+
users: {
7+
[process.env.APP_BASIC_USER]: process.env.APP_BASIC_PASSWORD
8+
},
9+
challenge: true
10+
});
11+
};

src/core/Server.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,21 @@ export class Server {
6565
*/
6666
public onStartUp(app: express.Application): void {
6767
this.log.debug(``);
68-
this.log.debug(`Aloha, your app is ready on ${app.get('host')}:${app.get('port')}${process.env.APP_URL_PREFIX}`);
68+
this.log.debug(`Aloha, your app is ready on ${app.get('host')}${process.env.APP_URL_PREFIX}`);
6969
this.log.debug(`To shut it down, press <CTRL> + C at any time.`);
7070
this.log.debug(``);
7171
this.log.debug('-------------------------------------------------------');
7272
this.log.debug(`Environment : ${Environment.getNodeEnv()}`);
7373
this.log.debug(`Version : ${Environment.getPkg().version}`);
7474
this.log.debug(``);
7575
if (Environment.isTruthy(process.env.API_INFO_ENABLED)) {
76-
this.log.debug(`API Info : ${app.get('host')}:${app.get('port')}${ApiInfo.getRoute()}`);
76+
this.log.debug(`API Info : ${app.get('host')}${ApiInfo.getRoute()}`);
7777
}
7878
if (Environment.isTruthy(process.env.SWAGGER_ENABLED)) {
79-
this.log.debug(`Swagger : ${app.get('host')}:${app.get('port')}${SwaggerUI.getRoute()}`);
79+
this.log.debug(`Swagger : ${app.get('host')}${SwaggerUI.getRoute()}`);
8080
}
8181
if (Environment.isTruthy(process.env.MONITOR_ENABLED)) {
82-
this.log.debug(`Monitor : ${app.get('host')}:${app.get('port')}${ApiMonitor.getRoute()}`);
82+
this.log.debug(`Monitor : ${app.get('host')}${ApiMonitor.getRoute()}`);
8383
}
8484
this.log.debug('-------------------------------------------------------');
8585
this.log.debug('');

0 commit comments

Comments
 (0)