import qs from 'qs' import { Params, Id, Query, NullableId, ServiceInterface } from '@feathersjs/feathers' import { BadRequest, Unavailable, convert } from '@feathersjs/errors' import { _, stripSlashes } from '@feathersjs/commons' function toError(error: Error & { code: string }) { if (error.code === 'ECONNREFUSED') { throw new Unavailable(error.message, _.pick(error, 'address', 'port', 'config')) } throw convert(error) } export interface RestClientParams extends Params { connection?: any } interface RestClientSettings { name: string base: string connection: any options: any } export abstract class Base< T = any, D = Partial, P extends Params = RestClientParams > implements ServiceInterface { name: string base: string connection: any options: any constructor(settings: RestClientSettings) { this.name = stripSlashes(settings.name) this.options = settings.options this.connection = settings.connection this.base = `${settings.base}/${this.name}` } makeUrl(query: Query, id?: string | number | null, route?: { [key: string]: string }) { let url = this.base if (route) { Object.keys(route).forEach((key) => { url = url.replace(`:${key}`, route[key]) }) } query = query || {} if (typeof id !== 'undefined' && id !== null) { url += `/${encodeURIComponent(id)}` } return url + this.getQuery(query) } getQuery(query: Query) { if (Object.keys(query).length !== 0) { const queryString = qs.stringify(query) return `?${queryString}` } return '' } abstract request(options: any, params: P): any methods(this: any, ...names: string[]) { names.forEach((method) => { const _method = `_${method}` this[_method] = function (data: any, params: Params = {}) { return this.request( { body: data, url: this.makeUrl(params.query, null, params.route), method: 'POST', headers: Object.assign( { 'Content-Type': 'application/json', 'X-Service-Method': method }, params.headers ) }, params ).catch(toError) } this[method] = function (data: any, params: Params = {}) { return this[_method](data, params) } }) return this } _find(params?: P) { return this.request( { url: this.makeUrl(params.query, null, params.route), method: 'GET', headers: Object.assign({}, params.headers) }, params ).catch(toError) } find(params?: P) { return this._find(params) } _get(id: Id, params?: P) { if (id === undefined || id === '') { return Promise.reject(new BadRequest('id for .get is required')) } return this.request( { url: this.makeUrl(params.query, id, params.route), method: 'GET', headers: Object.assign({}, params.headers) }, params ).catch(toError) } get(id: Id, params?: P) { return this._get(id, params) } _create(data: D, params?: P) { return this.request( { url: this.makeUrl(params.query, null, params.route), body: data, method: 'POST', headers: Object.assign({ 'Content-Type': 'application/json' }, params.headers) }, params ).catch(toError) } create(data: D, params?: P) { return this._create(data, params) } _update(id: NullableId, data: D, params?: P) { if (id === undefined || id === '') { return Promise.reject(new BadRequest('id for .update is required')) } return this.request( { url: this.makeUrl(params.query, id, params.route), body: data, method: 'PUT', headers: Object.assign({ 'Content-Type': 'application/json' }, params.headers) }, params ).catch(toError) } update(id: NullableId, data: D, params?: P) { return this._update(id, data, params) } _patch(id: NullableId, data: D, params?: P) { if (id === undefined || id === '') { return Promise.reject(new BadRequest('id for .patch is required')) } return this.request( { url: this.makeUrl(params.query, id, params.route), body: data, method: 'PATCH', headers: Object.assign({ 'Content-Type': 'application/json' }, params.headers) }, params ).catch(toError) } patch(id: NullableId, data: D, params?: P) { return this._patch(id, data, params) } _remove(id: NullableId, params?: P) { if (id === undefined || id === '') { return Promise.reject(new BadRequest('id for .remove is required')) } return this.request( { url: this.makeUrl(params.query, id, params.route), method: 'DELETE', headers: Object.assign({}, params.headers) }, params ).catch(toError) } remove(id: NullableId, params?: P) { return this._remove(id, params) } }