Skip to content

Commit a6bc97f

Browse files
authored
Merge pull request #58 from cham11ng/say-no-to-any
Say No to any, refactor codebase
2 parents f1f7377 + db90b8d commit a6bc97f

File tree

19 files changed

+96
-283
lines changed

19 files changed

+96
-283
lines changed

README.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
</a>
66
</p>
77

8-
Starter for Node.js Express API in Typescript.
8+
Starter for Node.js Express API in Typescript with jsonwebtoken, joi, Knex, Objection.js and many other popular tools.
99

1010
## Requirements
1111

1212
- [Node.js](https://yarnpkg.com/en/docs/install)
1313
- [Yarn](https://yarnpkg.com/en/docs/install)
1414
- [NPM](https://docs.npmjs.com/getting-started/installing-node)
1515
- [Docker](https://docs.docker.com/install/)
16-
- [Docker Compose](https://docs.docker.com/compose/install/)
1716

1817
## Getting Started
1918

@@ -42,11 +41,9 @@ $ yarn load:fake <FactoryName> <Number>
4241
Start the application.
4342

4443
```bash
45-
$ yarn build
44+
$ yarn build # For production
4645

47-
$ yarn start # For production
48-
49-
$ yarn start:dev # For development
46+
$ yarn start # For development
5047
```
5148

5249
<p align="center">
@@ -64,23 +61,23 @@ $ cp .env.docker .env
6461
Install dependencies and run the application locally.
6562

6663
```bash
67-
$ docker-compose up -d postgres
64+
$ docker compose up -d postgres
6865

69-
$ docker-compose up -d api
66+
$ docker compose up -d api
7067

71-
$ docker-compose exec api sh yarn migrate # Make sure server is started checking logs before running this command
68+
$ docker compose exec api sh yarn migrate # Make sure server is started checking logs before running this command
7269
```
7370

7471
View logs of the container.
7572

7673
```bash
77-
$ docker-compose logs -f
74+
$ docker compose logs -f
7875
```
7976

8077
To stop the services.
8178

8279
```bash
83-
$ docker-compose stop api postgres
80+
$ docker compose stop api postgres
8481
```
8582

8683
## Generating Migrations and Seeds

api.rest

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ GET {{host}} HTTP/1.1
22

33
###
44

5+
GET {{host}}/users HTTP/1.1
6+
Authorization: {{accessToken}}
7+
8+
###
9+
510
POST {{host}}/login HTTP/1.1
611
Content-Type: application/json
712

@@ -15,4 +20,7 @@ Content-Type: application/json
1520
POST {{host}}/refresh HTTP/1.1
1621
Authorization: {{refreshToken}}
1722

18-
###
23+
###
24+
25+
POST {{host}}/logout HTTP/1.1
26+
Authorization: {{refreshToken}}

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
],
5454
"dependencies": {
5555
"bcrypt": "^5.0.1",
56-
"bookshelf-case-converter-plugin": "^2.0.0",
5756
"cors": "^2.8.5",
5857
"date-fns": "^2.11.1",
5958
"dotenv": "^16.0.1",

scripts/fake-loader.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import chalk from 'chalk';
22

33
import * as fake from '../src/utils/fake';
4+
import { bindModel } from '../src/config/db';
45
import factories, { FactoryType } from '../src/database/factories';
56

67
const { info } = console;
@@ -18,10 +19,12 @@ function print<T>(data: T): void {
1819

1920
const factoryCallback = factories[table as FactoryType].run;
2021

22+
bindModel();
23+
2124
print(await fake.generate(factoryCallback, total));
2225

2326
process.exit(0);
24-
} catch (err: any) {
27+
} catch (err) {
2528
info(chalk`{red ${err.message}}`);
2629

2730
process.exit(1);

src/app.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
import cors from 'cors';
22
import helmet from 'helmet';
33
import express from 'express';
4-
import { Model } from 'objection';
54

65
import routes from './routes';
7-
import knex from './config/knex';
6+
import { bindModel } from './config/db';
87
import logHandler from './middlewares/logHandler';
98
import notFoundHandler from './middlewares/notFoundHandler';
109
import transactionHandler from './middlewares/transactionHandler';
1110
import genericErrorHandler from './middlewares/genericErrorHandler';
1211

13-
Model.knex(knex);
14-
1512
const app: express.Application = express();
1613

14+
bindModel();
15+
1716
app.use(cors());
1817
app.use(helmet());
1918
app.use(transactionHandler);

src/config/db.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Knex from 'knex';
2+
import { Model, knexSnakeCaseMappers } from 'objection';
3+
4+
import config from './config';
5+
6+
const dbConfig = config.db;
7+
8+
const knex = Knex({ ...dbConfig, ...knexSnakeCaseMappers() });
9+
10+
/**
11+
* Bind model with Knex.
12+
*/
13+
export function bindModel() {
14+
Model.knex(knex);
15+
}
16+
17+
export default knex;

src/config/knex.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/middlewares/authenticate.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1+
import { JsonWebTokenError } from 'jsonwebtoken';
12
import { Request, Response, NextFunction } from 'express';
23

34
import * as jwt from '../utils/jwt';
45
import logger from '../utils/logger';
56
import config from '../config/config';
6-
import ErrorType from './../resources/enums/ErrorType';
7+
import { JWTErrorType } from './../resources/enums/ErrorType';
78
import BadRequestError from '../exceptions/BadRequestError';
89
import UnauthorizedError from '../exceptions/UnauthorizedError';
10+
import { tokenErrorMessageMap } from '../resources/constants/maps';
911

1012
const { errors } = config;
1113

12-
const tokenErrorMessageMap: any = {
13-
[ErrorType.INVALID]: errors.invalidToken,
14-
[ErrorType.EXPIRED]: errors.accessTokenExpired
15-
};
16-
1714
/**
1815
* A middleware to authenticate the authorization token i.e. access token.
1916
*
@@ -48,17 +45,21 @@ async function authenticate(
4845
);
4946

5047
next();
51-
} catch (err: any) {
52-
const tokenErrorMessage = tokenErrorMessageMap[err.name];
53-
logger.log('error', 'JWT: Authentication failed - %s', err.message);
48+
} catch (err) {
49+
if (err instanceof JsonWebTokenError) {
50+
const tokenErrorMessage = tokenErrorMessageMap[err.name as JWTErrorType];
51+
logger.log('error', 'JWT: Authentication failed - %s', err.message);
52+
53+
if (tokenErrorMessage) {
54+
logger.log('error', 'JWT: Token error - %s', tokenErrorMessage);
5455

55-
if (tokenErrorMessage) {
56-
logger.log('error', 'JWT: Token error - %s', tokenErrorMessage);
56+
next(new UnauthorizedError(tokenErrorMessage));
5757

58-
next(new UnauthorizedError(tokenErrorMessage));
59-
} else {
60-
next(err);
58+
return;
59+
}
6160
}
61+
62+
next(err);
6263
}
6364
}
6465

src/middlewares/validateRefreshToken.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@ import { Request, Response, NextFunction } from 'express';
33
import * as jwt from '../utils/jwt';
44
import logger from '../utils/logger';
55
import config from '../config/config';
6-
import ErrorType from './../resources/enums/ErrorType';
76
import BadRequestError from '../exceptions/BadRequestError';
7+
import { JWTErrorType } from '../resources/enums/ErrorType';
88
import UnauthorizedError from '../exceptions/UnauthorizedError';
9+
import { tokenErrorMessageMap } from '../resources/constants/maps';
910

1011
const { errors } = config;
1112

12-
const tokenErrorMessageMap: any = {
13-
[ErrorType.INVALID]: errors.invalidToken,
14-
[ErrorType.EXPIRED]: errors.refreshTokenExpired
15-
};
16-
1713
/**
1814
* A middleware to validateRefershToken the authorization token i.e. refresh token.
1915
*
@@ -49,7 +45,7 @@ async function validateRefreshToken(
4945

5046
next();
5147
} catch (err: any) {
52-
const tokenErrorMessage = tokenErrorMessageMap[err.name];
48+
const tokenErrorMessage = tokenErrorMessageMap[err.name as JWTErrorType];
5349
logger.log('error', 'JWT: Authentication failed - %s', err.message);
5450

5551
if (tokenErrorMessage) {

src/resources/constants/maps.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import config from '../../config/config';
2+
import { JWTErrorType } from '../enums/ErrorType';
3+
4+
const { errors } = config;
5+
6+
export const tokenErrorMessageMap = {
7+
[JWTErrorType.INVALID]: errors.invalidToken,
8+
[JWTErrorType.EXPIRED]: errors.refreshTokenExpired
9+
};

0 commit comments

Comments
 (0)