Skip to content

Commit b3fa32a

Browse files
committed
feat(exercise): added endpoint to get exercise by exerciseid
1 parent 4b6e0b2 commit b3fa32a

File tree

5 files changed

+81
-1
lines changed

5 files changed

+81
-1
lines changed

src/middleware/auth/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ const ROUTE_CONFIG: RouteConfig[] = [
2929
message: 'signup is not allowed in production'
3030
},
3131
{ path: '/api/v1/authenticate', allowedEnvs: new Set(['development', 'staging', 'production']), skipAuth: true }
32-
// Add more routes as needed
3332
]
3433

3534
export async function authMiddleware(c: Context, next: Next) {

src/modules/exercises/controllers/exercise.controller.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { z } from 'zod'
44
import { ExerciseService } from '../services/exercise.service'
55
import Exercise from '#infra/mongodb/models/exercises/exercise.schema.js'
66
import { ExerciseModel } from '../models/exercise.model'
7+
import { HTTPException } from 'hono/http-exception'
78

89
export class ExerciseController implements Routes {
910
public controller: OpenAPIHono
@@ -280,5 +281,65 @@ export class ExerciseController implements Routes {
280281
})
281282
}
282283
)
284+
285+
this.controller.openapi(
286+
createRoute({
287+
method: 'get',
288+
path: '/exercises/{exerciseId}',
289+
tags: ['Exercises'],
290+
summary: 'Get exercise by ID',
291+
description: 'Retrieves a specific exercise by its unique identifier.',
292+
operationId: 'getExerciseById',
293+
request: {
294+
params: z.object({
295+
exerciseId: z.string().openapi({
296+
title: 'Exercise ID',
297+
description: 'The unique identifier of the exercise to retrieve.',
298+
type: 'string',
299+
example: 'ztAa1RK',
300+
default: 'ztAa1RK'
301+
})
302+
})
303+
},
304+
responses: {
305+
200: {
306+
description: 'Successful response with the exercise details.',
307+
content: {
308+
'application/json': {
309+
schema: z.object({
310+
success: z.boolean().openapi({
311+
description: 'Indicates whether the request was successful.',
312+
type: 'boolean',
313+
example: true
314+
}),
315+
data: ExerciseModel.openapi({
316+
description: 'The retrieved exercise details.'
317+
})
318+
})
319+
}
320+
}
321+
},
322+
404: {
323+
description: 'Exercise not found'
324+
},
325+
500: {
326+
description: 'Internal server error'
327+
}
328+
}
329+
}),
330+
async (ctx) => {
331+
const exerciseId = ctx.req.param('exerciseId')
332+
const exercise = await this.exerciseService.getExerciseById(exerciseId)
333+
334+
if (!exercise) {
335+
throw new HTTPException(404, { message: 'Exercise not found' })
336+
}
337+
338+
return ctx.json({
339+
success: true,
340+
data: exercise
341+
})
342+
}
343+
)
283344
}
284345
}

src/modules/exercises/services/exercise.service.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
GetAutoCompleteSuggestionsArgs,
55
GetAutoCompleteSuggestionsUseCase
66
} from '../use-cases/get-autocomplete-suggestions'
7+
import { GetExerciseByIdUseCase } from '../use-cases/get-exercises-by-id'
78
import { GetExercisesArgs, GetExercisesUseCase } from '../use-cases/get-exercises/get-exercise.usecase'
89

910
export interface GetExerciseSerivceArgs {
@@ -15,10 +16,12 @@ export class ExerciseService {
1516
private readonly createExerciseUseCase: CreateExerciseUseCase
1617
private readonly getExercisesUseCase: GetExercisesUseCase
1718
private readonly getAutoCompleteSuggestionsUseCase: GetAutoCompleteSuggestionsUseCase
19+
private readonly getExerciseByIdUseCase: GetExerciseByIdUseCase
1820
constructor(private readonly exerciseModel: IExerciseModel) {
1921
this.createExerciseUseCase = new CreateExerciseUseCase(exerciseModel)
2022
this.getExercisesUseCase = new GetExercisesUseCase(exerciseModel)
2123
this.getAutoCompleteSuggestionsUseCase = new GetAutoCompleteSuggestionsUseCase(exerciseModel)
24+
this.getExerciseByIdUseCase = new GetExerciseByIdUseCase(exerciseModel)
2225
}
2326

2427
createExercise = (params: CreateExerciseArgs) => {
@@ -35,4 +38,8 @@ export class ExerciseService {
3538
getAutoCompleteSuggestions = (params: GetAutoCompleteSuggestionsArgs) => {
3639
return this.getAutoCompleteSuggestionsUseCase.execute(params)
3740
}
41+
42+
getExerciseById = (exerciseId: string) => {
43+
return this.getExerciseByIdUseCase.execute(exerciseId)
44+
}
3845
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { IUseCase } from '#common/types/use-case.type.js'
2+
import { IExerciseDoc, IExerciseModel } from '#infra/mongodb/models/exercises/exercise.entity.js'
3+
4+
export class GetExerciseByIdUseCase implements IUseCase<string, IExerciseDoc | null> {
5+
constructor(private readonly exerciseModel: IExerciseModel) {}
6+
7+
async execute(exerciseId: string): Promise<IExerciseDoc | null> {
8+
return this.exerciseModel.findOne({
9+
exerciseId
10+
})
11+
}
12+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './get-exercise-by-id.usecase'

0 commit comments

Comments
 (0)