Skip to content

Commit

Permalink
Merge branch 'release/2.0.0-beta.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
hirsch88 committed Jul 11, 2017
2 parents 5e9dcb7 + 83c401e commit cebfb14
Show file tree
Hide file tree
Showing 40 changed files with 643 additions and 466 deletions.
119 changes: 98 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,104 @@ Try it!! We are happy to hear your feedback or any kind of new features.
- **Integrated Testing Tool** thanks to [Wallaby.js](https://wallabyjs.com/)

## Getting Started
### Prerequisites
* Install [Node.js](http://nodejs.org)
* on OSX use [homebrew](http://brew.sh) `brew install node`
* on Windows use [chocolatey](https://chocolatey.org/) `choco install nodejs`
* Install yarn globally `npm install yarn -g`

### Installing
* `fork` this repo
* `clone` your fork
* `cp .env.example .env` to copy the example .env file and enter your database connection
* Create a new database. You will find the name in the .env file.
* Run `npm run setup` or enter the following commands manually:
* `yarn install` to install all dependencies and typings.
* `npm run db:migrate` to create the schema.
* `npm run db:seed` to insert some test data.
* `npm run serve` to start the application.

### Running the app
After you have installed all dependencies you can run the app.
Enter `npm run serve` to start a local server using `nodemon`, which will watch for any file changes and will restart the sever according to these changes.
The server address will be displayed to you as `http://0.0.0.0:3000`.
### Step 1: Set up the Development Environment
You need to set up your development environment before you can do anything.

Install [Node.js and NPM](https://nodejs.org/en/download/)
* on OSX use [homebrew](http://brew.sh) `brew install node`
* on Windows use [chocolatey](https://chocolatey.org/) `choco install nodejs`

Install yarn globally
```
npm install yarn -g
```

Install a MySQL database.

> If you work with a mac, we recommend to use homebrew for the installation.
### Step 2: Create new Project
Fork or download this project. Configure your package.json for your new project.

Then copy the `example.env` file and rename it to `.env`. In this file you have to add your database connection information.

Create a new database with the name you have in your `.env`-file.

Then setup your application environment.
```
npm run setup
```

> This installs all dependencies with yarn. After that it migrates the database and seeds some test data into it. So after that your development environment is ready to use.
### Step 3: Serve your App
Go to the project dir and start your app with this npm script.
```
npm run serve
```

> This starts a local server using `nodemon`, which will watch for any file changes and will restart the sever according to these changes.
> The server address will be displayed to you as `http://0.0.0.0:3000`.
### Step 4: Create a new Resource
Go to the project dir and hit this command in your terminal.
```
npm run console make:resource
```

Apply the same information like you see in the screenshot below.

![console](console.png)

> With that you just have created a complete new endpoint in your api for the resource pets.
Normally a pet belogns to a user, so we have to add the relationship between users an pets. Open the created migration file and replace the user property with these lines.
```
table.integer('user_id').unsigned();
table.foreign('user_id').references('id').inTable('users').onDelete('cascade');
```

Next we have to add this relationship also in the pets model.
```
public user(): User {
return this.belongsTo(User);
}
```

> The relationship between the users and pets are set and ready. So you can migrate your database with `npm run db:migrate`
### Step 5: Create a Seeder
To seed some cute pets we need a smart factory. So open the ./src/database/factories/index.ts and add this code.
```
/**
* PET - Factory
*/
factory.define(Pet, (faker: Faker.FakerStatic, args: any[]) => {
const type = args[0];
return {
name: faker.name.firstName(),
type: type || 'dog',
userId: factory.get(User).returning('id')
};
});
```

> This factory helps us to create a fake pet to seed to the database.
Run this command in your terminal and call the new seeder `create pets`.
```
npm run console make:seed
```

Open the file and place this code into it.
```
await factory.get(Pet)
.create(10);
```

> Now we can seed some nice cats into the database with `npm run db:seed`.
> That was easy! Now its your turn to make something great out of it.
## Scripts / Tasks
All script are defined in the package.json file, but the most important ones are listed here.
Expand Down
Binary file added console.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 0 additions & 17 deletions knexfile.js

This file was deleted.

7 changes: 7 additions & 0 deletions knexfile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require('dotenv').config();

/**
* This is the database configuration for the migrations and
* the seeders.
*/
module.exports = require('./src/config/Database').DatabaseConfig;
5 changes: 2 additions & 3 deletions nodemon.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
{
"delay": "0",
"execMap": {
"ts": "./node_modules/.bin/ts-node"
"ts": "ts-node"
},
"events": {
"start": "./node_modules/.bin/tslint -c ./tslint.json -t stylish 'src/**/*.ts'",
"restart": "osascript -e 'display notification \"restarting server\" with title \"node.js application\"'"
"start": "tslint -c ./tslint.json -t stylish 'src/**/*.ts'"
}
}
76 changes: 37 additions & 39 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
{
"name": "express-typescript-boilerplate",
"version": "2.0.0-beta.1",
"version": "2.0.0-beta.2",
"description": "A delightful way to building a RESTful API with NodeJs & TypeScript",
"main": "src/app.ts",
"scripts": {
"banner": "npm run ts-node:fast -- ./src/console/lib/banner.ts",
"ts-node": "./node_modules/.bin/ts-node",
"ts-node:fast": "./node_modules/.bin/ts-node -F",
"setup": "yarn install && npm run banner setup && npm run db:migrate && npm run db:seed",
"serve": "npm run banner serve && \"./node_modules/.bin/nodemon\" --watch src --watch .env",
"build": "npm run banner build && npm run lint && npm run clean:dist && npm run transpile && npm run copy:assets",
"start": "node dist/app.js",
"pretest": "./node_modules/.bin/tslint -c ./tslint.json -t stylish './test/unit/**/*.ts'",
"test": "npm run banner test && cross-env NODE_ENV=test \"./node_modules/.bin/jest\" --testPathPattern=unit",
"test:pretty": "npm run test -- --verbose",
"test:coverage": "npm run test -- --coverage",
"pretest:black-box": "./node_modules/.bin/tslint -c ./tslint.json -t stylish './test/black-box/**/*.ts'",
"test:black-box": "npm run banner test && NODE_ENV=test ./node_modules/.bin/jest ./test/black-box -i",
"test:black-box": "npm run banner test && cross-env NODE_ENV=test \"./node_modules/.bin/jest\" --testPathPattern=black-box -i",
"test:black-box:pretty": "npm run test:black-box -- --verbose",
"db:migrate": "npm run banner migrate && \"./node_modules/.bin/knex\" migrate:latest",
"db:migrate:rollback": "npm run banner rollback && \"./node_modules/.bin/knex\" migrate:rollback",
"db:seed": "npm run banner seed && \"./node_modules/.bin/knex\" seed:run",
"db:reset": "npm run console db:reset",
"console": "npm run ts-node:fast -- ./src/console/lib/console.ts",
"console:dev": "npm run ts-node -- ./src/console/lib/console.ts",
"console:help": "npm run ts-node:fast -- ./src/console/lib/console.ts --help",
"lint": "./node_modules/.bin/tslint -c ./tslint.json -p tsconfig.json 'src/**/*.ts' --format stylish",
"transpile": "./node_modules/.bin/tsc",
"clean": "npm run banner clean && npm run clean:dist",
"clean:dist": "./node_modules/.bin/trash './dist'",
"copy:assets": "npm run copy:swagger && npm run copy:public",
"copy:swagger": "./node_modules/.bin/copyup ./src/api/swagger.json ./dist",
"copy:public": "./node_modules/.bin/copyup ./src/public/* ./dist",
"db:migrate": "npm run banner migrate && npm run ts-node:fast -- ./node_modules/.bin/knex migrate:latest",
"db:migrate:rollback": "npm run banner rollback && npm run ts-node:fast -- ./node_modules/.bin/knex migrate:rollback",
"db:seed": "npm run banner seed && npm run ts-node:fast -- ./node_modules/.bin/knex seed:run",
"db:reset": "npm run console db:reset",
"console": "npm run ts-node:fast -- ./src/console/commander.ts",
"console:dev": "npm run ts-node -- ./src/console/commander.ts",
"console:help": "npm run ts-node:fast -- ./src/console/commander.ts --help",
"setup": "npm run banner setup && yarn install && npm run db:migrate && npm run db:seed",
"serve": "npm run banner serve && ./node_modules/.bin/nodemon --watch 'src/**/*.ts' --watch 'src/**/*.json' --watch '.env'",
"clean": "npm run banner clean && npm run clean:dist",
"test": "npm run banner test && NODE_ENV=test ./node_modules/.bin/jest ./test/unit",
"build": "npm run banner build && npm run lint && npm run clean:dist && npm run transpile && npm run copy:assets",
"start": "node dist/app.js"
"banner": "npm run ts-node:fast -- ./src/console/lib/banner.ts",
"ts-node": "./node_modules/.bin/ts-node",
"ts-node:fast": "./node_modules/.bin/ts-node -F"
},
"repository": "git+ssh://git@github.com/w3tec/express-typescript-boilerplate.git",
"engines": {
Expand Down Expand Up @@ -75,24 +75,23 @@
"@types/helmet": "0.0.35",
"@types/inquirer": "^0.0.35",
"@types/jest": "^20.0.2",
"@types/jsonwebtoken": "^7.2.1",
"@types/jsonwebtoken": "^7.2.2",
"@types/knex": "0.0.52",
"@types/lodash": "^4.14.67",
"@types/mkdirp": "^0.3.29",
"@types/lodash": "^4.14.68",
"@types/morgan": "^1.7.32",
"@types/pluralize": "^0.0.27",
"@types/reflect-metadata": "0.0.5",
"@types/request": "^0.0.45",
"@types/request-promise": "^4.1.35",
"@types/request-promise": "^4.1.36",
"@types/serve-favicon": "^2.2.28",
"@types/winston": "^2.3.3",
"body-parser": "^1.17.2",
"bookshelf": "^0.10.3",
"bookshelf-camelcase": "^1.1.4",
"chalk": "^1.1.3",
"chalk": "^2.0.1",
"class-validator": "^0.7.2",
"commander": "^2.10.0",
"compression": "^1.6.2",
"commander": "^2.11.0",
"compression": "^1.7.0",
"copyfiles": "^1.2.0",
"cors": "^2.8.1",
"dotenv": "^4.0.0",
Expand All @@ -103,14 +102,12 @@
"glob": "^7.1.2",
"handlebars": "^4.0.10",
"helmet": "^3.6.1",
"inquirer": "^3.1.1",
"inversify": "^4.1.1",
"inversify-express-utils": "^3.5.1",
"jest": "^20.0.3",
"inquirer": "^3.2.0",
"inversify": "^4.2.0",
"inversify-express-utils": "^4.0.0",
"jsonwebtoken": "^7.4.1",
"knex": "^0.12.0",
"lodash": "^4.17.4",
"mkdirp": "^0.5.1",
"morgan": "^1.7.0",
"mysql": "^2.13.0",
"nodemon": "^1.11.0",
Expand All @@ -119,16 +116,12 @@
"reflect-metadata": "^0.1.10",
"request": "^2.81.0",
"request-promise": "^4.2.1",
"require-dir": "^0.3.2",
"rimraf": "^2.6.1",
"run-sequence": "^1.2.2",
"serve-favicon": "^2.4.3",
"swagger-jsdoc": "^1.9.5",
"swagger-ui-express": "^2.0.0",
"swagger-jsdoc": "^1.9.6",
"swagger-ui-express": "^2.0.1",
"trash-cli": "^1.4.0",
"ts-jest": "^20.0.6",
"ts-node": "^3.1.0",
"tslint": "^5.4.3",
"ts-node": "^3.2.0",
"tslint": "^5.5.0",
"typescript": "^2.4.1",
"winston": "^2.3.1"
},
Expand All @@ -146,5 +139,10 @@
"testEnvironment": "node",
"setupTestFrameworkScriptFile": "./test/unit/lib/setup.ts"
},
"license": "MIT"
"license": "MIT",
"devDependencies": {
"cross-env": "^5.0.1",
"jest": "^20.0.3",
"ts-jest": "^20.0.7"
}
}
28 changes: 14 additions & 14 deletions src/api/controllers/UserController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { inject, named } from 'inversify';
import { Controller, Get, Post, Put, Delete, RequestParam, RequestBody, Response, Request } from 'inversify-express-utils';
import { controller, httpGet, httpPost, httpPut, httpDelete, response, request, requestBody, requestParam } from 'inversify-express-utils';
import { app } from '../../app';
import { Types, Targets } from '../../constants';
import { UserService } from '../services/UserService';
Expand All @@ -17,42 +17,42 @@ const populateUser = app.IoC.getNamed<interfaces.Middleware>(Types.Middleware, T
const authenticate = app.IoC.getNamed<interfaces.Middleware>(Types.Middleware, Targets.Middleware.AuthenticateMiddleware);


@Controller('/users', authenticate.use)
@controller('/users', authenticate.use)
export class UserController {

constructor( @inject(Types.Service) @named(Targets.Service.UserService) private userService: UserService) { }

@Get('/')
public async findAll( @Response() res: myExpress.Response): Promise<any> {
@httpGet('/')
public async findAll( @response() res: myExpress.Response): Promise<any> {
const users = await this.userService.findAll();
return res.found(users.toJSON());
}

@Post('/')
public async create( @Response() res: myExpress.Response, @RequestBody() body: any): Promise<any> {
@httpPost('/')
public async create( @response() res: myExpress.Response, @requestBody() body: any): Promise<any> {
const user = await this.userService.create(body);
return res.created(user.toJSON());
}

@Get('/me', populateUser.use)
public async findMe( @Request() req: myExpress.Request, @Response() res: myExpress.Response): Promise<any> {
@httpGet('/me', populateUser.use)
public async findMe( @request() req: myExpress.Request, @response() res: myExpress.Response): Promise<any> {
return res.found(req.user);
}

@Get('/:id')
public async findOne( @Response() res: myExpress.Response, @RequestParam('id') id: string): Promise<any> {
@httpGet('/:id')
public async findOne( @response() res: myExpress.Response, @requestParam('id') id: string): Promise<any> {
const user = await this.userService.findOne(parseInt(id, 10));
return res.found(user.toJSON());
}

@Put('/:id')
public async update( @Response() res: myExpress.Response, @RequestParam('id') id: string, @RequestBody() body: any): Promise<any> {
@httpPut('/:id')
public async update( @response() res: myExpress.Response, @requestParam('id') id: string, @requestBody() body: any): Promise<any> {
const user = await this.userService.update(parseInt(id, 10), body);
return res.updated(user.toJSON());
}

@Delete('/:id')
public async destroy( @Response() res: myExpress.Response, @RequestParam('id') id: string): Promise<any> {
@httpDelete('/:id')
public async destroy( @response() res: myExpress.Response, @requestParam('id') id: string): Promise<any> {
await this.userService.destroy(parseInt(id, 10));
return res.destroyed();
}
Expand Down
10 changes: 5 additions & 5 deletions src/api/services/UserService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { inject, named } from 'inversify';
import { Types, Core, Targets } from '../../constants';
import { Logger as LoggerType } from '../../core/Logger';
import { EventEmitter } from '../../core/api/events';
import { Validate, Request } from '../../core/api/Validate';
import { validate, request } from '../../core/api/Validate';
import { NotFoundException } from '../exceptions/NotFoundException';
import { UserCreateRequest } from '../requests/user/UserCreateRequest';
import { UserUpdateRequest } from '../requests/user/UserUpdateRequest';
Expand Down Expand Up @@ -77,8 +77,8 @@ export class UserService {
* @param {*} data is the json body of the request
* @returns {Promise<User>}
*/
@Validate()
public async create( @Request(UserCreateRequest) data: any): Promise<User> {
@validate()
public async create( @request(UserCreateRequest) data: any): Promise<User> {
// If the request body was valid we will create the user
const user = await this.userRepo.create(data);
this.events.emit(UserCreatedListener.Event, user.toJSON());
Expand All @@ -93,8 +93,8 @@ export class UserService {
* @param {*} newUser is the json body of the request
* @returns {Promise<User>}
*/
@Validate()
public async update(id: number, @Request(UserUpdateRequest) newUser: any): Promise<User> {
@validate()
public async update(id: number, @request(UserUpdateRequest) newUser: any): Promise<User> {
// Find or fail
const user = await this.findOne(id);
// Set new values
Expand Down
Loading

0 comments on commit cebfb14

Please sign in to comment.