Implement GET method for idempotent methods
This commit is contained in:
parent
7edbe354a9
commit
81225b77a8
@ -1,7 +1,7 @@
|
||||
import express, {ErrorRequestHandler} from 'express'
|
||||
import {FunctionPropertyNames} from './types'
|
||||
import {IDEMPOTENT_METHOD_REGEX} from './idempotent'
|
||||
import {IErrorResponse} from './jsonrpc'
|
||||
import {IErrorResponse} from './error'
|
||||
import {ILogger} from '@rondo/common'
|
||||
import {ISuccessResponse} from './jsonrpc'
|
||||
import {NextFunction, Request, Response, Router} from 'express'
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
export type TId = number | string
|
||||
import {ArgumentTypes, FunctionPropertyNames, RetType} from './types'
|
||||
import {isPromise} from './isPromise'
|
||||
import {createError, IErrorWithData} from './error'
|
||||
import {createError, IErrorResponse, IErrorWithData} from './error'
|
||||
|
||||
export const ERROR_PARSE = {
|
||||
code: -32700,
|
||||
@ -43,7 +43,7 @@ export function pick<T, K extends FunctionPropertyNames<T>>(t: T, keys: K[])
|
||||
}, {} as Pick<T, K>)
|
||||
}
|
||||
|
||||
export interface IRequest<M extends string | symbol | number = any, A = any[]> {
|
||||
export interface IRequest<M extends string = any, A = any[]> {
|
||||
jsonrpc: '2.0'
|
||||
id: TId | null
|
||||
method: M
|
||||
@ -57,13 +57,6 @@ export interface ISuccessResponse<T> {
|
||||
error: null
|
||||
}
|
||||
|
||||
export interface IErrorResponse<T> {
|
||||
jsonrpc: '2.0'
|
||||
id: TId | null
|
||||
result: null
|
||||
error: IErrorWithData<T>
|
||||
}
|
||||
|
||||
export type IResponse<T = any> = ISuccessResponse<T> | IErrorResponse<T>
|
||||
|
||||
export function createSuccessResponse<T>(id: number | string, result: T)
|
||||
@ -76,19 +69,6 @@ export function createSuccessResponse<T>(id: number | string, result: T)
|
||||
}
|
||||
}
|
||||
|
||||
export function createErrorResponse<T>(
|
||||
id: number | string | null, error: IErrorWithData<T>)
|
||||
: IErrorResponse<T> {
|
||||
return {
|
||||
jsonrpc: '2.0',
|
||||
id,
|
||||
result: null,
|
||||
error,
|
||||
}
|
||||
}
|
||||
|
||||
export type TGetContext<Context> = (req: Request) => Context
|
||||
|
||||
export const createRpcService =
|
||||
<T, M extends FunctionPropertyNames<T>>(
|
||||
service: T,
|
||||
|
||||
@ -15,6 +15,7 @@ describe('remote', () => {
|
||||
|
||||
interface IService {
|
||||
add(a: number, b: number): number
|
||||
fetchItem(id: number): Promise<string>
|
||||
}
|
||||
const IServiceKeys = keys<IService>()
|
||||
|
||||
@ -22,6 +23,9 @@ describe('remote', () => {
|
||||
add(a: number, b: number) {
|
||||
return a + b
|
||||
}
|
||||
async fetchItem(id: number): Promise<string> {
|
||||
return Promise.resolve('id:' + id)
|
||||
}
|
||||
}
|
||||
|
||||
const service = new Service()
|
||||
@ -52,11 +56,20 @@ describe('remote', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('method invocation', () => {
|
||||
describe('idempotent method invocation (GET)', () => {
|
||||
it('creates a proxy for remote service', async () => {
|
||||
const s = createRemoteClient<IService>(
|
||||
const rpc = createRemoteClient<IService>(
|
||||
baseUrl, '/myService', IServiceKeys)
|
||||
const result = await s.add(3, 7)
|
||||
const result = await rpc.fetchItem(5)
|
||||
expect(result).toBe('id:5')
|
||||
})
|
||||
})
|
||||
|
||||
describe('method invocation (POST)', () => {
|
||||
it('creates a proxy for remote service', async () => {
|
||||
const rpc = createRemoteClient<IService>(
|
||||
baseUrl, '/myService', IServiceKeys)
|
||||
const result = await rpc.add(3, 7)
|
||||
expect(result).toBe(3 + 7)
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,37 +1,51 @@
|
||||
import Axios from 'axios'
|
||||
import {FunctionPropertyNames, TAsyncified} from './types'
|
||||
import {IDEMPOTENT_METHOD_REGEX} from './idempotent'
|
||||
|
||||
export type TRequestIdGenerator<T extends string | number> = () => T
|
||||
|
||||
export const createNumberGenerator = (val: number) => () => ++val
|
||||
export const constantId = (val: string) => () => val
|
||||
|
||||
export function createRemoteClient<T>(
|
||||
baseUrl: string,
|
||||
url: string,
|
||||
methods: Array<FunctionPropertyNames<T>>,
|
||||
getNextRequestId: TRequestIdGenerator<string | number> = constantId('c'),
|
||||
idempotentMethodRegex = IDEMPOTENT_METHOD_REGEX,
|
||||
) {
|
||||
const axios = Axios.create({
|
||||
baseURL: baseUrl,
|
||||
})
|
||||
|
||||
let id = 0
|
||||
async function createRequest(
|
||||
id: string | number | null,
|
||||
method: string,
|
||||
params: any[],
|
||||
) {
|
||||
const reqMethod = IDEMPOTENT_METHOD_REGEX.test(method) ? 'get' : 'post'
|
||||
const payloadKey = reqMethod === 'post' ? 'data' : 'params'
|
||||
|
||||
const response = await axios({
|
||||
method: reqMethod,
|
||||
url,
|
||||
[payloadKey]: {
|
||||
id,
|
||||
jsonrpc: '2.0',
|
||||
method,
|
||||
params,
|
||||
},
|
||||
})
|
||||
if (response.data.error) {
|
||||
// TODO create an actual error
|
||||
throw response.data.error
|
||||
}
|
||||
return response.data.result
|
||||
}
|
||||
|
||||
const service = methods.reduce((obj, method) => {
|
||||
obj[method] = async function makeRequest(...args: any[]) {
|
||||
id++
|
||||
const response = await axios({
|
||||
method: 'post',
|
||||
url,
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
data: {
|
||||
id,
|
||||
jsonrpc: '2.0',
|
||||
method,
|
||||
params: args,
|
||||
},
|
||||
})
|
||||
if (response.data.error) {
|
||||
// TODO create an actual error
|
||||
throw response.data.error
|
||||
}
|
||||
return response.data.result
|
||||
return createRequest(getNextRequestId(), method, args)
|
||||
}
|
||||
return obj
|
||||
}, {} as any)
|
||||
|
||||
@ -10,7 +10,11 @@ type PromisifyReturnType<T> = (...a: ArgumentTypes<T>) =>
|
||||
RetProm<UnwrapHOC<RetType<T>>>
|
||||
|
||||
export type FunctionPropertyNames<T> = {
|
||||
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never
|
||||
[K in keyof T]: K extends string
|
||||
? T[K] extends (...args: any[]) => any
|
||||
? K
|
||||
: never
|
||||
: never
|
||||
}[keyof T]
|
||||
|
||||
export type TAsyncified<T> = {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user