Skip to content

Commit 3847665

Browse files
committed
Fix eslint
1 parent 3bbadfb commit 3847665

21 files changed

+101
-80
lines changed

.dockerignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

README.md

+19-24
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
</a>
66
</p>
77

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

1010
## Requirements
1111

@@ -16,8 +16,6 @@ Starter for Node.js Express API in Typescript with jsonwebtoken, joi, Knex, Obje
1616

1717
## Getting Started
1818

19-
Clone the repository, install the dependencies.
20-
2119
```bash
2220
# Clone repository
2321
$ git clone [email protected]:cham11ng/typescript-api-starter.git <application-name>
@@ -27,6 +25,9 @@ $ cd <application-name>
2725
# Update database credentials
2826
$ cp .env.example .env
2927

28+
# Install dependencies
29+
$ yarn install
30+
3031
$ yarn migrate
3132
```
3233

@@ -53,60 +54,54 @@ $ yarn dev
5354
<a href="https://imgur.com/gallery/4rhTo"><img src="https://i.imgur.com/GpcDbLB.gif" /></a>
5455
</p>
5556

56-
**Using Docker**
57-
58-
Make a copy of `.env.docker` and save as `.env`.
57+
### Using Docker
5958

6059
```bash
60+
# Make a copy of `.env.docker` and save as `.env`.
6161
$ cp .env.docker .env
6262
```
6363

6464
Install dependencies and run the application locally.
6565

6666
```bash
67-
$ docker compose up -d postgres
68-
6967
$ docker compose up -d api
7068

71-
$ docker compose exec api sh yarn migrate # Make sure server is started checking logs before running this command
69+
# Make sure server is started checking logs before running this command
70+
$ docker compose exec api sh yarn migrate
7271
```
7372

74-
View logs of the container.
75-
7673
```bash
77-
$ docker compose logs -f
78-
```
74+
# View logs of the container.
75+
$ docker compose logs -f api
7976

80-
To stop the services.
81-
82-
```bash
77+
# To stop the services.
8378
$ docker compose stop api postgres
8479
```
8580

8681
## Generating Migrations and Seeds
8782

88-
To create migration use `make:migration` and seed use `make:seeder`:
89-
9083
```bash
84+
# To create migration use `make:migration`
9185
$ yarn make:migration create_{table_name}_table
9286

87+
# To create seed use `make:seeder`
9388
$ yarn make:seeder {table_name}_table_seeder
9489
```
9590

96-
Example,
97-
9891
```bash
92+
# Example
9993
$ yarn make:migration create_posts_table
100-
10194
$ yarn make:seeder post_table_seeder
10295
```
10396

10497
Modify migration and seeder file as per the requirement. Then finally:
10598

10699
```bash
107-
$ yarn migrate # to migrate
100+
# to migrate
101+
$ yarn migrate
108102

109-
$ yarn seed # to seed
103+
# to seed
104+
$ yarn seed
110105
```
111106

112107
## Setting up REST Client
@@ -120,7 +115,7 @@ Create a file or add following lines in `.vscode` > `settings.json` and switch a
120115
"refreshToken": "foo",
121116
"accessToken": "bar",
122117
"email": "[email protected]",
123-
"password": "secret"
118+
"password": "secret"
124119
},
125120
"local": {
126121
"host": "localhost",

src/controllers/home.ts

+2-10
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,9 @@ import config from '../config/config';
55

66
const { name, version } = config;
77

8-
/**
9-
* Handle / GET request, responds API information.
10-
*
11-
* @param {Request} req
12-
* @param _
13-
* @param {Response} res
14-
* @returns {void}
15-
*/
16-
export function index(_: Request, res: Response): void {
8+
export const index = (_: Request, res: Response): void => {
179
res.status(StatusCodes.OK).json({
1810
name,
1911
version
2012
});
21-
}
13+
};

src/controllers/user.ts

+4-19
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,7 @@ import * as userService from '../services/userService';
77

88
const { messages } = config;
99

10-
/**
11-
* Handle /users GET request.
12-
*
13-
* @param {Request} req
14-
* @param _
15-
* @param {Response} res
16-
* @param {NextFunction} next
17-
*/
18-
export async function index(_: Request, res: Response, next: NextFunction): Promise<void> {
10+
export const index = async (_: Request, res: Response, next: NextFunction): Promise<void> => {
1911
try {
2012
const response = await userService.fetchAll();
2113

@@ -27,16 +19,9 @@ export async function index(_: Request, res: Response, next: NextFunction): Prom
2719
} catch (err) {
2820
next(err);
2921
}
30-
}
22+
};
3123

32-
/**
33-
* Handle /users POST request.
34-
*
35-
* @param {Request} req
36-
* @param {Response} res
37-
* @param {NextFunction} next
38-
*/
39-
export async function store(req: Request, res: Response, next: NextFunction): Promise<void> {
24+
export const store = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
4025
try {
4126
const userPayload = req.body as UserPayload;
4227

@@ -50,4 +35,4 @@ export async function store(req: Request, res: Response, next: NextFunction): Pr
5035
} catch (err) {
5136
next(err);
5237
}
53-
}
38+
};

