Skip to content

Commit c138acf

Browse files
authored
feat(client): Improve client side custom method support (#2654)
1 parent c9b8f74 commit c138acf

15 files changed

Lines changed: 900 additions & 834 deletions

File tree

package-lock.json

Lines changed: 791 additions & 786 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/feathers/src/declarations.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ export type CustomMethods<T extends { [key: string]: [any, any] }> = {
8989
[K in keyof T]: (data: T[K][0], params?: Params) => Promise<T[K][1]>
9090
}
9191

92+
export type CustomMethod<T = any, R = T, P extends Params = Params> = (data: T, params?: P) => Promise<R>
93+
9294
export type ServiceMixin<A> = (service: FeathersService<A>, path: string, options: ServiceOptions) => void
9395

9496
export type ServiceGenericType<S> = S extends ServiceInterface<infer T> ? T : any

packages/rest-client/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@
5454
"dependencies": {
5555
"@feathersjs/commons": "^5.0.0-pre.22",
5656
"@feathersjs/errors": "^5.0.0-pre.22",
57-
"@types/node-fetch": "^3.0.2",
57+
"@feathersjs/feathers": "^5.0.0-pre.22",
5858
"@types/superagent": "^4.1.15",
5959
"qs": "^6.10.3"
6060
},
6161
"devDependencies": {
6262
"@feathersjs/express": "^5.0.0-pre.22",
63-
"@feathersjs/feathers": "^5.0.0-pre.22",
6463
"@feathersjs/memory": "^5.0.0-pre.22",
6564
"@feathersjs/tests": "^5.0.0-pre.22",
65+
"@types/node-fetch": "^2.0.2",
6666
"@types/mocha": "^9.1.1",
6767
"@types/node": "^17.0.31",
6868
"@types/qs": "^6.9.7",

packages/rest-client/src/axios.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { Params } from '@feathersjs/feathers'
12
import { Base, RestClientParams } from './base'
23

3-
export class AxiosClient extends Base {
4+
export class AxiosClient<T = any, D = Partial<T>, P extends Params = RestClientParams> extends Base<T, D, P> {
45
request(options: any, params: RestClientParams) {
56
const config = Object.assign(
67
{

packages/rest-client/src/base.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ interface RestClientSettings {
2222
options: any
2323
}
2424

25-
export abstract class Base<T = any, D = Partial<T>> implements ServiceInterface<T, D> {
25+
export abstract class Base<T = any, D = Partial<T>, P extends Params = RestClientParams>
26+
implements ServiceInterface<T, D, P>
27+
{
2628
name: string
2729
base: string
2830
connection: any
@@ -57,7 +59,7 @@ export abstract class Base<T = any, D = Partial<T>> implements ServiceInterface<
5759
return ''
5860
}
5961

60-
abstract request(options: any, params: Params): any
62+
abstract request(options: any, params: P): any
6163

6264
methods(this: any, ...names: string[]) {
6365
names.forEach((method) => {
@@ -83,7 +85,7 @@ export abstract class Base<T = any, D = Partial<T>> implements ServiceInterface<
8385
return this
8486
}
8587

86-
find(params: RestClientParams = {}) {
88+
find(params?: P) {
8789
return this.request(
8890
{
8991
url: this.makeUrl(params.query),
@@ -94,7 +96,7 @@ export abstract class Base<T = any, D = Partial<T>> implements ServiceInterface<
9496
).catch(toError)
9597
}
9698

97-
get(id: Id, params: RestClientParams = {}) {
99+
get(id: Id, params?: P) {
98100
if (typeof id === 'undefined') {
99101
return Promise.reject(new Error("id for 'get' can not be undefined"))
100102
}
@@ -109,7 +111,7 @@ export abstract class Base<T = any, D = Partial<T>> implements ServiceInterface<
109111
).catch(toError)
110112
}
111113

112-
create(body: D, params: RestClientParams = {}) {
114+
create(body: D, params?: P) {
113115
return this.request(
114116
{
115117
url: this.makeUrl(params.query),
@@ -121,7 +123,7 @@ export abstract class Base<T = any, D = Partial<T>> implements ServiceInterface<
121123
).catch(toError)
122124
}
123125

124-
update(id: NullableId, body: D, params: RestClientParams = {}) {
126+
update(id: NullableId, body: D, params?: P) {
125127
if (typeof id === 'undefined') {
126128
return Promise.reject(
127129
new Error("id for 'update' can not be undefined, only 'null' when updating multiple entries")
@@ -139,7 +141,7 @@ export abstract class Base<T = any, D = Partial<T>> implements ServiceInterface<
139141
).catch(toError)
140142
}
141143

142-
patch(id: NullableId, body: D, params: RestClientParams = {}) {
144+
patch(id: NullableId, body: D, params?: P) {
143145
if (typeof id === 'undefined') {
144146
return Promise.reject(
145147
new Error("id for 'patch' can not be undefined, only 'null' when updating multiple entries")
@@ -157,7 +159,7 @@ export abstract class Base<T = any, D = Partial<T>> implements ServiceInterface<
157159
).catch(toError)
158160
}
159161

160-
remove(id: NullableId, params: RestClientParams = {}) {
162+
remove(id: NullableId, params?: P) {
161163
if (typeof id === 'undefined') {
162164
return Promise.reject(
163165
new Error("id for 'remove' can not be undefined, only 'null' when removing multiple entries")

packages/rest-client/src/fetch.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { errors } from '@feathersjs/errors'
2+
import { Params } from '@feathersjs/feathers'
23
import { Base, RestClientParams } from './base'
34

4-
export class FetchClient extends Base {
5+
export class FetchClient<T = any, D = Partial<T>, P extends Params = RestClientParams> extends Base<T, D, P> {
56
request(options: any, params: RestClientParams) {
67
const fetchOptions = Object.assign({}, options, params.connection)
78

packages/rest-client/src/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Application, defaultServiceMethods } from '@feathersjs/feathers'
2+
13
import { Base } from './base'
24
import { AxiosClient } from './axios'
35
import { FetchClient } from './fetch'
@@ -56,13 +58,20 @@ export default function restClient(base = '') {
5658
return new (Service as any)({ base, name, connection, options })
5759
}
5860

59-
const initialize = (app: any) => {
61+
const initialize = (app: Application & { rest: any }) => {
6062
if (app.rest !== undefined) {
6163
throw new Error('Only one default client provider can be configured')
6264
}
6365

6466
app.rest = connection
6567
app.defaultService = defaultService
68+
app.mixins.unshift((service, _location, options) => {
69+
if (options && options.methods && service instanceof Base) {
70+
const customMethods = options.methods.filter((name) => !defaultServiceMethods.includes(name))
71+
72+
service.methods(...customMethods)
73+
}
74+
})
6675
}
6776

6877
initialize.Service = Service

packages/rest-client/src/superagent.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
import { Params } from '@feathersjs/feathers'
12
import { Base, RestClientParams } from './base'
23

3-
export class SuperagentClient extends Base {
4+
export class SuperagentClient<T = any, D = Partial<T>, P extends Params = RestClientParams> extends Base<
5+
T,
6+
D,
7+
P
8+
> {
49
request(options: any, params: RestClientParams) {
510
const superagent = this.connection(options.method, options.url)
611
.set(this.options.headers || {})

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ import { ServiceTypes } from './declarations'
1212

1313
describe('Axios REST connector', function () {
1414
const url = 'http://localhost:8889'
15-
const setup = rest(url).axios(axios)
16-
const app = feathers<ServiceTypes>().configure(setup)
15+
const connection = rest(url).axios(axios)
16+
const app = feathers<ServiceTypes>()
17+
.configure(connection)
18+
.use('todos', connection.service('todos'), {
19+
methods: ['get', 'find', 'create', 'patch', 'customMethod']
20+
})
1721
const service = app.service('todos')
1822
let server: Server
1923

20-
service.methods('customMethod')
21-
2224
before(async () => {
2325
server = await createServer().listen(8889)
2426
})
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
import { CustomMethods } from '@feathersjs/feathers'
1+
import { CustomMethod } from '@feathersjs/feathers'
22
import { RestService } from '../src'
33

4+
type Data = { message: string }
5+
type Result = {
6+
data: Data
7+
provider: string
8+
type: string
9+
}
10+
411
export type ServiceTypes = {
5-
todos: RestService & CustomMethods<{ customMethod: any }>
12+
todos: RestService & {
13+
customMethod: CustomMethod<Data, Result>
14+
}
615
}

0 commit comments

Comments
 (0)