Skip to content

Commit fae74b5

Browse files
authored
fix(rest): give the bare 501 exits a machine code — NOT_IMPLEMENTED (#4067) (#4068)
Four 501 exits returned a bare `{ error: '<string>' }` with no machine code, while most REST exits (and the clone / search 501s) already carry one: the cross-object transactional batch route when the runtime has no transaction() — the last untyped exit on that route after the #3897 / #3933 / #3939 line — plus the two saveMetaItem-unsupported exits and the UI-view-resolution-unsupported exit. Each now carries code: 'NOT_IMPLEMENTED', matching clone / search. Additive only (message and status unchanged); existing clients unaffected, new ones can branch on the code. Extended the cross-object batch 501 test to assert the code. Closes #4067.
1 parent 3abd233 commit fae74b5

3 files changed

Lines changed: 31 additions & 5 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
"@objectstack/rest": patch
3+
---
4+
5+
fix(rest): give the bare 501 error exits a machine `code` (#4067)
6+
7+
Most REST error exits already carry a typed `code` (`VALIDATION_FAILED`,
8+
`BATCH_NOT_ATOMIC`, `BATCH_TOO_LARGE`, `PERMISSION_DENIED`), and the clone /
9+
search 501s already answer `{ error, code: 'NOT_IMPLEMENTED' }`. Four 501 exits
10+
still returned a bare `{ error: '<string>' }` with no code, so a client could
11+
only key on the prose:
12+
13+
- the cross-object transactional batch route (`POST {basePath}/batch`) when the
14+
runtime has no `transaction()` — the last untyped exit on that route, whose
15+
siblings (`BATCH_NOT_ATOMIC`, `VALIDATION_FAILED`, the `enforceBatchSize`
16+
`BATCH_TOO_LARGE`) were already typed by the #3897 / #3933 / #3939 line;
17+
- the two `saveMetaItem`-unsupported exits;
18+
- the UI-view-resolution-unsupported exit.
19+
20+
Each now carries `code: 'NOT_IMPLEMENTED'`, matching the clone / search 501s.
21+
Additive only — the `error` message is unchanged and no status changes — so
22+
existing clients are unaffected; new ones can branch on the code.

packages/rest/src/rest-batch-endpoint.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,12 @@ describe('POST {basePath}/batch — cross-object transactional batch', () => {
109109
expect(route!.metadata?.tags).toEqual(expect.arrayContaining(['data', 'batch']));
110110
});
111111

112-
it('returns 501 when the runtime has no transactional ObjectQL', async () => {
112+
it('returns 501 with a NOT_IMPLEMENTED code when the runtime has no transactional ObjectQL', async () => {
113113
const { route } = buildServer({}); // no ql provider
114114
const res = await post(route, { operations: [{ object: 'account', data: {} }] });
115115
expect(res.statusCode).toBe(501);
116+
// Typed like every other 501 (#4067) so clients key on the code, not the prose.
117+
expect(res.body.code).toBe('NOT_IMPLEMENTED');
116118
});
117119

118120
// ── happy path ───────────────────────────────────────────────────────────

packages/rest/src/rest-server.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3334,7 +3334,7 @@ export class RestServer {
33343334
const environmentId = isScoped ? req.params?.environmentId : undefined;
33353335
const p = await this.resolveProtocol(environmentId, req);
33363336
if (!p.saveMetaItem) {
3337-
res.status(501).json({ error: 'Save operation not supported by protocol implementation' });
3337+
res.status(501).json({ error: 'Save operation not supported by protocol implementation', code: 'NOT_IMPLEMENTED' });
33383338
return;
33393339
}
33403340

@@ -3717,7 +3717,7 @@ export class RestServer {
37173717
const environmentId = isScoped ? req.params?.environmentId : undefined;
37183718
const p = await this.resolveProtocol(environmentId, req);
37193719
if (!p.saveMetaItem) {
3720-
res.status(501).json({ error: 'Save operation not supported by protocol implementation' });
3720+
res.status(501).json({ error: 'Save operation not supported by protocol implementation', code: 'NOT_IMPLEMENTED' });
37213721
return;
37223722
}
37233723

@@ -3780,7 +3780,7 @@ export class RestServer {
37803780
} as any);
37813781
res.json(view);
37823782
} else {
3783-
res.status(501).json({ error: 'UI View resolution not supported by protocol implementation' });
3783+
res.status(501).json({ error: 'UI View resolution not supported by protocol implementation', code: 'NOT_IMPLEMENTED' });
37843784
}
37853785
} catch (error: any) {
37863786
logError("[REST] Unhandled error:", error);
@@ -6877,7 +6877,9 @@ export class RestServer {
68776877
if (this.enforceAuth(req, res, context)) return;
68786878
const ql = this.objectQLProvider ? await this.objectQLProvider(environmentId) : undefined;
68796879
if (!ql || typeof ql.transaction !== 'function') {
6880-
res.status(501).json({ error: 'Transactional batch not supported by this runtime' });
6880+
// Typed like every other 501 on this server (clone/search,
6881+
// #4067) so a client can key on the code, not the prose.
6882+
res.status(501).json({ error: 'Transactional batch not supported by this runtime', code: 'NOT_IMPLEMENTED' });
68816883
return;
68826884
}
68836885

0 commit comments

Comments
 (0)