src/util/format.js
/**
* Generates a stringified JSON-RPC request object with appended delimiter.
*
* @function formatRequest
* @memberof Utils.format
* @param {object} request
* @param {string} request.method
* @param {array|object} request.params
* @param {string|number} request.id
* @param {string|number} request.version
* @param {string} request.delimiter
*/
const formatRequest = ({
method, params, id, version, delimiter
}) => {
if (typeof method !== "string") {
throw new TypeError(`${method} must be a string`);
}
const request = {
method
};
// assume 2.0 request unless otherwise specified
if (!version || version !== 1) {
request.jsonrpc = "2.0";
}
if (params && typeof params !== "object" && !Array.isArray(params)) {
throw new TypeError(`${params} must be an object or array`);
} else if (params) {
request.params = params;
}
// assume notification otherwise
if (typeof id !== "undefined") {
request.id = id;
}
return JSON.stringify(request) + delimiter;
};
/**
* Generates a stringified JSON-RPC response object with appended delimiter.
*
* @function formatResponse
* @memberof Utils.format
* @param {object} response
* @param {string} response.method
* @param {string|number} response.id
* @param {string|number} response.jsonrpc
* @param {string} response.delimiter
* @param response.result
*/
const formatResponse = ({
jsonrpc, id, method, result, params, delimiter
}) => {
if (params && result) {
throw new Error("Cannot send response with both params and result");
}
if (method && id) {
throw new Error("Cannot send response with both a method and non-null id");
}
if (method && typeof method !== "string") {
throw new TypeError("Method must be a string");
}
if (params && typeof params !== "object" && !Array.isArray(params)) {
throw new TypeError("Params must be an object or array");
}
const response = {};
if (typeof result !== "undefined") {
response.result = result;
}
if (params) {
response.params = params;
}
if (!jsonrpc || jsonrpc === 1) {
// 1.0 response
response.error = null;
// 1.0 notification
if (!id) {
response.id = null;
}
} else {
// assume 2.0 response, dont include null error and include jsonrpc version
response.jsonrpc = "2.0";
}
if (method) {
response.method = method;
}
if (id) {
response.id = id;
}
return JSON.stringify(response) + delimiter;
};
/**
* Generates a stringified JSON-RPC error object with appended delimiter.
*
* @function formatError
* @memberof Utils.format
* @param {object} error
* @param {string} error.message
* @param {array|object} error.code
* @param {string|number} error.id
* @param {string|number} error.jsonrpc
* @param {string} error.delimiter
* @param {string|object|array} error.data
*/
const formatError = ({
jsonrpc, id, code, message, data, delimiter
}) => {
if (!message) {
throw new Error("Must include message in error response");
}
// we're going to assume a 2.0 response if the version isnt explicitly 1
const response = jsonrpc && jsonrpc !== 1
? {
jsonrpc: "2.0",
error: { code, message },
id
}
: {
result: null,
error: { code, message },
id
};
if (data) {
response.error.data = data;
}
return JSON.stringify(response) + delimiter;
};
/**
* @static
*
*/
module.exports = {
formatRequest,
formatResponse,
formatError
};