Skip to content

Commit

Permalink
feat(muscles): added route endpoint to get exercises by specific muscle
Browse files Browse the repository at this point in the history
  • Loading branch information
cyberboyanmol committed Aug 26, 2024
1 parent d5786f2 commit b3c8a9c
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export class App {
description:
'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.'
},

spec: {
url: '/swagger'
}
Expand Down
9 changes: 7 additions & 2 deletions src/modules/images/controllers/image.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,19 @@ export class ImagesController implements Routes {
}
}),
async (ctx) => {
const { origin, pathname } = new URL(ctx.req.url)
const body = await ctx.req.parseBody()
const file = body['file'] as File
if (!file || file.type !== 'image/gif') {
return ctx.json({ success: false, error: 'Invalid file type. Only GIF files are allowed.' }, 400)
}

const uploadResult = await this.imageService.uploadImage(file)
return ctx.json({ success: true, data: uploadResult })
const { publicUrl } = await this.imageService.uploadImage(file)

return ctx.json({
success: true,
data: { publicUrl: `${origin}/api/v1/Images/${publicUrl.split('/').slice(-1)}` }
})
}
)
this.controller.openapi(
Expand Down
87 changes: 86 additions & 1 deletion src/modules/muscles/controllers/muscle.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { MuscleModel } from '../models/muscle.model'
import { MuscleService } from '../services'
import Muscle from '#infra/mongodb/models/muscles/muscle.schema.js'
import { HTTPException } from 'hono/http-exception'
import Exercise from '#infra/mongodb/models/exercises/exercise.schema.js'
import { ExerciseModel } from '#modules/exercises/models/exercise.model.js'

export class MuscleController implements Routes {
public controller: OpenAPIHono
private readonly muscleService: MuscleService
constructor() {
this.controller = new OpenAPIHono()
this.muscleService = new MuscleService(Muscle)
this.muscleService = new MuscleService(Muscle, Exercise)
}

public initRoutes() {
Expand Down Expand Up @@ -129,5 +131,88 @@ export class MuscleController implements Routes {
return ctx.json({ success: true, data: response })
}
)

this.controller.openapi(
createRoute({
method: 'get',
path: '/muscles/{muscleName}/exercises',
tags: ['Muscles'],
summary: 'Retrive exercises by muscles',
description: 'Retrive list of exercises by targetMuscles or secondaryMuscles.',
operationId: 'getExercisesByEquipment',
request: {
params: z.object({
muscleName: z.string().openapi({
description: 'muscles name',
type: 'string',
example: 'upper back',
default: 'upper back'
})
}),
query: z.object({
offset: z.coerce.number().nonnegative().optional().openapi({
title: 'Offset',
description:
'The number of exercises to skip from the start of the list. Useful for pagination to fetch subsequent pages of results.',
type: 'number',
example: 10,
default: 0
}),
limit: z.coerce.number().positive().max(100).optional().openapi({
title: 'Limit',
description:
'The maximum number of exercises to return in the response. Limits the number of results for pagination purposes.',
maximum: 100,
minimum: 1,
type: 'number',
example: 10,
default: 10
})
})
},
responses: {
200: {
description: 'Successful response with list of all exercises.',
content: {
'application/json': {
schema: z.object({
success: z.boolean().openapi({
description: 'Indicates whether the request was successful',
type: 'boolean',
example: true
}),
data: z.array(ExerciseModel).openapi({
description: 'Array of Exercises.'
})
})
}
}
},
500: {
description: 'Internal server error'
}
}
}),
async (ctx) => {
const { offset, limit = 10 } = ctx.req.valid('query')
const search = ctx.req.param('muscleName')
const { origin, pathname } = new URL(ctx.req.url)
const response = await this.muscleService.getExercisesByMuscles({ offset, limit, search })
return ctx.json({
success: true,
data: {
previousPage:
response.currentPage > 1
? `${origin}${pathname}?offset=${(response.currentPage - 1) * limit}&limit=${limit}`
: null,
nextPage:
response.currentPage < response.totalPages
? `${origin}${pathname}?offset=${response.currentPage * limit}&limit=${limit}`
: null,
...response
}
})
}
)
}
}
26 changes: 25 additions & 1 deletion src/modules/muscles/services/muscle.service.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { IExerciseModel } from '#infra/mongodb/models/exercises/exercise.entity.js'
import { IMuscleModel } from '#infra/mongodb/models/muscles/muscle.entity.js'
import { GetExerciseSerivceArgs } from '#modules/exercises/services/exercise.service.js'
import {
GetExercisesArgs,
GetExercisesUseCase
} from '#modules/exercises/use-cases/get-exercises/get-exercise.usecase.js'
import { CreateMuscleArgs, CreateMuscleUseCase } from '../use-cases/create-muscle'
import { GetMusclesUseCase } from '../use-cases/get-muscles'

export class MuscleService {
private readonly createMuscleUseCase: CreateMuscleUseCase
private readonly getMuscleUseCase: GetMusclesUseCase
private readonly getExercisesUseCase: GetExercisesUseCase

constructor(private readonly muscleModel: IMuscleModel) {
constructor(
private readonly muscleModel: IMuscleModel,
private readonly exerciseModel: IExerciseModel
) {
this.createMuscleUseCase = new CreateMuscleUseCase(muscleModel)
this.getMuscleUseCase = new GetMusclesUseCase(muscleModel)
this.getExercisesUseCase = new GetExercisesUseCase(exerciseModel)
}

createMuscle = (args: CreateMuscleArgs) => {
Expand All @@ -18,4 +29,17 @@ export class MuscleService {
getMuscles = () => {
return this.getMuscleUseCase.execute()
}
getExercisesByMuscles = (params: GetExerciseSerivceArgs) => {
const query: GetExercisesArgs = {
offset: params.offset,
limit: params.limit,
query: {
targetMuscles: {
$all: [params.search]
}
}
}

return this.getExercisesUseCase.execute(query)
}
}

0 comments on commit b3c8a9c

Please sign in to comment.