├── src ├── model │ ├── Category.ts │ └── Post.ts ├── controllers │ ├── PostController.ts │ └── CategoryController.ts ├── app.ts └── repository │ ├── CategoryRepository.ts │ └── PostRepository.ts ├── README.md ├── tsconfig.json ├── .gitignore └── package.json /src/model/Category.ts: -------------------------------------------------------------------------------- 1 | export class Category { 2 | 3 | id: number; 4 | name: string; 5 | 6 | constructor(id: number, name: string) { 7 | this.id = id; 8 | this.name = name; 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # routing-controllers with express demo 2 | 3 | 1. Install all dependencies: 4 | 5 | `npm install` 6 | 7 | 2. Run the project: 8 | 9 | `npm start` 10 | 11 | 3. Open in browser: 12 | 13 | `http://localhost:3000/posts` 14 | 15 | ### Using with older versions of node 16 | 17 | This project targets ES6. 18 | You can target ES5, but you'll need to use es6-shim and install its typings. 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "outDir": "build", 5 | "module": "commonjs", 6 | "target": "es6", 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "noImplicitAny": true, 11 | "sourceMap": true 12 | }, 13 | "exclude": [ 14 | "node_modules", 15 | "build" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Dependency directories 7 | node_modules 8 | 9 | # Build directory 10 | build 11 | 12 | # Editor's config directories 13 | .vscode 14 | .idea 15 | 16 | # MacOS related files 17 | *.DS_Store 18 | .AppleDouble 19 | .LSOverride 20 | ._* 21 | 22 | # Windows related files 23 | Thumbs.db 24 | ehthumbs.db 25 | Desktop.ini 26 | $RECYCLE.BIN/ 27 | 28 | # Optional npm cache directory 29 | .npm -------------------------------------------------------------------------------- /src/model/Post.ts: -------------------------------------------------------------------------------- 1 | import {Category} from "./Category"; 2 | 3 | export class Post { 4 | 5 | id: number; 6 | title: string; 7 | text: string; 8 | createDate: Date = new Date(); 9 | categories: Category[]; 10 | 11 | constructor(id: number, 12 | title: string, 13 | text: string, 14 | categories: Category[]) { 15 | this.id = id; 16 | this.title = title; 17 | this.text = text; 18 | this.categories = categories; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/controllers/PostController.ts: -------------------------------------------------------------------------------- 1 | import {JsonController, Get, Post as HttpPost, Param, Delete, Body} from "routing-controllers"; 2 | import {Service} from "typedi"; 3 | import {PostRepository} from "../repository/PostRepository"; 4 | import {Post} from "../model/Post"; 5 | 6 | @Service() 7 | @JsonController() 8 | export class PostController { 9 | 10 | constructor(private postRepository: PostRepository) { 11 | } 12 | 13 | @Get("/posts") 14 | all(): Promise { 15 | return this.postRepository.findAll(); 16 | } 17 | 18 | @Get("/posts/:id") 19 | one(@Param("id") id: number): Post { 20 | return this.postRepository.findOne(id); 21 | } 22 | 23 | @HttpPost("/posts") 24 | post(@Body() post: Post): Post { 25 | return this.postRepository.save(post); 26 | } 27 | 28 | @Delete("/posts/:id") 29 | delete(@Param("id") id: number): Post { 30 | return this.postRepository.remove(id); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/controllers/CategoryController.ts: -------------------------------------------------------------------------------- 1 | import {JsonController, Get, Post, Param, Delete, Body} from "routing-controllers"; 2 | import {Service} from "typedi"; 3 | import {CategoryRepository} from "../repository/CategoryRepository"; 4 | import {Category} from "../model/Category"; 5 | 6 | @Service() 7 | @JsonController() 8 | export class CategoryController { 9 | 10 | constructor(private categoryRepository: CategoryRepository) { 11 | } 12 | 13 | @Get("/categories") 14 | all(): Promise { 15 | return this.categoryRepository.findAll(); 16 | } 17 | 18 | @Get("/categories/:id") 19 | one(@Param("id") id: number): Category { 20 | return this.categoryRepository.findOne(id); 21 | } 22 | 23 | @Post("/categories") 24 | category(@Body() category: Category): Category { 25 | return this.categoryRepository.save(category); 26 | } 27 | 28 | @Delete("/categories/:id") 29 | delete(@Param("id") id: number): Category { 30 | return this.categoryRepository.remove(id); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import "reflect-metadata"; 2 | import {createExpressServer, useContainer, useExpressServer} from "routing-controllers"; 3 | import {Container} from "typedi"; 4 | import {CategoryController} from "./controllers/CategoryController"; 5 | import {PostController} from "./controllers/PostController"; 6 | 7 | /** 8 | * Setup routing-controllers to use typedi container. 9 | */ 10 | useContainer(Container); 11 | 12 | /** 13 | * We create a new express server instance. 14 | * We could have also use useExpressServer here to attach controllers to an existing express instance. 15 | */ 16 | const expressApp = createExpressServer({ 17 | /** 18 | * We can add options about how routing-controllers should configure itself. 19 | * Here we specify what controllers should be registered in our express server. 20 | */ 21 | controllers: [ 22 | CategoryController, 23 | PostController 24 | ] 25 | }); 26 | 27 | /** 28 | * Start the express app. 29 | */ 30 | expressApp.listen(3000); 31 | 32 | console.log("Server is up and running at port 3000"); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "routing-controllers-express-demo", 3 | "private": true, 4 | "version": "0.0.1", 5 | "description": "Example of express + typescript project using routing-controllers", 6 | "license": "MIT", 7 | "scripts": { 8 | "start": "npm run build && node ./build/app.js", 9 | "start:watch": "npm run build:watch & nodemon ./build/app.js", 10 | "build": "node_modules/.bin/tsc", 11 | "build:watch": "npm run build -- -w" 12 | }, 13 | "author": { 14 | "name": "Umed Khudoiberdiev", 15 | "email": "pleerock.me@gmail.com" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/pleerock/routing-controllers-express-demo.git" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/pleerock/routing-controllers-express-demo/issues" 23 | }, 24 | "tags": [ 25 | "express", 26 | "typescript-express", 27 | "routing-controllers" 28 | ], 29 | "dependencies": { 30 | "body-parser": "1.17.2", 31 | "express": "4.15.3", 32 | "multer": "1.3.0", 33 | "reflect-metadata": "0.1.10", 34 | "routing-controllers": "0.7.0", 35 | "typedi": "0.5.2" 36 | }, 37 | "devDependencies": { 38 | "@types/body-parser": "1.16.3", 39 | "@types/express": "4.0.35", 40 | "@types/multer": "0.0.33", 41 | "@types/node": "7.0.22", 42 | "nodemon": "1.11.0", 43 | "typescript": "2.3.3" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/repository/CategoryRepository.ts: -------------------------------------------------------------------------------- 1 | import {Service} from "typedi"; 2 | import {Category} from "../model/Category"; 3 | 4 | @Service() 5 | export class CategoryRepository { 6 | 7 | private categories = [ 8 | new Category(1, "Society"), 9 | new Category(2, "Technology"), 10 | new Category(3, "Politics"), 11 | new Category(4, "Economy"), 12 | new Category(5, "Sports"), 13 | ]; 14 | 15 | findAll() { 16 | // here, for example you can load categories using mongoose 17 | // you can also return a promise here 18 | // simulate async with creating an empty promise 19 | return Promise.resolve(this.categories); 20 | } 21 | 22 | findOne(id: number) { 23 | // here, for example you can load category id using mongoose 24 | // you can also return a promise here 25 | let foundCategory: Category = undefined; 26 | this.categories.forEach(category => { 27 | if (category.id === id) 28 | foundCategory = category; 29 | }); 30 | return foundCategory; 31 | } 32 | 33 | save(category: Category) { 34 | // here, for example you can save a category to mongodb using mongoose 35 | this.categories.push(category); 36 | return category; 37 | } 38 | 39 | remove(id: number) { 40 | // here, for example you can save a category to mongodb using mongoose 41 | const category = this.findOne(id); 42 | if (category) 43 | this.categories.splice(this.categories.indexOf(category), 1); 44 | 45 | return category; 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/repository/PostRepository.ts: -------------------------------------------------------------------------------- 1 | import {Service} from "typedi"; 2 | import {Post} from "../model/Post"; 3 | import {Category} from "../model/Category"; 4 | 5 | @Service() 6 | export class PostRepository { 7 | 8 | private posts = [ 9 | new Post(1, "post #1", "about post #1", [new Category(1, "People"), new Category(2, "Technology")]), 10 | new Post(2, "post #2", "about post #2", [new Category(2, "Technology")]), 11 | new Post(3, "post #3", "about post #3", [new Category(3, "Politics")]), 12 | new Post(4, "post #4", "about post #4", [new Category(3, "Politics"), new Category(4, "Economy")]), 13 | ]; 14 | 15 | findAll() { 16 | // here, for example you can load categories using mongoose 17 | // you can also return a promise here 18 | // simulate async with creating an empty promise 19 | return Promise.resolve(this.posts); 20 | } 21 | 22 | findOne(id: number) { 23 | // here, for example you can load post id using mongoose 24 | // you can also return a promise here 25 | let foundPost: Post = undefined; 26 | this.posts.forEach(post => { 27 | if (post.id === id) 28 | foundPost = post; 29 | }); 30 | return foundPost; 31 | } 32 | 33 | save(post: Post) { 34 | // here, for example you can save a post to mongodb using mongoose 35 | this.posts.push(post); 36 | return post; 37 | } 38 | 39 | remove(id: number) { 40 | // here, for example you can save a post to mongodb using mongoose 41 | const post = this.findOne(id); 42 | if (post) 43 | this.posts.splice(this.posts.indexOf(post), 1); 44 | 45 | return post; 46 | } 47 | 48 | } --------------------------------------------------------------------------------