fix(engine): validation errors return 400 instead of 500 (closes #34)
- Add ValidationError class for client-side input errors - POST /events: ref format, type mismatch, nonexistent type → 400 - POST /objects: undefined type → 400 - POST /event-defs: schema validation → 400 - POST /projection-defs: value_schema, initial_value, source validation → 400 - All API handlers: catch ValidationError → 400 INVALID_INPUT - Update 10 test cases to expect 400 + INVALID_INPUT
This commit is contained in:
parent
edeb549162
commit
d06d000ec0
@ -2,6 +2,15 @@
|
|||||||
// sources[] replaces driven_by + bindings + expression
|
// sources[] replaces driven_by + bindings + expression
|
||||||
|
|
||||||
import jsonata from 'jsonata'
|
import jsonata from 'jsonata'
|
||||||
|
|
||||||
|
/** Thrown for client-side input errors (should map to HTTP 400). */
|
||||||
|
export class ValidationError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message)
|
||||||
|
this.name = 'ValidationError'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ObjectDef,
|
ObjectDef,
|
||||||
Object,
|
Object,
|
||||||
@ -88,7 +97,7 @@ export async function getObjectDef(db: D1Database, name: string): Promise<Object
|
|||||||
|
|
||||||
export async function createObject(db: D1Database, typeName: string): Promise<Object> {
|
export async function createObject(db: D1Database, typeName: string): Promise<Object> {
|
||||||
const exists = await db.prepare('SELECT 1 FROM object_defs WHERE name = ?').bind(typeName).first<{ 1: number }>()
|
const exists = await db.prepare('SELECT 1 FROM object_defs WHERE name = ?').bind(typeName).first<{ 1: number }>()
|
||||||
if (!exists) throw new Error(`Object type ${typeName} not defined`)
|
if (!exists) throw new ValidationError(`Object type ${typeName} not defined`)
|
||||||
|
|
||||||
const createdAt = Date.now()
|
const createdAt = Date.now()
|
||||||
const result = await db
|
const result = await db
|
||||||
@ -141,15 +150,15 @@ export async function listObjects(
|
|||||||
|
|
||||||
function validateEventSchema(schema: { properties: Record<string, PropertyDef> }): void {
|
function validateEventSchema(schema: { properties: Record<string, PropertyDef> }): void {
|
||||||
if (!schema.properties || typeof schema.properties !== 'object') {
|
if (!schema.properties || typeof schema.properties !== 'object') {
|
||||||
throw new Error('schema must have properties object')
|
throw new ValidationError('schema must have properties object')
|
||||||
}
|
}
|
||||||
for (const [key, prop] of Object.entries(schema.properties)) {
|
for (const [key, prop] of Object.entries(schema.properties)) {
|
||||||
if (!['ref', 'string', 'number', 'boolean'].includes(prop.type)) {
|
if (!['ref', 'string', 'number', 'boolean'].includes(prop.type)) {
|
||||||
throw new Error(`Invalid property type for ${key}: ${prop.type}`)
|
throw new ValidationError(`Invalid property type for ${key}: ${prop.type}`)
|
||||||
}
|
}
|
||||||
if (prop.type === 'ref' && prop.object_type) {
|
if (prop.type === 'ref' && prop.object_type) {
|
||||||
if (typeof prop.object_type !== 'string' && !Array.isArray(prop.object_type)) {
|
if (typeof prop.object_type !== 'string' && !Array.isArray(prop.object_type)) {
|
||||||
throw new Error(`object_type for ${key} must be string or array`)
|
throw new ValidationError(`object_type for ${key} must be string or array`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,22 +257,22 @@ async function validateEventPayload(
|
|||||||
|
|
||||||
switch (propDef.type) {
|
switch (propDef.type) {
|
||||||
case 'string':
|
case 'string':
|
||||||
if (typeof value !== 'string') throw new Error(`${key} must be string`)
|
if (typeof value !== 'string') throw new ValidationError(`${key} must be string`)
|
||||||
break
|
break
|
||||||
case 'number':
|
case 'number':
|
||||||
if (typeof value !== 'number') throw new Error(`${key} must be number`)
|
if (typeof value !== 'number') throw new ValidationError(`${key} must be number`)
|
||||||
break
|
break
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
if (typeof value !== 'boolean') throw new Error(`${key} must be boolean`)
|
if (typeof value !== 'boolean') throw new ValidationError(`${key} must be boolean`)
|
||||||
break
|
break
|
||||||
case 'ref': {
|
case 'ref': {
|
||||||
if (typeof value !== 'number') throw new Error(`${key} must be ref (number)`)
|
if (typeof value !== 'number') throw new ValidationError(`${key} must be ref (number)`)
|
||||||
const obj = await getObject(db, value)
|
const obj = await getObject(db, value)
|
||||||
if (!obj) throw new Error(`Referenced object ${value} does not exist`)
|
if (!obj) throw new ValidationError(`Referenced object ${value} does not exist`)
|
||||||
if (propDef.object_type) {
|
if (propDef.object_type) {
|
||||||
const allowedTypes = Array.isArray(propDef.object_type) ? propDef.object_type : [propDef.object_type]
|
const allowedTypes = Array.isArray(propDef.object_type) ? propDef.object_type : [propDef.object_type]
|
||||||
if (!allowedTypes.includes(obj.type)) {
|
if (!allowedTypes.includes(obj.type)) {
|
||||||
throw new Error(`${key} ref ${value} type mismatch: expected ${allowedTypes.join('|')}, got ${obj.type}`)
|
throw new ValidationError(`${key} ref ${value} type mismatch: expected ${allowedTypes.join('|')}, got ${obj.type}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
refProperties.set(key, { refId: value, objectType: propDef.object_type })
|
refProperties.set(key, { refId: value, objectType: propDef.object_type })
|
||||||
@ -281,7 +290,7 @@ export async function createEvent(
|
|||||||
payload: Record<string, any>,
|
payload: Record<string, any>,
|
||||||
): Promise<{ event: Event; reactions_fired: number; reaction_results: ReactionPayload[] }> {
|
): Promise<{ event: Event; reactions_fired: number; reaction_results: ReactionPayload[] }> {
|
||||||
const typeHash = await resolveEventDefName(db, typeName)
|
const typeHash = await resolveEventDefName(db, typeName)
|
||||||
if (!typeHash) throw new Error(`Event type ${typeName} not defined`)
|
if (!typeHash) throw new ValidationError(`Event type ${typeName} not defined`)
|
||||||
|
|
||||||
const schemaRow = await db
|
const schemaRow = await db
|
||||||
.prepare('SELECT schema FROM event_def_versions WHERE hash = ?')
|
.prepare('SELECT schema FROM event_def_versions WHERE hash = ?')
|
||||||
@ -428,39 +437,39 @@ export async function findEventsByRef(
|
|||||||
|
|
||||||
function validateValueSchema(valueSchema: { type: string }): void {
|
function validateValueSchema(valueSchema: { type: string }): void {
|
||||||
if (!valueSchema || !valueSchema.type) {
|
if (!valueSchema || !valueSchema.type) {
|
||||||
throw new Error('value_schema must have type field')
|
throw new ValidationError('value_schema must have type field')
|
||||||
}
|
}
|
||||||
const validTypes = ['ref', 'string', 'number', 'boolean', 'array', 'object']
|
const validTypes = ['ref', 'string', 'number', 'boolean', 'array', 'object']
|
||||||
if (!validTypes.includes(valueSchema.type)) {
|
if (!validTypes.includes(valueSchema.type)) {
|
||||||
throw new Error(`Invalid value_schema type: ${valueSchema.type}`)
|
throw new ValidationError(`Invalid value_schema type: ${valueSchema.type}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateInitialValue(initialValue: any, valueSchema: { type: string }): void {
|
function validateInitialValue(initialValue: any, valueSchema: { type: string }): void {
|
||||||
if (initialValue === undefined || initialValue === null) {
|
if (initialValue === undefined || initialValue === null) {
|
||||||
throw new Error('initial_value is required (cannot be null or undefined)')
|
throw new ValidationError('initial_value is required (cannot be null or undefined)')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 简单类型校验
|
// 简单类型校验
|
||||||
switch (valueSchema.type) {
|
switch (valueSchema.type) {
|
||||||
case 'string':
|
case 'string':
|
||||||
if (typeof initialValue !== 'string') throw new Error('initial_value must be string')
|
if (typeof initialValue !== 'string') throw new ValidationError('initial_value must be string')
|
||||||
break
|
break
|
||||||
case 'number':
|
case 'number':
|
||||||
if (typeof initialValue !== 'number') throw new Error('initial_value must be number')
|
if (typeof initialValue !== 'number') throw new ValidationError('initial_value must be number')
|
||||||
break
|
break
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
if (typeof initialValue !== 'boolean') throw new Error('initial_value must be boolean')
|
if (typeof initialValue !== 'boolean') throw new ValidationError('initial_value must be boolean')
|
||||||
break
|
break
|
||||||
case 'ref':
|
case 'ref':
|
||||||
if (typeof initialValue !== 'string') throw new Error('initial_value for ref must be string')
|
if (typeof initialValue !== 'string') throw new ValidationError('initial_value for ref must be string')
|
||||||
break
|
break
|
||||||
case 'array':
|
case 'array':
|
||||||
if (!Array.isArray(initialValue)) throw new Error('initial_value must be array')
|
if (!Array.isArray(initialValue)) throw new ValidationError('initial_value must be array')
|
||||||
break
|
break
|
||||||
case 'object':
|
case 'object':
|
||||||
if (typeof initialValue !== 'object' || Array.isArray(initialValue))
|
if (typeof initialValue !== 'object' || Array.isArray(initialValue))
|
||||||
throw new Error('initial_value must be object')
|
throw new ValidationError('initial_value must be object')
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,21 +486,21 @@ export async function createProjectionDef(
|
|||||||
validateInitialValue(initialValue, valueSchema)
|
validateInitialValue(initialValue, valueSchema)
|
||||||
|
|
||||||
if (!sources || sources.length === 0) {
|
if (!sources || sources.length === 0) {
|
||||||
throw new Error('At least one source is required')
|
throw new ValidationError('At least one source is required')
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolvedSources: Array<{ event_def_hash: string; bindings: Record<string, string>; expression: string }> = []
|
const resolvedSources: Array<{ event_def_hash: string; bindings: Record<string, string>; expression: string }> = []
|
||||||
|
|
||||||
for (const source of sources) {
|
for (const source of sources) {
|
||||||
const eventHash = await resolveEventDefName(db, source.event_def)
|
const eventHash = await resolveEventDefName(db, source.event_def)
|
||||||
if (!eventHash) throw new Error(`Event type ${source.event_def} not defined`)
|
if (!eventHash) throw new ValidationError(`Event type ${source.event_def} not defined`)
|
||||||
|
|
||||||
for (const [, value] of Object.entries(source.bindings)) {
|
for (const [, value] of Object.entries(source.bindings)) {
|
||||||
if (typeof value !== 'string') throw new Error('All binding values must be strings')
|
if (typeof value !== 'string') throw new ValidationError('All binding values must be strings')
|
||||||
if (value.startsWith('$')) {
|
if (value.startsWith('$')) {
|
||||||
const paramKey = value.slice(1)
|
const paramKey = value.slice(1)
|
||||||
if (!(paramKey in params))
|
if (!(paramKey in params))
|
||||||
throw new Error(`Binding references param ${paramKey} which is not defined in params`)
|
throw new ValidationError(`Binding references param ${paramKey} which is not defined in params`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1282,11 +1282,11 @@ describe('Error Cases: Object Defs', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('Error Cases: Objects', () => {
|
describe('Error Cases: Objects', () => {
|
||||||
it('POST /objects type not defined → 500', async () => {
|
it('POST /objects type not defined → 400', async () => {
|
||||||
const res = await app.fetch(req('POST', '/objects', { type: 'nonexistent' }), { DB: db, API_TOKEN: API_TOKEN })
|
const res = await app.fetch(req('POST', '/objects', { type: 'nonexistent' }), { DB: db, API_TOKEN: API_TOKEN })
|
||||||
expect(res.status).toBe(500)
|
expect(res.status).toBe(400)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
expect(json.error.code).toBe('INTERNAL_ERROR')
|
expect(json.error.code).toBe('INVALID_INPUT')
|
||||||
expect(json.error.message).toContain('Object type nonexistent not defined')
|
expect(json.error.message).toContain('Object type nonexistent not defined')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1314,26 +1314,26 @@ describe('Error Cases: Event Defs', () => {
|
|||||||
expect(json.error.code).toBe('MISSING_FIELD')
|
expect(json.error.code).toBe('MISSING_FIELD')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('POST /event-defs schema without properties → 500', async () => {
|
it('POST /event-defs schema without properties → 400', async () => {
|
||||||
const res = await app.fetch(req('POST', '/event-defs', { name: 'test', schema: {} }), {
|
const res = await app.fetch(req('POST', '/event-defs', { name: 'test', schema: {} }), {
|
||||||
DB: db,
|
DB: db,
|
||||||
API_TOKEN: API_TOKEN,
|
API_TOKEN: API_TOKEN,
|
||||||
})
|
})
|
||||||
expect(res.status).toBe(500)
|
expect(res.status).toBe(400)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
expect(json.error.code).toBe('INTERNAL_ERROR')
|
expect(json.error.code).toBe('INVALID_INPUT')
|
||||||
expect(json.error.message).toContain('properties')
|
expect(json.error.message).toContain('properties')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('POST /event-defs invalid property type → 500', async () => {
|
it('POST /event-defs invalid property type → 400', async () => {
|
||||||
const schema = { properties: { field: { type: 'invalid' } } }
|
const schema = { properties: { field: { type: 'invalid' } } }
|
||||||
const res = await app.fetch(req('POST', '/event-defs', { name: 'test', schema }), {
|
const res = await app.fetch(req('POST', '/event-defs', { name: 'test', schema }), {
|
||||||
DB: db,
|
DB: db,
|
||||||
API_TOKEN: API_TOKEN,
|
API_TOKEN: API_TOKEN,
|
||||||
})
|
})
|
||||||
expect(res.status).toBe(500)
|
expect(res.status).toBe(400)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
expect(json.error.code).toBe('INTERNAL_ERROR')
|
expect(json.error.code).toBe('INVALID_INPUT')
|
||||||
expect(json.error.message).toContain('Invalid property type')
|
expect(json.error.message).toContain('Invalid property type')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1369,29 +1369,29 @@ describe('Error Cases: Events', () => {
|
|||||||
await app.fetch(req('POST', '/event-defs', { name: 'test_event', schema }), { DB: db, API_TOKEN: API_TOKEN })
|
await app.fetch(req('POST', '/event-defs', { name: 'test_event', schema }), { DB: db, API_TOKEN: API_TOKEN })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('POST /events type not defined → 500', async () => {
|
it('POST /events type not defined → 400', async () => {
|
||||||
const res = await app.fetch(req('POST', '/events', { type: 'nonexistent', payload: {} }), {
|
const res = await app.fetch(req('POST', '/events', { type: 'nonexistent', payload: {} }), {
|
||||||
DB: db,
|
DB: db,
|
||||||
API_TOKEN: API_TOKEN,
|
API_TOKEN: API_TOKEN,
|
||||||
})
|
})
|
||||||
expect(res.status).toBe(500)
|
expect(res.status).toBe(400)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
expect(json.error.code).toBe('INTERNAL_ERROR')
|
expect(json.error.code).toBe('INVALID_INPUT')
|
||||||
expect(json.error.message).toContain('Event type nonexistent not defined')
|
expect(json.error.message).toContain('Event type nonexistent not defined')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('POST /events ref nonexistent object → 500', async () => {
|
it('POST /events ref nonexistent object → 400', async () => {
|
||||||
const res = await app.fetch(req('POST', '/events', { type: 'test_event', payload: { participant: 99999 } }), {
|
const res = await app.fetch(req('POST', '/events', { type: 'test_event', payload: { participant: 99999 } }), {
|
||||||
DB: db,
|
DB: db,
|
||||||
API_TOKEN: API_TOKEN,
|
API_TOKEN: API_TOKEN,
|
||||||
})
|
})
|
||||||
expect(res.status).toBe(500)
|
expect(res.status).toBe(400)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
expect(json.error.code).toBe('INTERNAL_ERROR')
|
expect(json.error.code).toBe('INVALID_INPUT')
|
||||||
expect(json.error.message).toContain('does not exist')
|
expect(json.error.message).toContain('does not exist')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('POST /events ref type mismatch → 500', async () => {
|
it('POST /events ref type mismatch → 400', async () => {
|
||||||
await app.fetch(req('POST', '/object-defs', { name: 'task' }), { DB: db, API_TOKEN: API_TOKEN })
|
await app.fetch(req('POST', '/object-defs', { name: 'task' }), { DB: db, API_TOKEN: API_TOKEN })
|
||||||
const taskRes = await app.fetch(req('POST', '/objects', { type: 'task' }), { DB: db, API_TOKEN: API_TOKEN })
|
const taskRes = await app.fetch(req('POST', '/objects', { type: 'task' }), { DB: db, API_TOKEN: API_TOKEN })
|
||||||
const taskId = (await taskRes.json()).id
|
const taskId = (await taskRes.json()).id
|
||||||
@ -1399,20 +1399,20 @@ describe('Error Cases: Events', () => {
|
|||||||
DB: db,
|
DB: db,
|
||||||
API_TOKEN: API_TOKEN,
|
API_TOKEN: API_TOKEN,
|
||||||
})
|
})
|
||||||
expect(res.status).toBe(500)
|
expect(res.status).toBe(400)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
expect(json.error.code).toBe('INTERNAL_ERROR')
|
expect(json.error.code).toBe('INVALID_INPUT')
|
||||||
expect(json.error.message).toContain('type mismatch')
|
expect(json.error.message).toContain('type mismatch')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('POST /events payload property wrong type → 500', async () => {
|
it('POST /events payload property wrong type → 400', async () => {
|
||||||
const res = await app.fetch(
|
const res = await app.fetch(
|
||||||
req('POST', '/events', { type: 'test_event', payload: { participant: agentId, count: 'string' } }),
|
req('POST', '/events', { type: 'test_event', payload: { participant: agentId, count: 'string' } }),
|
||||||
{ DB: db, API_TOKEN: API_TOKEN },
|
{ DB: db, API_TOKEN: API_TOKEN },
|
||||||
)
|
)
|
||||||
expect(res.status).toBe(500)
|
expect(res.status).toBe(400)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
expect(json.error.code).toBe('INTERNAL_ERROR')
|
expect(json.error.code).toBe('INVALID_INPUT')
|
||||||
expect(json.error.message).toContain('must be number')
|
expect(json.error.message).toContain('must be number')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1550,7 +1550,7 @@ describe('Error Cases: Projection Defs', () => {
|
|||||||
expect(json.error.message).toContain('sources')
|
expect(json.error.message).toContain('sources')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('POST /projection-defs invalid value_schema type → 500', async () => {
|
it('POST /projection-defs invalid value_schema type → 400', async () => {
|
||||||
const res = await app.fetch(
|
const res = await app.fetch(
|
||||||
req('POST', '/projection-defs', {
|
req('POST', '/projection-defs', {
|
||||||
name: 'test_proj',
|
name: 'test_proj',
|
||||||
@ -1561,13 +1561,13 @@ describe('Error Cases: Projection Defs', () => {
|
|||||||
}),
|
}),
|
||||||
{ DB: db, API_TOKEN: API_TOKEN },
|
{ DB: db, API_TOKEN: API_TOKEN },
|
||||||
)
|
)
|
||||||
expect(res.status).toBe(500)
|
expect(res.status).toBe(400)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
expect(json.error.code).toBe('INTERNAL_ERROR')
|
expect(json.error.code).toBe('INVALID_INPUT')
|
||||||
expect(json.error.message).toContain('Invalid value_schema type')
|
expect(json.error.message).toContain('Invalid value_schema type')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('POST /projection-defs initial_value type mismatch → 500', async () => {
|
it('POST /projection-defs initial_value type mismatch → 400', async () => {
|
||||||
const res = await app.fetch(
|
const res = await app.fetch(
|
||||||
req('POST', '/projection-defs', {
|
req('POST', '/projection-defs', {
|
||||||
name: 'test_proj',
|
name: 'test_proj',
|
||||||
@ -1578,13 +1578,13 @@ describe('Error Cases: Projection Defs', () => {
|
|||||||
}),
|
}),
|
||||||
{ DB: db, API_TOKEN: API_TOKEN },
|
{ DB: db, API_TOKEN: API_TOKEN },
|
||||||
)
|
)
|
||||||
expect(res.status).toBe(500)
|
expect(res.status).toBe(400)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
expect(json.error.code).toBe('INTERNAL_ERROR')
|
expect(json.error.code).toBe('INVALID_INPUT')
|
||||||
expect(json.error.message).toContain('initial_value must be number')
|
expect(json.error.message).toContain('initial_value must be number')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('POST /projection-defs source with nonexistent event → 500', async () => {
|
it('POST /projection-defs source with nonexistent event → 400', async () => {
|
||||||
const res = await app.fetch(
|
const res = await app.fetch(
|
||||||
req('POST', '/projection-defs', {
|
req('POST', '/projection-defs', {
|
||||||
name: 'test_proj',
|
name: 'test_proj',
|
||||||
@ -1595,9 +1595,9 @@ describe('Error Cases: Projection Defs', () => {
|
|||||||
}),
|
}),
|
||||||
{ DB: db, API_TOKEN: API_TOKEN },
|
{ DB: db, API_TOKEN: API_TOKEN },
|
||||||
)
|
)
|
||||||
expect(res.status).toBe(500)
|
expect(res.status).toBe(400)
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
expect(json.error.code).toBe('INTERNAL_ERROR')
|
expect(json.error.code).toBe('INVALID_INPUT')
|
||||||
expect(json.error.message).toContain('Event type nonexistent not defined')
|
expect(json.error.message).toContain('Event type nonexistent not defined')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,7 @@ import {
|
|||||||
deleteApiKey,
|
deleteApiKey,
|
||||||
validateApiKey,
|
validateApiKey,
|
||||||
getSchema,
|
getSchema,
|
||||||
|
ValidationError,
|
||||||
} from './engine'
|
} from './engine'
|
||||||
import type {
|
import type {
|
||||||
CreateObjectDefRequest,
|
CreateObjectDefRequest,
|
||||||
@ -158,7 +159,7 @@ app.post('/object-defs', async (c) => {
|
|||||||
const result = await createObjectDef(c.env.DB, body.name)
|
const result = await createObjectDef(c.env.DB, body.name)
|
||||||
return c.json(result, 201)
|
return c.json(result, 201)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
if (err?.name === 'ValidationError') return apiError(c, 400, ErrorCode.INVALID_INPUT, err.message); return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -185,7 +186,7 @@ app.post('/objects', async (c) => {
|
|||||||
const obj = await createObject(c.env.DB, body.type)
|
const obj = await createObject(c.env.DB, body.type)
|
||||||
return c.json(obj, 201)
|
return c.json(obj, 201)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
if (err?.name === 'ValidationError') return apiError(c, 400, ErrorCode.INVALID_INPUT, err.message); return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -220,7 +221,7 @@ app.post('/event-defs', async (c) => {
|
|||||||
const result = await createEventDef(c.env.DB, body.name, body.schema)
|
const result = await createEventDef(c.env.DB, body.name, body.schema)
|
||||||
return c.json(result, 201)
|
return c.json(result, 201)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
if (err?.name === 'ValidationError') return apiError(c, 400, ErrorCode.INVALID_INPUT, err.message); return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -288,7 +289,10 @@ app.post('/events', async (c) => {
|
|||||||
|
|
||||||
return c.json({ event, reactions_fired, reaction_results }, 201)
|
return c.json({ event, reactions_fired, reaction_results }, 201)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
if (err?.name === 'ValidationError') {
|
||||||
|
return apiError(c, 400, ErrorCode.INVALID_INPUT, err.message)
|
||||||
|
}
|
||||||
|
if (err?.name === 'ValidationError') return apiError(c, 400, ErrorCode.INVALID_INPUT, err.message); return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -338,7 +342,7 @@ app.post('/projection-defs', async (c) => {
|
|||||||
)
|
)
|
||||||
return c.json(result, 201)
|
return c.json(result, 201)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
if (err?.name === 'ValidationError') return apiError(c, 400, ErrorCode.INVALID_INPUT, err.message); return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -374,7 +378,7 @@ app.get('/projections/:name', async (c) => {
|
|||||||
}
|
}
|
||||||
return c.json(response)
|
return c.json(response)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
if (err?.name === 'ValidationError') return apiError(c, 400, ErrorCode.INVALID_INPUT, err.message); return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -408,7 +412,7 @@ app.post('/reactions', async (c) => {
|
|||||||
})
|
})
|
||||||
return c.json(reaction, 201)
|
return c.json(reaction, 201)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
if (err?.name === 'ValidationError') return apiError(c, 400, ErrorCode.INVALID_INPUT, err.message); return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -499,7 +503,7 @@ app.post('/api-keys', async (c) => {
|
|||||||
const result = await createApiKey(c.env.DB, body.name, body.allowed_events, body.rate_limit)
|
const result = await createApiKey(c.env.DB, body.name, body.allowed_events, body.rate_limit)
|
||||||
return c.json(result, 201)
|
return c.json(result, 201)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
if (err?.name === 'ValidationError') return apiError(c, 400, ErrorCode.INVALID_INPUT, err.message); return apiError(c, 500, ErrorCode.INTERNAL_ERROR, err.message || 'Internal error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user