From 27462b061538210acc494b151d5d6c88b8d99474 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 27 Nov 2020 18:40:11 +0100 Subject: [PATCH 1/8] Fixed wrong type --- src/models/Track.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/Track.ts b/src/models/Track.ts index dc83239..9d977b2 100644 --- a/src/models/Track.ts +++ b/src/models/Track.ts @@ -22,5 +22,5 @@ export class Track { @Column() @IsInt() @IsPositive() - length: string; + length: number; } From f2efc4e37b44f9eb68cd03713a17df7d93e2c550 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 27 Nov 2020 18:46:04 +0100 Subject: [PATCH 2/8] Set env to node_env for the server --- .env.example | 3 ++- src/app.ts | 15 ++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.env.example b/.env.example index f9c3dc1..6c41318 100644 --- a/.env.example +++ b/.env.example @@ -4,4 +4,5 @@ DB_HOST=bla DB_PORT=bla DB_USER=bla DB_PASSWORD=bla -DB_NAME=bla \ No newline at end of file +DB_NAME=bla +NODE_ENV=production \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index 488b549..fd902ed 100644 --- a/src/app.ts +++ b/src/app.ts @@ -8,15 +8,16 @@ dotenvSafe.config(); const PORT = process.env.APP_PORT || 4010; const app = createExpressServer({ - controllers: [__dirname + "/controllers/*.ts"], + controllers: [__dirname + "/controllers/*.ts"], + development: process.env.NODE_ENV === "production", }); async function main() { - await loaders(app); - app.listen(PORT, () => { - consola.success( - `⚡️[server]: Server is running at http://localhost:${PORT}` - ); - }); + await loaders(app); + app.listen(PORT, () => { + consola.success( + `⚡️[server]: Server is running at http://localhost:${PORT}` + ); + }); } main(); From b382f0689bba58f9b731a7d63b44f9ba09b5d732 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 27 Nov 2020 18:48:22 +0100 Subject: [PATCH 3/8] Added errors and fixed the create model ref #4 --- src/controllers/TrackController.ts | 114 +++++++++++++++++------------ 1 file changed, 67 insertions(+), 47 deletions(-) diff --git a/src/controllers/TrackController.ts b/src/controllers/TrackController.ts index 0f68282..029ee7b 100644 --- a/src/controllers/TrackController.ts +++ b/src/controllers/TrackController.ts @@ -1,60 +1,80 @@ -import { - JsonController, - Param, - Body, - Get, - Post, - Put, - Delete, -} from "routing-controllers"; -import { getConnectionManager, Repository } from "typeorm"; -import { EntityFromBody } from "typeorm-routing-controllers-extensions"; -import { ResponseSchema } from "routing-controllers-openapi"; -import { Track } from "../models/Track"; -import { IsInt, IsNotEmpty, IsPositive, IsString } from "class-validator"; +import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined } from 'routing-controllers'; +import { getConnectionManager, Repository } from 'typeorm'; +import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; +import { ResponseSchema } from 'routing-controllers-openapi'; +import { Track } from '../models/Track'; +import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; class CreateTrack { - @IsString() - @IsNotEmpty() - name: string; + @IsString() + @IsNotEmpty() + name: string; - @IsInt() - @IsPositive() - length: string; + @IsInt() + @IsPositive() + length: number; } -@JsonController("/track") +export class TrackNotFoundError extends NotFoundError { + constructor() { + super('Track not found!'); + } +} + +@JsonController('/tracks') export class TrackController { - private trackRepository: Repository; + private trackRepository: Repository; - constructor() { - this.trackRepository = getConnectionManager().get().getRepository(Track); - } + constructor() { + this.trackRepository = getConnectionManager().get().getRepository(Track); + } - @Get() - @ResponseSchema(Track, { isArray: true }) - getAll() { - return this.trackRepository.find(); - } + @Get() + @ResponseSchema(Track, { isArray: true }) + getAll() { + return this.trackRepository.find(); + } - @Get("/:id") - @ResponseSchema(Track) - getOne(@Param("id") id: number) { - return this.trackRepository.findOne({ id: id }); - } + @Get('/:id') + @ResponseSchema(Track) + @OnUndefined(TrackNotFoundError) + getOne(@Param('id') id: number) { + return this.trackRepository.findOne({ id: id }); + } - @Post() - post(@Body({ validate: true }) track: CreateTrack) { - return this.trackRepository.save(track); - } + @Post() + @ResponseSchema(Track) + post( + @Body({ validate: true }) + track: CreateTrack + ) { + return this.trackRepository.save(track); + } - @Put("/:id") - put(@Param("id") id: number, @EntityFromBody() track: Track) { - return this.trackRepository.update({ id: id }, track); - } + @Put('/:id') + @ResponseSchema(Track) + async put(@Param('id') id: number, @EntityFromBody() track: Track) { + let oldTrack = await this.trackRepository.findOne({ id: id }); - @Delete("/:id") - remove(@Param("id") id: number) { - return this.trackRepository.delete({ id: id }); - } + if (!oldTrack) { + throw new TrackNotFoundError(); + } + + await this.trackRepository.update(oldTrack, track); + return track; + } + + @Delete('/:id') + @ResponseSchema(Track) + @OnUndefined(TrackNotFoundError) + async remove(@Param('id') id: number) { + let track = await this.trackRepository.findOne({ id: id }); + + if (!track) { + throw new TrackNotFoundError(); + } + + await this.trackRepository.delete(track); + return track; + } } From 4e5e08483d1b63ae03dc6dbb16d3277cc12bbf8d Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 27 Nov 2020 19:32:29 +0100 Subject: [PATCH 4/8] Added "/api" route prefix ref #4 #5 --- src/app.ts | 2 ++ src/loaders/openapi.ts | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app.ts b/src/app.ts index fd902ed..40863e9 100644 --- a/src/app.ts +++ b/src/app.ts @@ -10,6 +10,8 @@ const PORT = process.env.APP_PORT || 4010; const app = createExpressServer({ controllers: [__dirname + "/controllers/*.ts"], development: process.env.NODE_ENV === "production", + routePrefix: "/api", + controllers: [__dirname + "/controllers/*.ts"], }); async function main() { diff --git a/src/loaders/openapi.ts b/src/loaders/openapi.ts index 963360e..9a0ff85 100644 --- a/src/loaders/openapi.ts +++ b/src/loaders/openapi.ts @@ -11,7 +11,9 @@ export default async (app: Application) => { }); const spec = routingControllersToSpec( storage, - {}, + { + routePrefix: "/api" + }, { components: { schemas, @@ -27,11 +29,11 @@ export default async (app: Application) => { explorer: true, }; app.use( - "/docs", + "/api/docs", swaggerUiExpress.serve, swaggerUiExpress.setup(spec, options) ); - app.get(["/openapi.json", "/swagger.json"], (req, res) => { + app.get(["/api/openapi.json", "/api/swagger.json"], (req, res) => { res.json(spec); }); return app; From 24d890f638b2298ac2588786897490797a405ee5 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 27 Nov 2020 19:32:54 +0100 Subject: [PATCH 5/8] Moved cors to the routing-controller function ref #4 --- src/app.ts | 2 +- src/loaders/express.ts | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/app.ts b/src/app.ts index 40863e9..6a3e801 100644 --- a/src/app.ts +++ b/src/app.ts @@ -8,8 +8,8 @@ dotenvSafe.config(); const PORT = process.env.APP_PORT || 4010; const app = createExpressServer({ - controllers: [__dirname + "/controllers/*.ts"], development: process.env.NODE_ENV === "production", + cors: true, routePrefix: "/api", controllers: [__dirname + "/controllers/*.ts"], }); diff --git a/src/loaders/express.ts b/src/loaders/express.ts index 87b4f4c..787497a 100644 --- a/src/loaders/express.ts +++ b/src/loaders/express.ts @@ -3,12 +3,6 @@ import bodyParser from 'body-parser'; import cors from 'cors'; export default async (app: Application) => { - app.get('/status', (req, res) => res.status(200).end()); app.enable('trust proxy'); - - app.use(cors()); - // app.use(bodyParser.urlencoded({ extended: false })); - - // more middlewares return app; }; From d2278fd248658504cba856542328851f4fc6d96b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 27 Nov 2020 19:57:10 +0100 Subject: [PATCH 6/8] Added jsdoc style class documentation ref #3 --- src/models/Track.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/models/Track.ts b/src/models/Track.ts index 9d977b2..b0a789b 100644 --- a/src/models/Track.ts +++ b/src/models/Track.ts @@ -7,6 +7,12 @@ import { IsString, } from "class-validator"; +/** + * @classdesc Defines a track of given length. + * @property {number} id - Autogenerated unique id + * @property {string} name - The track's name + * @property {number} lenth - The track's length in meters +*/ @Entity() export class Track { @PrimaryGeneratedColumn() From b267d87ba66e19e61fc04a64dee5056e3cad91e5 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 27 Nov 2020 19:58:00 +0100 Subject: [PATCH 7/8] Added endpoint descriptions ref #4 --- src/controllers/TrackController.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/controllers/TrackController.ts b/src/controllers/TrackController.ts index 029ee7b..62fd70f 100644 --- a/src/controllers/TrackController.ts +++ b/src/controllers/TrackController.ts @@ -1,7 +1,7 @@ -import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined } from 'routing-controllers'; +import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError } from 'routing-controllers'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; -import { ResponseSchema } from 'routing-controllers-openapi'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { Track } from '../models/Track'; import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; @@ -25,12 +25,16 @@ export class TrackNotFoundError extends NotFoundError { export class TrackController { private trackRepository: Repository; + /** + * Gets the repository of this controller's model/entity. + */ constructor() { this.trackRepository = getConnectionManager().get().getRepository(Track); } @Get() @ResponseSchema(Track, { isArray: true }) + @OpenAPI({description: "Lists all tracks."}) getAll() { return this.trackRepository.find(); } @@ -38,12 +42,14 @@ export class TrackController { @Get('/:id') @ResponseSchema(Track) @OnUndefined(TrackNotFoundError) + @OpenAPI({description: "Returns a track of a specified id (if it exists)"}) getOne(@Param('id') id: number) { return this.trackRepository.findOne({ id: id }); } @Post() @ResponseSchema(Track) + @OpenAPI({description: "Create a new track object (id will be generated automagicly)."}) post( @Body({ validate: true }) track: CreateTrack @@ -53,6 +59,7 @@ export class TrackController { @Put('/:id') @ResponseSchema(Track) + @OpenAPI({description: "Update a track object (id can't be changed)."}) async put(@Param('id') id: number, @EntityFromBody() track: Track) { let oldTrack = await this.trackRepository.findOne({ id: id }); @@ -66,7 +73,7 @@ export class TrackController { @Delete('/:id') @ResponseSchema(Track) - @OnUndefined(TrackNotFoundError) + @OpenAPI({description: "Delete a specified track (if it exists)."}) async remove(@Param('id') id: number) { let track = await this.trackRepository.findOne({ id: id }); From aef2f9562a0c585cd567175118996a1725edf28b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 27 Nov 2020 19:59:07 +0100 Subject: [PATCH 8/8] Put now isn't allowed to change ids ref #4 --- src/controllers/TrackController.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/controllers/TrackController.ts b/src/controllers/TrackController.ts index 62fd70f..965fde9 100644 --- a/src/controllers/TrackController.ts +++ b/src/controllers/TrackController.ts @@ -64,7 +64,11 @@ export class TrackController { let oldTrack = await this.trackRepository.findOne({ id: id }); if (!oldTrack) { - throw new TrackNotFoundError(); + throw new TrackNotFoundError(); + } + + if(oldTrack.id != track.id){ + throw new NotAcceptableError("The id's don't match!"); } await this.trackRepository.update(oldTrack, track);