diff --git a/src/services/api/leaderboard-api.service.ts b/src/services/api/leaderboard-api.service.ts index bfab5256..191946b8 100644 --- a/src/services/api/leaderboard-api.service.ts +++ b/src/services/api/leaderboard-api.service.ts @@ -1,4 +1,4 @@ -import { HasPermission, Routes, Request, Response, Validate, ForwardTo, forwardRequest, Docs } from 'koa-clay' +import { HasPermission, Routes, Request, Response, Validate, ForwardTo, forwardRequest, Docs, ValidationCondition } from 'koa-clay' import LeaderboardAPIPolicy from '../../policies/api/leaderboard-api.policy' import APIService from './api-service' import { EntityManager } from '@mikro-orm/mysql' @@ -53,7 +53,19 @@ export default class LeaderboardAPIService extends APIService { @Validate({ headers: ['x-talo-alias'], - body: ['score'] + body: { + score: { + required: true + }, + props: { + validation: async (val: unknown): Promise => [ + { + check: val ? Array.isArray(val) : true, + error: 'Props must be an array' + } + ] + } + } }) @HasPermission(LeaderboardAPIPolicy, 'post') @Docs(LeaderboardAPIDocs.post) @@ -61,10 +73,6 @@ export default class LeaderboardAPIService extends APIService { const { score, props } = req.body const em: EntityManager = req.ctx.em - if (props && !Array.isArray(props)) { - req.ctx.throw(400, 'Props must be an array') - } - const leaderboard: Leaderboard = req.ctx.state.leaderboard let entry: LeaderboardEntry = null diff --git a/tests/services/_api/leaderboard-api/post.test.ts b/tests/services/_api/leaderboard-api/post.test.ts index c2ba5184..bff28eb9 100644 --- a/tests/services/_api/leaderboard-api/post.test.ts +++ b/tests/services/_api/leaderboard-api/post.test.ts @@ -330,4 +330,30 @@ describe('Leaderboard API service - post', () => { { key: 'key1', value: 'value1' } ]) }) + + it('should return a 400 if props are not an array', async () => { + const [apiKey, token] = await createAPIKeyAndToken([APIKeyScope.WRITE_LEADERBOARDS]) + const player = await new PlayerFactory([apiKey.game]).one() + const leaderboard = await new LeaderboardFactory([apiKey.game]).state(() => ({ unique: false })).one() + await (global.em).persistAndFlush([player, leaderboard]) + + const res = await request(global.app) + .post(`/v1/leaderboards/${leaderboard.internalName}/entries`) + .send({ + score: 300, + props: { + key1: 'value1', + key2: 'value2' + } + }) + .auth(token, { type: 'bearer' }) + .set('x-talo-alias', String(player.aliases[0].id)) + .expect(400) + + expect(res.body).toStrictEqual({ + errors: { + props: ['Props must be an array'] + } + }) + }) })