1 // Written in D programming language
2 /**
3 * JSON-RPC 2.0 Protocol<br>
4 * 
5 * $(B This module contain JSON-RPC 2.0 errors)
6 *
7 * See_Also:
8 *    $(LINK http://www.jsonrpc.org/specification)
9 *
10 * Copyright: © 2014 DSoftOut
11 * License: Subject to the terms of the MIT license, as written in the included LICENSE file.
12 * Authors: Zaramzan <shamyan.roman@gmail.com>
13 */
14 module json_rpc.error;
15 
16 import std.exception;
17 
18 import vibe.data.bson;
19 
20 import util;
21 
22 /**
23 * Contains JSON-RPC 2.0 error codes
24 * 
25 * Authors: Zaramzan <shamyan.roman@gmail.com>
26 */
27 enum RPC_ERROR_CODE:int
28 {
29 	NONE,
30 	
31 	PARSE_ERROR = -32700,
32 	
33 	INVALID_REQUEST = -32600,
34 	
35 	METHOD_NOT_FOUND = -32601,
36 	
37 	INVALID_PARAMS = -32602,
38 	
39 	INTERNAL_ERROR = -32603,
40 	
41 	SERVER_ERROR = -32000,
42 	
43 	SERVER_ERROR_EXT = -32099
44 }
45 
46 /// Supported JSON-RPC protocol version
47 enum RPC_VERSION = "2.0";
48 
49 /**
50 * Struct describes JSON-RPC 2.0 error object which used in RpcRequest
51 *
52 * Example
53 * ------
54 *  auto err1 = RpcError(bson);
55 *  auto err2 = RpcError(RPC_ERROR_CODE.INVALID_PARAMS, "Invalid params");
56 *  auto err3 = RpcError(RPC_ERROR_CODE.INVALID_PARAMS, "mycustommessage");
57 *  auto err4 = RpcError(RPC_ERROR_CODE.INVALID_PARAMS, "Invalid params", erroData); 
58 *  auto err5 = RpcError(new RpcInvalidParams());
59 *
60 *  //toJson
61 *  err2.toJson(); 
62 * ------ 
63 * 
64 * Authors: Zaramzan <shamyan.roman@gmail.com>
65 */
66 struct RpcError
67 {
68 	@required
69 	string message;
70 	
71 	@required
72 	int code;
73 	
74 	@possible
75 	Json data = Json(null);
76 	
77 	this(in Bson bson)
78 	{
79 		this = tryEx!(RpcInternalError, deserializeFromJson!RpcError)(bson.toJson);
80 	}
81 	
82 	this(RPC_ERROR_CODE code, string message)
83 	{
84 		this.code = code;
85 		this.message = message;
86 	}
87 	
88 	this (RPC_ERROR_CODE code, string message, Json errorData)
89 	{
90 		this.data = errorData;
91 		
92 		this(code, message);
93 	}
94 	
95 	this(RpcException ex)
96 	{
97 		this(ex.code, ex.msg);
98 	}
99 	
100 	Json toJson()
101 	{
102 		Json ret = Json.emptyObject;
103 		
104 		ret.code = code;
105 		
106 		ret.message = message;
107 		
108 		if (data.type != Json.Type.null_)
109 		{
110 			ret.data = data;
111 		}
112 		
113 		return ret;
114 	}
115 }
116 
117 
118 /// Super class for all JSON-RPC exceptions
119 class RpcException:Exception
120 {
121 	RPC_ERROR_CODE code;
122 	
123 	@safe pure nothrow this(string msg = "", string file = __FILE__, size_t line = __LINE__, Throwable next = null)
124 	{
125 		super(msg, file, line, next); 
126 	}
127 
128 }
129 
130 class RpcParseError: RpcException
131 {	
132 	@safe pure nothrow this(string msg = "", string file = __FILE__, size_t line = __LINE__)
133 	{
134 		code = RPC_ERROR_CODE.PARSE_ERROR;
135 		
136 		msg = "Parse error. " ~ msg;
137 		
138 		super(msg, file, line); 
139 	}
140 }
141 
142 class RpcInvalidRequest: RpcException
143 {	
144 	@safe pure nothrow this(string msg = "", string file = __FILE__, size_t line = __LINE__)
145 	{
146 		code = RPC_ERROR_CODE.INVALID_REQUEST;
147 		
148 		msg = "Invalid request. " ~ msg;
149 		
150 		super(msg, file, line); 
151 	}
152 }
153 
154 class RpcMethodNotFound: RpcException
155 {
156 	@safe pure nothrow this(string msg = "", string file = __FILE__, size_t line = __LINE__)
157 	{
158 		code = RPC_ERROR_CODE.METHOD_NOT_FOUND;
159 		
160 		msg = "Method not found. " ~ msg;
161 		
162 		super(msg, file, line);
163 	}
164 }
165 
166 class RpcInvalidParams: RpcException
167 {	
168 	@safe pure nothrow this(string msg = "", string file = __FILE__, size_t line = __LINE__)
169 	{
170 		code = RPC_ERROR_CODE.INVALID_PARAMS;
171 		
172 		msg = "Invalid params. " ~ msg;
173 		
174 		super(msg, file, line); 
175 	}
176 }
177 
178 class RpcInternalError: RpcException
179 {
180 	@safe pure nothrow this(string msg = "", string file = __FILE__, size_t line = __LINE__)
181 	{
182 		code = RPC_ERROR_CODE.INTERNAL_ERROR;
183 		
184 		msg = "Internal error. " ~ msg;
185 		
186 		super(msg, file, line);
187 	}
188 }
189 
190 class RpcServerError: RpcException
191 {
192 	@safe pure nothrow this(string msg = "", string file = __FILE__, size_t line = __LINE__)
193 	{
194 		code = RPC_ERROR_CODE.SERVER_ERROR;
195 		
196 		msg = "Server error. " ~ msg;
197 		
198 		super(msg, file, line);
199 	}
200 }
201 
202 unittest
203 {
204 	import vibe.data.bson;
205 	import vibe.data.json;
206 	
207 	auto code = cast(int) RPC_ERROR_CODE.METHOD_NOT_FOUND;
208 	auto message = "METHOD NOT FOUND";
209 	
210 	auto error1 = RpcError(Bson(["code":Bson(code),"message": Bson(message)])).toJson(); 
211 	
212 	auto error2 = RpcError(cast(RPC_ERROR_CODE)code, message).toJson();
213 	
214 	auto error = Json.emptyObject;
215 	error.code = code;
216 	error.message = message; 
217 	
218 	assert(error == error1, "RpcError unittest failed");
219 	assert(error == error2, "RpcError unittest failed");
220 }