Skip to content

Commit

Permalink
Add responseMiddleware
Browse files Browse the repository at this point in the history
  • Loading branch information
likui628 committed Oct 3, 2024
1 parent cf90f7e commit 8e2e4b2
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 24 deletions.
9 changes: 8 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import passport from 'passport'
import cookieParser from 'cookie-parser'

import routes from './routes/v1'
import { rateLimiter, errorHandler, notFound } from './middlewares'
import {
rateLimiter,
errorHandler,
notFound,
responseMiddleware,
} from './middlewares'
import { jwtStrategy } from './config/passport'
import morgan from './config/morgan'

Expand All @@ -25,6 +30,8 @@ app.use(cors())
app.use(cookieParser())
app.use(express.json())

app.use(responseMiddleware)

if (process.env.NODE_ENV === 'production') {
app.use('/v1/auth', rateLimiter)
app.use('/v1/users', rateLimiter)
Expand Down
23 changes: 12 additions & 11 deletions src/controllers/auth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Request, Response } from 'express'
import { asyncHandler, errorResponse, successResponse } from '../utils'
import { asyncHandler } from '../utils'
import { userService, authService, tokenService } from '../services'
import { User } from '@prisma/client'
import { UserData } from '../types'

async function handleTokens(user: User, res: Response) {
const { token, refreshToken } = await tokenService.generateAuthTokens(user)
Expand All @@ -18,21 +19,21 @@ export const register = asyncHandler(async (req: Request, res: Response) => {
const user = await userService.createUser(req.body)
const token = await handleTokens(user, res)

successResponse(res, { ...user, token }, 201)
res.jsonSuccess<UserData>({ ...user, token }, 201)
})

export const login = asyncHandler(async (req: Request, res: Response) => {
const { email, password } = req.body
const user = await authService.loginUserWithEmailAndPassword(email, password)
const token = await handleTokens(user, res)

successResponse(res, { ...user, token }, 200)
res.jsonSuccess<UserData>({ ...user, token }, 200)
})

export const logout = asyncHandler(async (req: Request, res: Response) => {
const cookies = req.cookies
if (!cookies?.refreshToken) {
return successResponse(res, null, 200)
res.jsonSuccess(undefined, 200)
}
const refreshToken = cookies.refreshToken as string

Expand All @@ -42,21 +43,21 @@ export const logout = asyncHandler(async (req: Request, res: Response) => {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
})
return successResponse(res, null, 200)
res.jsonSuccess(undefined, 200)
}

await tokenService.deleteToken(refreshToken)
res.clearCookie('refreshToken', {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
})
return successResponse(res, null, 200)
res.jsonSuccess(undefined, 200)
})

export const refresh = asyncHandler(async (req: Request, res: Response) => {
const cookies = req.cookies
if (!cookies?.refreshToken) {
return errorResponse(res, null, 401, 'Unauthorized')
res.jsonFail(401, 'Unauthorized')
}
const refreshToken = cookies.refreshToken as string
res.clearCookie('refreshToken', {
Expand All @@ -66,14 +67,14 @@ export const refresh = asyncHandler(async (req: Request, res: Response) => {

const tokenInfo = await tokenService.verifyToken(refreshToken)
if (!tokenInfo) {
return errorResponse(res, null, 401, 'Unauthorized')
res.jsonFail(401, 'Unauthorized')
}

const user = await userService.getUserById(tokenInfo.userId)
if (!user) {
return errorResponse(res, null, 401, 'Unauthorized')
res.jsonFail(401, 'Unauthorized')
}

const token = await handleTokens(user, res)
successResponse(res, { token }, 200)
const token = await handleTokens(user!, res)
res.jsonSuccess<string>(token, 200)
})
18 changes: 18 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,21 @@ const port = env.PORT || 5000
app.listen(port, () => {
logger.info(`Listening to port ${port}`)
})

import { Role, User } from '@prisma/client'

declare module 'express-serve-static-core' {
interface CustomUser extends Express.User {
id?: User['id']
username?: User['name']
role?: Role
}
interface Request {
user?: CustomUser
}

interface Response {
jsonSuccess: <T>(data: T, statusCode?: number, message?: string) => void
jsonFail: (code: number, message?: string) => void
}
}
1 change: 1 addition & 0 deletions src/middlewares/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './validate'
export * from './verify-jwt'
export * from './verify-roles'
export * from './rate-limiter'
export * from './response'
26 changes: 26 additions & 0 deletions src/middlewares/response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NextFunction, Request, Response } from 'express'

export const responseMiddleware = (
_req: Request,
res: Response,
next: NextFunction,
) => {
res.jsonSuccess = <T>(data: T, code = 200, message = 'Success'): void => {
res.status(code)
res.json({
code,
message,
data,
})
}

res.jsonFail = (code, message = 'Fail'): void => {
res.status(code)
res.json({
code,
message,
})
}

next()
}
10 changes: 0 additions & 10 deletions src/middlewares/verify-roles.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
import { NextFunction, Request, Response } from 'express'
import { Role } from '@prisma/client'
import { errorResponse } from '../utils'
import { roleRights } from '../config/roles'

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Express {
interface User {
role?: Role
}
}
}

export const verifyRoles = (...requiredRights: string[]) => {
return (req: Request, res: Response, next: NextFunction) => {
if (requiredRights.length) {
Expand Down
6 changes: 5 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Role } from '@prisma/client'
import { Role, User } from '@prisma/client'

export interface Pagination {
orderBy?: 'name' | 'email' | 'createdAt' | 'updatedAt'
Expand All @@ -11,3 +11,7 @@ export interface QueryUsers extends Pagination {
name?: string
role?: Role
}

export interface UserData extends User {
token: string
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
"include": [
"./*.js",
"src/**/*.ts",
"test/**/*.ts",
"test/**/*.ts"
],
}

0 comments on commit 8e2e4b2

Please sign in to comment.