Encode JSON-RPC GET request params as JSON

This commit is contained in:
Jerko Steiner 2019-08-04 14:07:25 +07:00
parent 81225b77a8
commit e2f6c5f798
4 changed files with 64 additions and 48 deletions

View File

@ -50,7 +50,7 @@ export function jsonrpc<Context>(
service: T,
methods: F[],
) {
const callRpcService = createRpcService(service, methods)
const rpcService = createRpcService(service, methods)
const router = Router()
@ -76,13 +76,19 @@ export function jsonrpc<Context>(
})
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))
.catch(next)
})
router.post('/', (req, res, next) => {
callRpcService(req.body, getContext(req))
rpcService.invoke(req.body, getContext(req))
.then(response => handleResponse(response, res))
.catch(next)
})

View File

@ -69,51 +69,57 @@ export function createSuccessResponse<T>(id: number | string, result: T)
}
}
export const createRpcService =
<T, M extends FunctionPropertyNames<T>>(
service: T,
methods: M[],
) => async <Context>(req: IRequest<M, ArgumentTypes<T[M]>>, context: Context)
: Promise<ISuccessResponse<RetType<T[M]>> | null> => {
const {id, method, params} = req
export const createRpcService = <T, M extends FunctionPropertyNames<T>>(
service: T,
methods: M[],
) => {
return {
async invoke<Context>(
req: IRequest<M, ArgumentTypes<T[M]>>,
context: Context,
): Promise<ISuccessResponse<RetType<T[M]>> | null> {
const {id, method, params} = req
if (
req.jsonrpc !== '2.0' ||
typeof method !== 'string' ||
!Array.isArray(params)
) {
throw createError(ERROR_INVALID_REQUEST, {
id,
data: null,
statusCode: 400,
})
}
if (
req.jsonrpc !== '2.0' ||
typeof method !== 'string' ||
!Array.isArray(params)
) {
console.log(req.jsonrpc, method, params)
throw createError(ERROR_INVALID_REQUEST, {
id,
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 (
!rpcService.hasOwnProperty(method) ||
typeof rpcService[method] !== 'function'
) {
throw createError(ERROR_METHOD_NOT_FOUND, {
id,
data: null,
statusCode: 404,
})
}
if (
!rpcService.hasOwnProperty(method) ||
typeof rpcService[method] !== 'function'
) {
throw createError(ERROR_METHOD_NOT_FOUND, {
id,
data: null,
statusCode: 404,
})
}
let retValue = (rpcService[method] as any)(...params)
let retValue = (rpcService[method] as any)(...params)
if (typeof retValue === 'function') {
retValue = retValue(context)
}
if (typeof retValue === 'function') {
retValue = retValue(context)
}
if (!isPromise(retValue) && isNotification) {
return null
}
if (!isPromise(retValue) && isNotification) {
return null
}
retValue = await retValue
return createSuccessResponse(req.id as any, retValue)
retValue = await retValue
return createSuccessResponse(req.id as any, retValue)
},
}
}

View File

@ -15,7 +15,8 @@ describe('remote', () => {
interface IService {
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>()
@ -23,8 +24,9 @@ describe('remote', () => {
add(a: number, b: number) {
return a + b
}
async fetchItem(id: number): Promise<string> {
return Promise.resolve('id:' + id)
async fetchItem(obj1: {a: number}, obj2: {b: number})
: Promise<{a: number, b: number}> {
return Promise.resolve({...obj1, ...obj2})
}
}
@ -60,8 +62,8 @@ describe('remote', () => {
it('creates a proxy for remote service', async () => {
const rpc = createRemoteClient<IService>(
baseUrl, '/myService', IServiceKeys)
const result = await rpc.fetchItem(5)
expect(result).toBe('id:5')
const result = await rpc.fetchItem({a: 10}, {b: 20})
expect(result).toEqual({a: 10, b: 20})
})
})

View File

@ -33,7 +33,9 @@ export function createRemoteClient<T>(
id,
jsonrpc: '2.0',
method,
params,
params: reqMethod === 'post'
? params
: JSON.stringify(params),
},
})
if (response.data.error) {