Encode JSON-RPC GET request params as JSON
This commit is contained in:
parent
81225b77a8
commit
e2f6c5f798
@ -50,7 +50,7 @@ export function jsonrpc<Context>(
|
|||||||
service: T,
|
service: T,
|
||||||
methods: F[],
|
methods: F[],
|
||||||
) {
|
) {
|
||||||
const callRpcService = createRpcService(service, methods)
|
const rpcService = createRpcService(service, methods)
|
||||||
|
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
@ -76,13 +76,19 @@ export function jsonrpc<Context>(
|
|||||||
})
|
})
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
callRpcService(req.query, getContext(req))
|
const request = {
|
||||||
|
id: req.query.id,
|
||||||
|
jsonrpc: req.query.jsonrpc,
|
||||||
|
method: req.query.method,
|
||||||
|
params: JSON.parse(req.query.params),
|
||||||
|
}
|
||||||
|
rpcService.invoke(request, getContext(req))
|
||||||
.then(response => handleResponse(response, res))
|
.then(response => handleResponse(response, res))
|
||||||
.catch(next)
|
.catch(next)
|
||||||
})
|
})
|
||||||
|
|
||||||
router.post('/', (req, res, next) => {
|
router.post('/', (req, res, next) => {
|
||||||
callRpcService(req.body, getContext(req))
|
rpcService.invoke(req.body, getContext(req))
|
||||||
.then(response => handleResponse(response, res))
|
.then(response => handleResponse(response, res))
|
||||||
.catch(next)
|
.catch(next)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -69,51 +69,57 @@ export function createSuccessResponse<T>(id: number | string, result: T)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createRpcService =
|
export const createRpcService = <T, M extends FunctionPropertyNames<T>>(
|
||||||
<T, M extends FunctionPropertyNames<T>>(
|
service: T,
|
||||||
service: T,
|
methods: M[],
|
||||||
methods: M[],
|
) => {
|
||||||
) => async <Context>(req: IRequest<M, ArgumentTypes<T[M]>>, context: Context)
|
return {
|
||||||
: Promise<ISuccessResponse<RetType<T[M]>> | null> => {
|
async invoke<Context>(
|
||||||
const {id, method, params} = req
|
req: IRequest<M, ArgumentTypes<T[M]>>,
|
||||||
|
context: Context,
|
||||||
|
): Promise<ISuccessResponse<RetType<T[M]>> | null> {
|
||||||
|
const {id, method, params} = req
|
||||||
|
|
||||||
if (
|
if (
|
||||||
req.jsonrpc !== '2.0' ||
|
req.jsonrpc !== '2.0' ||
|
||||||
typeof method !== 'string' ||
|
typeof method !== 'string' ||
|
||||||
!Array.isArray(params)
|
!Array.isArray(params)
|
||||||
) {
|
) {
|
||||||
throw createError(ERROR_INVALID_REQUEST, {
|
console.log(req.jsonrpc, method, params)
|
||||||
id,
|
throw createError(ERROR_INVALID_REQUEST, {
|
||||||
data: null,
|
id,
|
||||||
statusCode: 400,
|
data: null,
|
||||||
})
|
statusCode: 400,
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const isNotification = req.id === null || req.id === undefined
|
const isNotification = req.id === null || req.id === undefined
|
||||||
|
|
||||||
const rpcService = pick(service, methods)
|
const rpcService = pick(service, methods)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!rpcService.hasOwnProperty(method) ||
|
!rpcService.hasOwnProperty(method) ||
|
||||||
typeof rpcService[method] !== 'function'
|
typeof rpcService[method] !== 'function'
|
||||||
) {
|
) {
|
||||||
throw createError(ERROR_METHOD_NOT_FOUND, {
|
throw createError(ERROR_METHOD_NOT_FOUND, {
|
||||||
id,
|
id,
|
||||||
data: null,
|
data: null,
|
||||||
statusCode: 404,
|
statusCode: 404,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let retValue = (rpcService[method] as any)(...params)
|
let retValue = (rpcService[method] as any)(...params)
|
||||||
|
|
||||||
if (typeof retValue === 'function') {
|
if (typeof retValue === 'function') {
|
||||||
retValue = retValue(context)
|
retValue = retValue(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isPromise(retValue) && isNotification) {
|
if (!isPromise(retValue) && isNotification) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
retValue = await retValue
|
retValue = await retValue
|
||||||
return createSuccessResponse(req.id as any, retValue)
|
return createSuccessResponse(req.id as any, retValue)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -15,7 +15,8 @@ describe('remote', () => {
|
|||||||
|
|
||||||
interface IService {
|
interface IService {
|
||||||
add(a: number, b: number): number
|
add(a: number, b: number): number
|
||||||
fetchItem(id: number): Promise<string>
|
fetchItem(obj1: {a: number}, obj2: {b: number})
|
||||||
|
: Promise<{a: number, b: number}>
|
||||||
}
|
}
|
||||||
const IServiceKeys = keys<IService>()
|
const IServiceKeys = keys<IService>()
|
||||||
|
|
||||||
@ -23,8 +24,9 @@ describe('remote', () => {
|
|||||||
add(a: number, b: number) {
|
add(a: number, b: number) {
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
async fetchItem(id: number): Promise<string> {
|
async fetchItem(obj1: {a: number}, obj2: {b: number})
|
||||||
return Promise.resolve('id:' + id)
|
: Promise<{a: number, b: number}> {
|
||||||
|
return Promise.resolve({...obj1, ...obj2})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,8 +62,8 @@ describe('remote', () => {
|
|||||||
it('creates a proxy for remote service', async () => {
|
it('creates a proxy for remote service', async () => {
|
||||||
const rpc = createRemoteClient<IService>(
|
const rpc = createRemoteClient<IService>(
|
||||||
baseUrl, '/myService', IServiceKeys)
|
baseUrl, '/myService', IServiceKeys)
|
||||||
const result = await rpc.fetchItem(5)
|
const result = await rpc.fetchItem({a: 10}, {b: 20})
|
||||||
expect(result).toBe('id:5')
|
expect(result).toEqual({a: 10, b: 20})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,9 @@ export function createRemoteClient<T>(
|
|||||||
id,
|
id,
|
||||||
jsonrpc: '2.0',
|
jsonrpc: '2.0',
|
||||||
method,
|
method,
|
||||||
params,
|
params: reqMethod === 'post'
|
||||||
|
? params
|
||||||
|
: JSON.stringify(params),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (response.data.error) {
|
if (response.data.error) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user