Skip to content

Commit eacf9aa

Browse files
committed
SOFIE-295 | make the api error more generic
1 parent fc72f02 commit eacf9aa

4 files changed

Lines changed: 21 additions & 17 deletions

File tree

meteor/server/api/rest/v1/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ interface APIRequestError {
117117
status: number
118118
message: string
119119
details?: string[]
120+
additionalInfo?: Record<string, unknown>
120121
}
121122

122123
function sofieAPIRequest<API, Params, Body, Response>(
@@ -133,6 +134,7 @@ function sofieAPIRequest<API, Params, Body, Response>(
133134
) => Promise<ClientAPI.ClientResponse<Response>>
134135
) {
135136
koaRouter[method](route, async (ctx, next) => {
137+
let responseAdditionalInfo: Record<string, unknown> | undefined
136138
try {
137139
const context = new APIContext()
138140
const serverAPI = serverAPIFactory.createServerAPI(context)
@@ -144,6 +146,7 @@ function sofieAPIRequest<API, Params, Body, Response>(
144146
ctx.request.body as unknown as Body
145147
)
146148
if (ClientAPI.isClientResponseError(response)) {
149+
responseAdditionalInfo = response.additionalInfo
147150
throw UserError.fromSerialized(response.error)
148151
}
149152
ctx.body = JSON.stringify({ status: response.success, result: response.result })
@@ -176,7 +179,8 @@ function sofieAPIRequest<API, Params, Body, Response>(
176179
ctx.type = 'application/json'
177180
const bodyObj: APIRequestError = { status: errCode, message: errMsg }
178181
const details = extractErrorDetails(e)
179-
if (details) bodyObj['details'] = details
182+
if (details) bodyObj.details = details
183+
if (responseAdditionalInfo) bodyObj.additionalInfo = responseAdditionalInfo
180184
ctx.body = JSON.stringify(bodyObj)
181185
ctx.status = errCode
182186
}

packages/meteor-lib/src/api/__tests__/client.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('ClientAPI', () => {
5050
})
5151
}
5252
})
53-
it('Extracts nextAllowedTakeTime from error args', () => {
53+
it('Extracts additionalInfo from error args', () => {
5454
const error = ClientAPI.responseError(
5555
UserError.create(
5656
UserErrorMessage.TakeRateLimit,
@@ -61,12 +61,12 @@ describe('ClientAPI', () => {
6161
429
6262
)
6363
)
64-
expect(error.nextAllowedTakeTime).toBe(1234567890)
64+
expect(error.additionalInfo).toEqual({ duration: 1000, nextAllowedTakeTime: 1234567890 })
6565
expect(error.errorCode).toBe(429)
6666
})
67-
it('Does not include nextAllowedTakeTime when not in args', () => {
67+
it('Does not include additionalInfo when no args', () => {
6868
const error = ClientAPI.responseError(UserError.create(UserErrorMessage.InactiveRundown))
69-
expect(error.nextAllowedTakeTime).toBeUndefined()
69+
expect(error.additionalInfo).toBeUndefined()
7070
})
7171
describe('isClientResponseSuccess', () => {
7272
it('Correctly recognizes a responseSuccess object', () => {

packages/meteor-lib/src/api/client.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ export namespace ClientAPI {
5050
errorCode: number
5151
/** On error, provide a human-readable error message */
5252
error: SerializedUserError
53-
/** For blocked TAKE operations, the next allowed take time (Unix timestamp ms) */
54-
nextAllowedTakeTime?: number
53+
/** Optional additional information about the error, forwarded from UserError args */
54+
additionalInfo?: Record<string, unknown>
5555
}
5656

5757
/**
@@ -61,11 +61,11 @@ export namespace ClientAPI {
6161
* @returns A `ClientResponseError` object containing the error and the resolved error code.
6262
*/
6363
export function responseError(userError: UserError): ClientResponseError {
64-
const nextAllowedTakeTime = userError.userMessage.args?.nextAllowedTakeTime as number | undefined
64+
const args = userError.userMessage.args
6565
return {
6666
error: UserError.serialize(userError),
6767
errorCode: userError.errorCode,
68-
...(nextAllowedTakeTime !== undefined && { nextAllowedTakeTime }),
68+
...(args !== undefined && Object.keys(args).length > 0 && { additionalInfo: args }),
6969
}
7070
}
7171
export interface ClientResponseSuccess<Result> {

packages/openapi/api/definitions/playlists.yaml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -633,10 +633,10 @@ resources:
633633
message:
634634
type: string
635635
example: Cannot take during a transition
636-
nextAllowedTakeTime:
637-
type: number
638-
description: Unix timestamp (ms) of when the next take will be allowed.
639-
example: 1707024000000
636+
additionalInfo:
637+
type: object
638+
description: Additional error details, e.g. includes nextAllowedTakeTime (Unix timestamp ms) for blocked takes.
639+
additionalProperties: true
640640
429:
641641
description: Take rate limit exceeded - takes are happening too quickly.
642642
content:
@@ -650,10 +650,10 @@ resources:
650650
message:
651651
type: string
652652
example: Ignoring TAKES that are too quick after eachother (1000 ms)
653-
nextAllowedTakeTime:
654-
type: number
655-
description: Unix timestamp (ms) of when the next take will be allowed.
656-
example: 1707024000000
653+
additionalInfo:
654+
type: object
655+
description: Additional error details, e.g. includes nextAllowedTakeTime (Unix timestamp ms) for blocked takes.
656+
additionalProperties: true
657657
500:
658658
$ref: '#/components/responses/internalServerError'
659659

0 commit comments

Comments
 (0)