Skip to content

Commit 8822811

Browse files
committed
Improved error handling and execution result rendering.
1 parent 5429369 commit 8822811

File tree

3 files changed

+97
-72
lines changed

3 files changed

+97
-72
lines changed

Action.php

Lines changed: 82 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace georgique\yii2\jsonrpc;
44

55
use yii\base\InvalidRouteException;
6+
use yii\base\UserException;
67
use yii\helpers\Json;
78

89
/**
@@ -20,19 +21,19 @@ class Action extends \yii\base\Action {
2021
* Parses json body.
2122
* @param $rawBody
2223
* @return array
23-
* @throws Exception
24+
* @throws JsonRpcException
2425
*/
2526
public function parseJsonRpcBody($rawBody) {
2627
try {
2728
$parameters = Json::decode($rawBody, false);
2829
if (!$parameters) {
29-
throw new Exception('Could not parse JSON-RPC request body - empty result.', JSON_RPC_ERROR_REQUEST_INVALID);
30+
throw new JsonRpcException('Could not parse JSON-RPC request body - empty result.', JSON_RPC_ERROR_REQUEST_INVALID);
3031
}
3132

3233
return $parameters;
3334
}
34-
catch (Exception $e) {
35-
throw new Exception('Could not parse JSON-RPC request.', JSON_RPC_ERROR_PARSE);
35+
catch (JsonRpcException $e) {
36+
throw new JsonRpcException('Could not parse JSON-RPC request.', JSON_RPC_ERROR_PARSE, $e);
3637
}
3738
}
3839

@@ -43,7 +44,7 @@ public function parseJsonRpcBody($rawBody) {
4344
* @return bool|string
4445
*/
4546
public function parseMethod($method) {
46-
if (!preg_match('/^[\d\w_.]+$/', $method)) {
47+
if (!preg_match('/^[\d\w_\-.]+$/', $method)) {
4748
return false;
4849
}
4950

@@ -60,16 +61,16 @@ public function parseMethod($method) {
6061
* Parses request (parsed JSON object) and prepares JsonRpcRequest object.
6162
* @param $request
6263
* @return JsonRpcRequest
63-
* @throws Exception
64+
* @throws JsonRpcException
6465
* @throws \yii\base\InvalidConfigException
6566
*/
6667
public function parseRequest($request) {
6768
if (!isset($request->jsonrpc) || $request->jsonrpc !== '2.0') {
68-
throw new Exception("The JSON sent is not a correct JSON-RPC request - missing or incorrect version.", JSON_RPC_ERROR_REQUEST_INVALID);
69+
throw new JsonRpcException("The JSON sent is not a correct JSON-RPC request - missing or incorrect version.", JSON_RPC_ERROR_REQUEST_INVALID);
6970
}
7071

7172
if (!isset($request->method) || !is_string($request->method) || (!$route = $this->parseMethod($request->method))) {
72-
throw new Exception("The JSON sent is not a correct JSON-RPC request - missing or incorrect method.", JSON_RPC_ERROR_REQUEST_INVALID);
73+
throw new JsonRpcException("The JSON sent is not a correct JSON-RPC request - missing or incorrect method.", JSON_RPC_ERROR_REQUEST_INVALID);
7374
}
7475

7576
$params = null;
@@ -79,7 +80,7 @@ public function parseRequest($request) {
7980

8081
if (!isset($request->id)) {
8182
if (!is_int($request->id) && !ctype_digit($request->id)) {
82-
throw new Exception("The JSON sent is not a correct JSON-RPC request - incorrect id.", JSON_RPC_ERROR_INVALID_REQUEST);
83+
throw new JsonRpcException("The JSON sent is not a correct JSON-RPC request - incorrect id.", JSON_RPC_ERROR_REQUEST_INVALID);
8384
}
8485
}
8586

@@ -95,7 +96,7 @@ public function parseRequest($request) {
9596
* Parses JSON to an array of JsonRpcRequest.
9697
* @param $params
9798
* @return JsonRpcRequest[]
98-
* @throws Exception
99+
* @throws JsonRpcException
99100
*/
100101
public function parseRequests($params) {
101102
if (is_object($params)) {
@@ -109,29 +110,22 @@ public function parseRequests($params) {
109110
$result = $this->parseRequest($request);
110111
}
111112
catch (\Exception $exception) {
112-
if ($exception instanceof Exception) {
113-
if (isset($request->id) && is_string($request->id) || is_int($request->id)) {
114-
$exception->id = $request->id;
115-
}
116-
$result = $exception;
117-
}
118-
else {
119-
$result = new Exception("Error happened during request parsing.", JSON_RPC_ERROR_INTERNAL);
120-
$result->data['exception'] = $exception->getMessage();
121-
}
113+
$result = ($exception instanceof JsonRpcException)
114+
? $exception
115+
: new JsonRpcException("Error happened during request parsing.", JSON_RPC_ERROR_INTERNAL, $exception);
122116
}
123117
$results[] = $result;
124118
}
125119
return $results;
126120
}
127121

128-
throw new Exception("The JSON sent is not a correct JSON-RPC request.", JSON_RPC_ERROR_INVALID_REQUEST);
122+
throw new JsonRpcException("The JSON sent is not a correct JSON-RPC request.", JSON_RPC_ERROR_REQUEST_INVALID);
129123
}
130124

131125
/**
132126
* Executes JSON-RPC request by route.
133127
* @param JsonRpcRequest $request
134-
* @return Exception|mixed
128+
* @return JsonRpcException|mixed
135129
*/
136130
public function executeRequest($request) {
137131
$route = $request->route;
@@ -143,16 +137,14 @@ public function executeRequest($request) {
143137
}
144138
catch (\Exception $exception) {
145139
if ($exception instanceof InvalidRouteException) {
146-
$result = new Exception('Method not found.', JSON_RPC_ERROR_METHOD_NOT_FOUND);
147-
$result->data['message'] = $exception->getMessage();
140+
$result = new JsonRpcException('Method not found.', JSON_RPC_ERROR_METHOD_NOT_FOUND, $exception);
148141
return $result;
149142
}
150-
else if ($exception instanceof Exception) {
143+
else if ($exception instanceof JsonRpcException) {
151144
return $exception;
152145
}
153146
else {
154-
$result = new Exception('Internal error.', JSON_RPC_ERROR_INTERNAL);
155-
$result->data['message'] = $exception->getMessage();
147+
$result = new JsonRpcException('Internal error.', JSON_RPC_ERROR_INTERNAL, $exception);
156148
return $result;
157149
}
158150
}
@@ -167,31 +159,73 @@ public function runWithParams($params)
167159

168160
$response = [];
169161
foreach ($requestObjects as $request) {
170-
if ($request instanceof Exception) {
171-
$response[] = [
172-
'jsonrpc' => '2.0',
173-
'error' => $request->toJsonRpcFormat(),
174-
'id' => $request->id
162+
$executionResult = $this->executeRequest($request);
163+
$renderMethod = ($executionResult instanceof \Exception) ? 'renderError' : 'renderSuccess';
164+
$response[] = $this->$renderMethod($executionResult, $request->id);
165+
}
166+
167+
return (sizeof($response) == 1) ? array_shift($response) : $response;
168+
}
169+
170+
/**
171+
* Renders exception.
172+
* @param \Exception $exception
173+
* @return array
174+
*/
175+
protected function renderException($exception) {
176+
$result = [
177+
'code' => $exception->getCode(),
178+
'message' => $exception->getMessage(),
179+
];
180+
181+
if (YII_DEBUG) {
182+
$result['data'] = [
183+
'type' => get_class($exception)
184+
];
185+
if (!$exception instanceof UserException) {
186+
$result['data'] += [
187+
'file' => $exception->getFile(),
188+
'line' => $exception->getLine(),
189+
'stack-trace' => explode("\n", $exception->getTraceAsString())
175190
];
176-
}
177-
else {
178-
$executionResult = $this->executeRequest($request);
179-
if ($executionResult instanceof Exception) {
180-
$response[] = [
181-
'jsonrpc' => '2.0',
182-
'error' => $executionResult->toJsonRpcFormat(),
183-
'id' => $request->id
184-
];
185-
} else {
186-
$response[] = [
187-
'jsonrpc' => '2.0',
188-
'result' => $executionResult,
189-
'id' => $request->id
190-
];
191+
192+
if ($exception instanceof \yii\db\Exception) {
193+
$result['data']['error-info'] = $exception->errorInfo;
191194
}
192195
}
193196
}
197+
if (($prev = $exception->getPrevious()) !== null) {
198+
$result['data']['previous'] = $this->renderException($prev);
199+
}
194200

195-
return (sizeof($response) == 1) ? array_shift($response) : $response;
201+
return $result;
202+
}
203+
204+
/**
205+
* Renders error response.
206+
* @param $data
207+
* @param null $id
208+
* @return array
209+
*/
210+
protected function renderError($data, $id = null) {
211+
return [
212+
'jsonrpc' => '2.0',
213+
'error' => ($data instanceof \Exception) ? $this->renderException($data) : $data,
214+
'id' => $id,
215+
];
216+
}
217+
218+
/**
219+
* Renders success response.
220+
* @param $data
221+
* @param null $id
222+
* @return array
223+
*/
224+
protected function renderSuccess($data, $id = null) {
225+
return [
226+
'jsonrpc' => '2.0',
227+
'result' => $data,
228+
'id' => $id
229+
];
196230
}
197231
}

ErrorHandler.php

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
/**
1010
* Class ErrorHandler
1111
* This class is supposed to catch any unhandled errors and format them into JSON-RPC response.
12-
* @autho George Shestayev [email protected]
12+
* @author George Shestayev [email protected]
1313
* @package georgique\yii2\jsonrpc
1414
*/
1515
class ErrorHandler extends \yii\base\ErrorHandler
@@ -45,21 +45,25 @@ protected function renderException($exception)
4545
*/
4646
protected function convertExceptionToArray($exception)
4747
{
48-
if (!YII_DEBUG && !$exception instanceof Exception) {
49-
$exception = new Exception('Internal error', JSON_RPC_ERROR_INTERNAL);
48+
if (!YII_DEBUG && !$exception instanceof JsonRpcException) {
49+
$exception = new JsonRpcException('Internal error.', JSON_RPC_ERROR_INTERNAL);
5050
}
5151

5252
$errorArray = [
5353
'code' => $exception->getCode(),
5454
'message' => $exception->getMessage(),
55-
'data' => []
5655
];
5756
if (YII_DEBUG) {
58-
$errorArray['data']['type'] = get_class($exception);
57+
$errorArray['data'] = [
58+
'type' => get_class($exception)
59+
];
5960
if (!$exception instanceof UserException) {
60-
$errorArray['data']['file'] = $exception->getFile();
61-
$errorArray['data']['line'] = $exception->getLine();
62-
$errorArray['data']['stack-trace'] = explode("\n", $exception->getTraceAsString());
61+
$errorArray['data'] += [
62+
'file' => $exception->getFile(),
63+
'line' => $exception->getLine(),
64+
'stack-trace' => explode("\n", $exception->getTraceAsString())
65+
];
66+
6367
if ($exception instanceof \yii\db\Exception) {
6468
$errorArray['data']['error-info'] = $exception->errorInfo;
6569
}
@@ -72,7 +76,7 @@ protected function convertExceptionToArray($exception)
7276
return [
7377
'jsonrpc' => '2.0',
7478
'error' => $errorArray,
75-
'id' => ($exception instanceof Exception) ? $exception->id : null,
79+
'id' => ($exception instanceof JsonRpcException) ? $exception->id : null,
7680
];
7781
}
7882

Exception.php renamed to JsonRpcException.php

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@
33
namespace georgique\yii2\jsonrpc;
44

55
/**
6-
* Class Exception
6+
* Class JsonRpcException
77
* Basic exception class for handling JSON-RPC errors.
88
* @author George Shestayev [email protected]
99
* @package georgique\yii2\jsonrpc
1010
*/
11-
class Exception extends \yii\base\Exception {
12-
13-
/* @var int Used for identifying request in a batch */
14-
public $id;
11+
class JsonRpcException extends \yii\base\Exception {
1512

1613
/**
1714
* @return string the user-friendly name of this exception
@@ -44,14 +41,4 @@ public function getName()
4441
}
4542
}
4643

47-
public function toJsonRpcFormat() {
48-
return [
49-
'code' => $this->getCode(),
50-
'message' => $this->getMessage(),
51-
'data' => [
52-
// TODO Include some useful data here
53-
]
54-
];
55-
}
56-
5744
}

0 commit comments

Comments
 (0)