src/database/migrations/20170517164638_create_user_roles_table.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import Table from '../../resources/enums/Table';
55
/**
66
* Add user_roles table.
77
*
8-
* @param {Knex} knex
8+
* @param {Knex} knex - knex instance.
9+
* @returns {Promise<void>}
910
*/
1011
export function up(knex: Knex): Promise<void> {
1112
return knex.schema
@@ -38,7 +39,8 @@ export function up(knex: Knex): Promise<void> {
3839
/**
3940
* Drop user_roles table.
4041
*
41-
* @param {Knex} knex
42+
* @param {Knex} knex - knex instance.
43+
* @returns {Knex.SchemaBuilder}
4244
*/
4345
export function down(knex: Knex): Knex.SchemaBuilder {
4446
return knex.schema.dropTable(Table.USER_ROLES);

src/database/migrations/20180130005620_create_users_table.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import { Knex } from 'knex';
33
import Table from '../../resources/enums/Table';
44

55
/**
6+
* Add users table.
67
*
7-
* @param knex
8+
* @param {Knex} knex - knex instance.
9+
* @returns {Knex.SchemaBuilder}
810
*/
911
export function up(knex: Knex): Knex.SchemaBuilder {
1012
return knex.schema.createTable(Table.USERS, (table) => {
@@ -19,8 +21,10 @@ export function up(knex: Knex): Knex.SchemaBuilder {
1921
}
2022

2123
/**
24+
* Drop users table.
2225
*
23-
* @param knex
26+
* @param {Knex} knex - knex instance.
27+
* @returns {Knex.SchemaBuilder}
2428
*/
2529
export function down(knex: Knex): Knex.SchemaBuilder {
2630
return knex.schema.dropTable(Table.USERS);

src/database/migrations/20180517164647_create_user_sessions_table.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import { Knex } from 'knex';
33
import Table from '../../resources/enums/Table';
44

55
/**
6+
* Add user_sessions table.
67
*
7-
* @param knex
8+
* @param knex - knex instance.
9+
* @returns {Knex.SchemaBuilder}
810
*/
911
export function up(knex: Knex): Knex.SchemaBuilder {
1012
return knex.schema.createTable(Table.USER_SESSIONS, (table) => {
@@ -19,8 +21,10 @@ export function up(knex: Knex): Knex.SchemaBuilder {
1921
}
2022

2123
/**
24+
* Drop user_sessions table.
2225
*
23-
* @param knex
26+
* @param knex - knex instance.
27+
* @returns {Knex.SchemaBuilder}
2428
*/
2529
export function down(knex: Knex): Knex.SchemaBuilder {
2630
return knex.schema.dropTable(Table.USER_SESSIONS);

src/database/seeds/user_table_seeder.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import Table from '../../resources/enums/Table';
55
import * as bcrypt from '../../utils/bcrypt';
66

77
/**
8+
* Seed users table.
89
*
9-
* @param knex
10+
* @param {Knex} knex - knex instance.
11+
* @returns {Promise<number[] | number[][]>}
1012
*/
11-
export function seed(knex: Knex): Promise<any> {
13+
export function seed(knex: Knex): Promise<number[] | number[][]> {
1214
return knex(Table.USERS).then(async () => {
1315
return Promise.all([
1416
knex(Table.USERS).insert([

src/domain/misc/ResponseData.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import JWTPayload from './JWTPayload';
2+
3+
type ResponseData = Request & { data: JWTPayload };
4+
5+
export default ResponseData;

src/middlewares/authenticate.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { NextFunction, Request, Response } from 'express';
22
import { JsonWebTokenError } from 'jsonwebtoken';
33

44
import config from '../config/config';
5+
import ResponseData from '../domain/misc/ResponseData';
56
import BadRequestError from '../exceptions/BadRequestError';
67
import UnauthorizedError from '../exceptions/UnauthorizedError';
78
import { tokenErrorMessageMap } from '../resources/constants/maps';
@@ -20,7 +21,7 @@ const authenticate = async (req: Request, res: Response, next: NextFunction): Pr
2021
}
2122

2223
logger.log('info', 'JWT: Verifying token - %s', res.locals.accessToken);
23-
const response: any = jwt.verifyAccessToken(res.locals.accessToken);
24+
const response = jwt.verifyAccessToken(res.locals.accessToken) as ResponseData;
2425

2526
res.locals.loggedInPayload = response.data;
2627

src/middlewares/genericErrorHandler.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import { getReasonPhrase, StatusCodes } from 'http-status-codes';
44
import APIResponseInterface from '../domain/responses/APIResponse';
55
import logger from '../utils/logger';
66

7+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
78
export const buildError = (err: any): APIResponseInterface<{ code: number; message: string; data?: any }> => {
89
if (err.isJoi) {
910
return {
1011
code: StatusCodes.BAD_REQUEST,
1112
message: getReasonPhrase(StatusCodes.BAD_REQUEST),
1213
data:
1314
err.details &&
15+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1416
err.details.map((error: any) => ({
1517
param: error.path.join('.'),
1618
message: error.message
@@ -39,10 +41,10 @@ export const buildError = (err: any): APIResponseInterface<{ code: number; messa
3941
};
4042

4143
const genericErrorHandler = (
44+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
4245
err: any,
4346
_: Request,
4447
res: Response,
45-
// TODO: Remove this.
4648
// eslint-disable-next-line @typescript-eslint/no-unused-vars
4749
__: NextFunction
4850
): void => {

src/middlewares/rateLimitHandler.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { rateLimit } from 'express-rate-limit';
22

3-
// write express rateLimit best practices
43
const rateLimitMiddleware = rateLimit({
54
windowMs: 15 * 60 * 1000, // 15 minutes
65
max: 100, // limit each IP to 100 requests per windowMs
76
message: 'Too many requests from this IP, please try again after 15 minutes',
8-
headers: true
7+
headers: true,
8+
legacyHeaders: false,
9+
standardHeaders: true
910
});
1011

1112
export default rateLimitMiddleware;

src/middlewares/transactionHandler.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const transactionHandler = (req: Request, _: Response, next: NextFunction): void
1010
const transactionId = req.headers['transactionId'] || randomUUID();
1111

1212
// Set the TransactionId inside the store
13-
context.getStore().set('transactionId', transactionId);
13+
context.getStore()?.set('transactionId', transactionId);
1414

1515
next();
1616
});

src/middlewares/validateRefreshToken.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { NextFunction, Request, Response } from 'express';
22

33
import config from '../config/config';
4+
import ResponseData from '../domain/misc/ResponseData';
45
import BadRequestError from '../exceptions/BadRequestError';
56
import UnauthorizedError from '../exceptions/UnauthorizedError';
67
import { tokenErrorMessageMap } from '../resources/constants/maps';
@@ -19,13 +20,14 @@ const validateRefreshToken = async (req: Request, res: Response, next: NextFunct
1920
}
2021

2122
logger.log('info', 'JWT: Verifying token - %s', res.locals.refreshToken);
22-
const response: any = jwt.verifyRefreshToken(res.locals.refreshToken);
23+
const response = jwt.verifyRefreshToken(res.locals.refreshToken) as ResponseData;
2324

2425
res.locals.jwtPayload = response.data;
2526

2627
logger.log('debug', 'JWT: Authentication verified -', res.locals.jwtPayload);
2728

2829
next();
30+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2931
} catch (err: any) {
3032
const tokenErrorMessage = tokenErrorMessageMap[err.name as JWTErrorType];
3133
logger.log('error', 'JWT: Authentication failed - %s', err.message);

src/resources/stubs/migration.stub

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import * as Knex from 'knex';
22

3+
/**
4+
* Add :table table.
5+
*
6+
* @param {Knex} knex - knex instance.
7+
* @returns {Promise<Knex.SchemaBuilder>}
8+
*/
39
export function up(knex: Knex): Knex.SchemaBuilder {
410
return knex.schema.createTable('table_name', (table) => {
511
table.increments('id').primary();
@@ -8,6 +14,12 @@ export function up(knex: Knex): Knex.SchemaBuilder {
814
});
915
}
1016

17+
/**
18+
* Drop :table table.
19+
*
20+
* @param {Knex} knex - knex instance.
21+
* @returns {Knex.SchemaBuilder}
22+
*/
1123
export function down(knex: Knex): Knex.SchemaBuilder {
1224
return knex.schema.dropTable('table_name');
1325
}

src/resources/stubs/seed.stub

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import * as Knex from 'knex';
22

3-
export function seed(knex: Knex): Knex.SchemaBuilder {
3+
/**
4+
* Seed :table table
5+
6+
* @param {Knex} knex - knex instance.
7+
* @returns {Promise<number[] | number[][]>}
8+
*/
9+
export function seed(knex: Knex): Promise<number[] | number[][]> {
410
return knex('table_name')
511
.del()
612
.then(() => {

0 commit comments

Comments
 (0)