Skip to content

Commit 0e67988

Browse files
author
Anmol Gangwar
committed
refactor(infra): 🔨 revamped infra removed mongodb, supabase, redis
1 parent 3620011 commit 0e67988

File tree

40 files changed

+543
-913
lines changed

40 files changed

+543
-913
lines changed

.env.example

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

bun.lockb

-11.8 KB
Binary file not shown.

package.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,12 @@
5050
"dependencies": {
5151
"@hono/node-server": "^1.12.1",
5252
"@hono/zod-openapi": "^0.15.3",
53-
"@scalar/hono-api-reference": "^0.5.142",
54-
"@supabase/supabase-js": "^2.45.2",
53+
"@scalar/hono-api-reference": "^0.9.5",
5554
"@typescript-eslint/eslint-plugin": "^8.2.0",
5655
"axios": "^1.7.5",
5756
"form-data": "^4.0.0",
57+
"fuse.js": "^7.1.0",
5858
"hono": "^4.5.8",
59-
"ioredis": "^5.4.1",
60-
"jsonwebtoken": "^9.0.2",
61-
"mongoose": "^8.5.3",
62-
"otplib": "^12.0.1",
6359
"zod": "^3.23.8"
6460
},
6561
"devDependencies": {

src/app.ts

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { OpenAPIHono } from '@hono/zod-openapi'
2-
import { apiReference } from '@scalar/hono-api-reference'
2+
import { Scalar } from '@scalar/hono-api-reference'
33
import { logger } from 'hono/logger'
44
import { prettyJSON } from 'hono/pretty-json'
55
import { Home } from './pages/home'
66
import { Routes } from '#common/types'
77
import type { HTTPException } from 'hono/http-exception'
88
import { cors } from 'hono/cors'
9-
import { authMiddleware } from './middleware/auth'
109
export class App {
1110
private app: OpenAPIHono
1211
constructor(routes: Routes[]) {
@@ -35,16 +34,6 @@ export class App {
3534
}
3635

3736
private initializeGlobalMiddleware() {
38-
this.app.use(async (c, next) => {
39-
try {
40-
await next()
41-
} catch (error) {
42-
console.error('Database connection error:', error)
43-
return c.json({ error: 'Internal Server Error' }, 500)
44-
} finally {
45-
// await this.dalService.cleanup()
46-
}
47-
})
4837
this.app.use(
4938
cors({
5039
origin: '*',
@@ -61,7 +50,7 @@ export class App {
6150
c.res.headers.set('X-Response-Time', `${end - start}ms`)
6251
})
6352

64-
this.app.use(authMiddleware)
53+
// this.app.use(authMiddleware)
6554
}
6655

6756
private initializeSwaggerUI() {
@@ -90,12 +79,14 @@ export class App {
9079

9180
this.app.get(
9281
'/docs',
93-
apiReference({
82+
Scalar({
9483
pageTitle: 'ExerciseDB API Documentation',
9584
theme: 'bluePlanet',
9685
isEditable: false,
9786
layout: 'modern',
9887
darkMode: true,
88+
url: '/swagger',
89+
favicon: 'https://cdn.exercisedb.dev/exercisedb/favicon.ico',
9990
metaData: {
10091
applicationName: 'ExerciseDB API',
10192
author: 'ExerciseDB API',
@@ -104,10 +95,6 @@ export class App {
10495
robots: 'index follow',
10596
description:
10697
'Access detailed data on over 1300+ exercises with the ExerciseDB API. This API offers extensive information on each exercise, including target body parts, equipment needed, GIFs for visual guidance, and step-by-step instructions.'
107-
},
108-
109-
spec: {
110-
url: '/swagger'
11198
}
11299
})
113100
)
@@ -118,7 +105,7 @@ export class App {
118105
return c.json(
119106
{
120107
success: false,
121-
message: 'oops route not found!!. check docs at https://v1.exercisedb.dev/docs'
108+
message: 'route not found!!. check docs at https://v1.exercisedb.dev/docs'
122109
},
123110
404
124111
)

src/common/helpers/crypto.service.ts

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

src/data/exercises.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"name": "band shrug",
55
"gifUrl": "https://v1.cdn.exercisedb.dev/media/trmte8s.gif",
66
"targetMuscles": ["traps"],
7-
"bodyParts": ["back"],
7+
"bodyParts": ["neck"],
88
"equipments": ["band"],
99
"secondaryMuscles": ["shoulders"],
1010
"instructions": [

src/data/load.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { promises as fs } from 'fs'
2+
import path from 'path'
3+
import { Equipment, Exercise, Muscle, BodyPart } from './types'
4+
import { HTTPException } from 'hono/http-exception'
5+
6+
export class FileLoader {
7+
private static dataPath = path.resolve(process.cwd(), 'src', 'data')
8+
9+
private static cache = new Map<string, unknown>()
10+
11+
private static async loadJSON<T>(filename: string): Promise<T> {
12+
const filePath = path.resolve(this.dataPath, filename)
13+
14+
if (this.cache.has(filePath)) {
15+
return this.cache.get(filePath) as T
16+
}
17+
18+
try {
19+
const fileContent = await fs.readFile(filePath, 'utf-8')
20+
const data = JSON.parse(fileContent) as T
21+
this.cache.set(filePath, data)
22+
return data
23+
} catch (error) {
24+
console.error(`❌ Error loading JSON file [${filename}]:`, error)
25+
throw new HTTPException(500, { message: `database not working` })
26+
}
27+
}
28+
29+
public static loadExercises(): Promise<Exercise[]> {
30+
return this.loadJSON<Exercise[]>(`exercises.json`)
31+
}
32+
33+
public static loadEquipments(): Promise<Equipment[]> {
34+
return this.loadJSON<Equipment[]>('equipments.json')
35+
}
36+
37+
public static loadBodyParts(): Promise<BodyPart[]> {
38+
return this.loadJSON<BodyPart[]>('bodyparts.json')
39+
}
40+
41+
public static loadMuscles(): Promise<Muscle[]> {
42+
return this.loadJSON<Muscle[]>('muscles.json')
43+
}
44+
}

src/data/types.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export interface Equipment {
2+
name: string
3+
}
4+
5+
export interface Exercise {
6+
exerciseId: string
7+
name: string
8+
gifUrl: string
9+
equipments: string[]
10+
bodyParts: string[]
11+
targetMuscles: string[]
12+
secondaryMuscles: string[]
13+
instructions: string[]
14+
}
15+
16+
export interface BodyPart {
17+
name: string
18+
}
19+
20+
export interface Muscle {
21+
name: string
22+
}

src/middleware/auth/index.ts

Lines changed: 64 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,79 @@
1-
import { CryptoService } from '#common/helpers/crypto.service.js'
2-
import { Context, Next } from 'hono'
1+
// import { Context, Next } from 'hono'
32

4-
type Role = 'member' | 'moderator' | 'admin'
3+
// type Role = 'member' | 'moderator' | 'admin'
54

6-
const ROLE_PERMISSIONS: Record<Role, Set<string>> = {
7-
member: new Set(['GET']),
8-
moderator: new Set(['GET', 'POST', 'PUT', 'PATCH']),
9-
admin: new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE'])
10-
}
5+
// const ROLE_PERMISSIONS: Record<Role, Set<string>> = {
6+
// member: new Set(['GET']),
7+
// moderator: new Set(['GET', 'POST', 'PUT', 'PATCH']),
8+
// admin: new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE'])
9+
// }
1110

12-
const RESTRICTED_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])
13-
const VALID_ROLES = new Set(['member', 'moderator', 'admin'])
11+
// const RESTRICTED_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])
12+
// const VALID_ROLES = new Set(['member', 'moderator', 'admin'])
1413

15-
const cryptoService = new CryptoService()
1614

17-
interface RouteConfig {
18-
path: string
19-
allowedEnvs: Set<string>
20-
skipAuth?: boolean
21-
message?: string
22-
}
15+
// interface RouteConfig {
16+
// path: string
17+
// allowedEnvs: Set<string>
18+
// skipAuth?: boolean
19+
// message?: string
20+
// }
2321

24-
const ROUTE_CONFIG: RouteConfig[] = [
25-
{
26-
path: '/api/v1/register',
27-
allowedEnvs: new Set(['development', 'staging']),
28-
skipAuth: true,
29-
message: 'signup is not allowed in production'
30-
},
31-
{ path: '/api/v1/authenticate', allowedEnvs: new Set(['development', 'staging', 'production']), skipAuth: true }
32-
]
22+
// const ROUTE_CONFIG: RouteConfig[] = [
23+
// {
24+
// path: '/api/v1/register',
25+
// allowedEnvs: new Set(['development', 'staging']),
26+
// skipAuth: true,
27+
// message: 'signup is not allowed in production'
28+
// },
29+
// { path: '/api/v1/authenticate', allowedEnvs: new Set(['development', 'staging', 'production']), skipAuth: true }
30+
// ]
3331

34-
export async function authMiddleware(c: Context, next: Next) {
35-
const { method, path } = c.req
36-
const currentEnv = process.env.NODE_ENV || 'development'
32+
// export async function authMiddleware(c: Context, next: Next) {
33+
// const { method, path } = c.req
34+
// const currentEnv = process.env.NODE_ENV || 'development'
3735

38-
const routeConfig = ROUTE_CONFIG.find((route) => route.path === path)
36+
// const routeConfig = ROUTE_CONFIG.find((route) => route.path === path)
3937

40-
if (routeConfig) {
41-
if (!routeConfig.allowedEnvs.has(currentEnv)) {
42-
return c.json(
43-
{
44-
success: false,
45-
error: routeConfig.message
46-
? routeConfig.message
47-
: `This route is not available in the ${currentEnv} environment.`
48-
},
49-
403
50-
)
51-
}
52-
if (routeConfig.skipAuth) {
53-
return next()
54-
}
55-
}
38+
// if (routeConfig) {
39+
// if (!routeConfig.allowedEnvs.has(currentEnv)) {
40+
// return c.json(
41+
// {
42+
// success: false,
43+
// error: routeConfig.message
44+
// ? routeConfig.message
45+
// : `This route is not available in the ${currentEnv} environment.`
46+
// },
47+
// 403
48+
// )
49+
// }
50+
// if (routeConfig.skipAuth) {
51+
// return next()
52+
// }
53+
// }
5654

57-
if (!RESTRICTED_METHODS.has(method)) return next()
55+
// if (!RESTRICTED_METHODS.has(method)) return next()
5856

59-
const authorization = c.req.header('Authorization')
57+
// const authorization = c.req.header('Authorization')
6058

61-
if (!authorization) {
62-
return c.json({ success: false, error: 'No authorization header | unauthorized request' }, 401)
63-
}
64-
const token = authorization.split(' ')[1]
59+
// if (!authorization) {
60+
// return c.json({ success: false, error: 'No authorization header | unauthorized request' }, 401)
61+
// }
62+
// const token = authorization.split(' ')[1]
6563

66-
if (!authorization.startsWith('Bearer')) {
67-
return c.json({ success: false, error: 'Invalid authorization header format. Format is "Bearer <token>".' }, 401)
68-
}
64+
// if (!authorization.startsWith('Bearer')) {
65+
// return c.json({ success: false, error: 'Invalid authorization header format. Format is "Bearer <token>".' }, 401)
66+
// }
6967

70-
try {
71-
const userPayload = cryptoService.verifyAccessToken(token)
72-
if (!VALID_ROLES.has(userPayload.role) || !ROLE_PERMISSIONS[userPayload.role as Role].has(method)) {
73-
return c.json({ success: false, error: 'Forbidden' }, 403)
74-
}
68+
// try {
69+
// if (!VALID_ROLES.has(userPayload.role) || !ROLE_PERMISSIONS[userPayload.role as Role].has(method)) {
70+
// return c.json({ success: false, error: 'Forbidden' }, 403)
71+
// }
7572

76-
c.set('user', userPayload)
77-
await next()
78-
} catch (error) {
79-
console.error(error)
80-
return c.json({ success: false, error: 'Invalid token' }, 401)
81-
}
82-
}
73+
// c.set('user', userPayload)
74+
// await next()
75+
// } catch (error) {
76+
// console.error(error)
77+
// return c.json({ success: false, error: 'Invalid token' }, 401)
78+
// }
79+
// }

0 commit comments

Comments
 (0)