Skip to content

Commit bc754d3

Browse files
authored
fix(client): Ensure all client methods require valid ids (#3661)
1 parent f711789 commit bc754d3

File tree

4 files changed

+108
-23
lines changed

4 files changed

+108
-23
lines changed

packages/rest-client/src/base.ts

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import qs from 'qs'
22
import { Params, Id, Query, NullableId, ServiceInterface } from '@feathersjs/feathers'
3-
import { Unavailable, convert } from '@feathersjs/errors'
3+
import { BadRequest, Unavailable, convert } from '@feathersjs/errors'
44
import { _, stripSlashes } from '@feathersjs/commons'
55

66
function toError(error: Error & { code: string }) {
@@ -113,8 +113,8 @@ export abstract class Base<
113113
}
114114

115115
_get(id: Id, params?: P) {
116-
if (typeof id === 'undefined') {
117-
return Promise.reject(new Error("id for 'get' can not be undefined"))
116+
if (id === undefined || id === '') {
117+
return Promise.reject(new BadRequest('id for .get is required'))
118118
}
119119

120120
return this.request(
@@ -148,10 +148,8 @@ export abstract class Base<
148148
}
149149

150150
_update(id: NullableId, data: D, params?: P) {
151-
if (typeof id === 'undefined') {
152-
return Promise.reject(
153-
new Error("id for 'update' can not be undefined, only 'null' when updating multiple entries")
154-
)
151+
if (id === undefined || id === '') {
152+
return Promise.reject(new BadRequest('id for .update is required'))
155153
}
156154

157155
return this.request(
@@ -170,10 +168,8 @@ export abstract class Base<
170168
}
171169

172170
_patch(id: NullableId, data: D, params?: P) {
173-
if (typeof id === 'undefined') {
174-
return Promise.reject(
175-
new Error("id for 'patch' can not be undefined, only 'null' when updating multiple entries")
176-
)
171+
if (id === undefined || id === '') {
172+
return Promise.reject(new BadRequest('id for .patch is required'))
177173
}
178174

179175
return this.request(
@@ -192,10 +188,8 @@ export abstract class Base<
192188
}
193189

194190
_remove(id: NullableId, params?: P) {
195-
if (typeof id === 'undefined') {
196-
return Promise.reject(
197-
new Error("id for 'remove' can not be undefined, only 'null' when removing multiple entries")
198-
)
191+
if (id === undefined || id === '') {
192+
return Promise.reject(new BadRequest('id for .remove is required'))
199193
}
200194

201195
return this.request(

packages/rest-client/test/index.test.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,25 +46,41 @@ describe('REST client tests', function () {
4646
}
4747
})
4848

49-
it('errors when id property for get, patch, update or remove is undefined', async () => {
49+
it('errors when id property for get, patch, update or remove is undefined or empty string', async () => {
5050
const app = feathers().configure(init('http://localhost:8889').fetch(fetch))
5151

5252
const service = app.service('todos')
5353

5454
await assert.rejects(() => service.get(undefined), {
55-
message: "id for 'get' can not be undefined"
55+
message: 'id for .get is required'
56+
})
57+
58+
await assert.rejects(() => service.get(''), {
59+
message: 'id for .get is required'
5660
})
5761

5862
await assert.rejects(() => service.remove(undefined), {
59-
message: "id for 'remove' can not be undefined, only 'null' when removing multiple entries"
63+
message: 'id for .remove is required'
64+
})
65+
66+
await assert.rejects(() => service.remove(''), {
67+
message: 'id for .remove is required'
6068
})
6169

6270
await assert.rejects(() => service.update(undefined, {}), {
63-
message: "id for 'update' can not be undefined, only 'null' when updating multiple entries"
71+
message: 'id for .update is required'
72+
})
73+
74+
await assert.rejects(() => service.update('', {}), {
75+
message: 'id for .update is required'
6476
})
6577

6678
await assert.rejects(() => service.patch(undefined, {}), {
67-
message: "id for 'patch' can not be undefined, only 'null' when updating multiple entries"
79+
message: 'id for .patch is required'
80+
})
81+
82+
await assert.rejects(() => service.patch('', {}), {
83+
message: 'id for .patch is required'
6884
})
6985
})
7086

packages/transport-commons/src/client.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable @typescript-eslint/ban-ts-comment */
2-
import { convert } from '@feathersjs/errors'
2+
import { BadRequest, convert } from '@feathersjs/errors'
33
import { createDebug } from '@feathersjs/commons'
44
import { Id, NullableId, Params, ServiceInterface } from '@feathersjs/feathers'
55

@@ -128,6 +128,10 @@ export class Service<T = any, D = Partial<T>, P extends Params = Params> impleme
128128
}
129129

130130
_get(id: Id, params: Params = {}) {
131+
if (id === undefined || id === '') {
132+
return Promise.reject(new BadRequest('id for .get is required'))
133+
}
134+
131135
return this.send<T>('get', id, params.query || {}, params.route || {})
132136
}
133137

@@ -144,17 +148,26 @@ export class Service<T = any, D = Partial<T>, P extends Params = Params> impleme
144148
}
145149

146150
_update(id: NullableId, data: D, params: Params = {}) {
147-
if (typeof id === 'undefined') {
148-
return Promise.reject(new Error("id for 'update' can not be undefined"))
151+
if (id === undefined || id === '') {
152+
return Promise.reject(new BadRequest('id for .update is required'))
149153
}
154+
150155
return this.send<T>('update', id, data, params.query || {}, params.route || {})
151156
}
152157

153158
update(id: NullableId, data: D, params: Params = {}) {
159+
if (id === undefined || id === '') {
160+
return Promise.reject(new BadRequest('id for .update is required'))
161+
}
162+
154163
return this._update(id, data, params)
155164
}
156165

157166
_patch(id: NullableId, data: D, params: Params = {}) {
167+
if (id === undefined || id === '') {
168+
return Promise.reject(new BadRequest('id for .patch is required'))
169+
}
170+
158171
return this.send<T | T[]>('patch', id, data, params.query || {}, params.route || {})
159172
}
160173

@@ -163,6 +176,10 @@ export class Service<T = any, D = Partial<T>, P extends Params = Params> impleme
163176
}
164177

165178
_remove(id: NullableId, params: Params = {}) {
179+
if (id === undefined || id === '') {
180+
return Promise.reject(new BadRequest('id for .remove is required'))
181+
}
182+
166183
return this.send<T | T[]>('remove', id, params.query || {}, params.route || {})
167184
}
168185

packages/transport-commons/test/client.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,64 @@ describe('client', () => {
2727
assert.ok(service.events)
2828
})
2929

30+
it('throws for .get, .update, .patch and .remove with undefined or empty string id', async () => {
31+
try {
32+
await service.get(undefined)
33+
assert.ok(false, 'Should never get here')
34+
} catch (e: any) {
35+
assert.strictEqual(e.message, 'id for .get is required')
36+
}
37+
38+
try {
39+
await service.get('')
40+
assert.ok(false, 'Should never get here')
41+
} catch (e: any) {
42+
assert.strictEqual(e.message, 'id for .get is required')
43+
}
44+
45+
try {
46+
await service.update(undefined, testData)
47+
assert.ok(false, 'Should never get here')
48+
} catch (e: any) {
49+
assert.strictEqual(e.message, 'id for .update is required')
50+
}
51+
52+
try {
53+
await service.update('', testData)
54+
assert.ok(false, 'Should never get here')
55+
} catch (e: any) {
56+
assert.strictEqual(e.message, 'id for .update is required')
57+
}
58+
59+
try {
60+
await service.patch(undefined, testData)
61+
assert.ok(false, 'Should never get here')
62+
} catch (e: any) {
63+
assert.strictEqual(e.message, 'id for .patch is required')
64+
}
65+
66+
try {
67+
await service.patch('', testData)
68+
assert.ok(false, 'Should never get here')
69+
} catch (e: any) {
70+
assert.strictEqual(e.message, 'id for .patch is required')
71+
}
72+
73+
try {
74+
await service.remove(undefined)
75+
assert.ok(false, 'Should never get here')
76+
} catch (e: any) {
77+
assert.strictEqual(e.message, 'id for .remove is required')
78+
}
79+
80+
try {
81+
await service.remove('')
82+
assert.ok(false, 'Should never get here')
83+
} catch (e: any) {
84+
assert.strictEqual(e.message, 'id for .remove is required')
85+
}
86+
})
87+
3088
it('throws an error when the emitter does not have the method', () => {
3189
const clientService = new Service({
3290
name: 'todos',

0 commit comments

Comments
 (0)