UNPKG

4.84 kBJavaScriptView Raw
1/**
2 * @file Defines the ErrorResponse class.
3 *
4 * @author Luke Chavers <luke@c2cschools.com>
5 * @author Kevin Sanders <kevin@c2cschools.com>
6 * @since 5.0.0
7 * @license See LICENSE.md for details about licensing.
8 * @copyright 2017 C2C Schools, LLC
9 */
10
11"use strict";
12
13const BaseResponse = require( "./BaseResponse" );
14
15/**
16 * This is the base class for all API error responses.
17 *
18 * @memberOf Response
19 * @extends Response.BaseResponse
20 */
21module.exports = class ErrorResponse extends BaseResponse {
22
23 /**
24 * @inheritDoc
25 *
26 * @param {?Error} [cfg.errorObject] - An error object represented in the
27 * response.
28 */
29 _initialize( cfg ) {
30
31 const me = this;
32
33 cfg.isError = true;
34
35 // Call parent
36 super._initialize( cfg );
37
38 // Check for an error object
39 if ( cfg.errorObject !== undefined && cfg.errorObject !== null ) {
40
41 me.addErrorObject( cfg.errorObject );
42 me.setConfigValue( "errorObject", null );
43 }
44 }
45
46 /**
47 * Adds an error object to the response.
48 *
49 * @public
50 * @param {Error} err - The error to add
51 * @returns {void}
52 */
53 addErrorObject( err ) {
54
55 const me = this;
56
57 // Dependencies
58 const TIPE = me.$dep( "tipe" );
59
60 // Get the existing list of errors
61 let errs = me.getConfigValue( "errorObjects", [] );
62
63 // Ensure the list is an array
64 if ( TIPE( errs ) !== "array" ) {
65
66 errs = [];
67 }
68
69 // Add the new error
70 errs.push( err );
71
72 // Persist the list
73 me.setConfigValue( "errorObjects", errs );
74
75 // Do error parsing
76 me._parseErrorObjects();
77 }
78
79 /**
80 * Stores one or more `Error` objects that will be represented in the
81 * response.
82 *
83 * Setting the value of this property will _append_ the error object
84 * collection, and will NOT overwrite it or remove any existing errors.
85 *
86 * @public
87 * @type {Error[]}
88 */
89 get errorObjects() {
90
91 const me = this;
92
93 return me.getConfigValue( "errorObjects", [] );
94 }
95
96 set errorObjects( /** Error[] */ val ) {
97
98 const me = this;
99
100 me.setConfigValue( "errorObjects", val );
101 me._parseErrorObjects();
102 }
103
104 // FIXME: properly documented?
105 set errorObject( val ) {
106
107 const me = this;
108
109 me.addErrorObject( val );
110 }
111
112 /**
113 * The first error in the error object collection, or NULL if no errors
114 * exist within the collection.
115 *
116 * @public
117 * @type {?Error}
118 * @readonly
119 */
120 get firstError() {
121
122 const me = this;
123
124 let errs = me.errorObjects;
125
126 if ( errs[ 0 ] !== undefined ) {
127
128 return errs[ 0 ];
129 }
130
131 return null;
132 }
133
134 /**
135 * Normalizes `Error` objects that are added to the internal error object
136 * collection.
137 *
138 * @private
139 * @returns {void} All modifications are made ByRef.
140 */
141 _parseErrorObjects() {
142
143 const me = this;
144
145 let err = me.firstError;
146
147 if ( err === null || err.statusCode === undefined ) {
148
149 me.statusCode = 500;
150
151 } else {
152
153 me.statusCode = err.statusCode;
154 }
155 }
156
157 /**
158 * Creates a JSON-API compatible scaffold for the response body [object].
159 *
160 * This method extends the `BaseResponse` scaffold by adding the error info.
161 *
162 * @private
163 * @returns {Object} Response body.
164 */
165 _createResponseBody() {
166
167 const me = this;
168
169 let sBody = super._createResponseBody();
170 let desc = me._getErrorDescriptions();
171
172 sBody.errors = desc;
173
174 return sBody;
175 }
176
177 /**
178 * Gets a plain-object representation for ALL of the errors within this
179 * Response's internal error object collection.
180 *
181 * @private
182 * @returns {Object[]} An array of error description objects.
183 */
184 _getErrorDescriptions() {
185
186 const me = this;
187
188 // Dependencies
189 const _ = me.$dep( "lodash" );
190
191 let ret = [];
192 let errs = me.errorObjects;
193
194 _.each( errs, function ( err ) {
195
196 ret.push( me._getOneErrorDescription( err ) );
197 } );
198
199 return ret;
200 }
201
202 /**
203 * Gets a plain-object representation for a provided `Error`.
204 *
205 * @private
206 * @param {Error} err - The error to convert to a plain object.
207 *
208 * @returns {Object} Error description object.
209 */
210 _getOneErrorDescription( err ) {
211
212 const me = this;
213
214 let apiStage = me.context.apiStage;
215
216 let ret = {
217 code : 500,
218 title : "UnknownError",
219 detail : "An unknown error has occurred.",
220 url : "http://developer.c2cschools.com/api/dev/errors/UnknownError.html",
221 };
222
223 if ( err.statusCode !== undefined ) {
224
225 ret.code = err.statusCode;
226 }
227
228 if ( err.jse_cause !== undefined ) {
229
230 ret.title = err.jse_cause.name;
231
232 } else {
233
234 ret.title = err.name;
235 }
236
237 if (
238 ret.title === undefined ||
239 ret.title === null ||
240 ret.title === ""
241 ) {
242
243 ret.title = "UnknownError";
244 }
245
246 // FIXME: apiStage in the URL here breaks validation against testing
247 // data because it will be "mochaDev" for local testing, but something
248 // like "dev" during CI testing.
249
250 ret.detail = err.message;
251 ret.url = "http://developer.c2cschools.com/api/" + apiStage + "/errors/" + ret.title + ".html";
252
253 return ret;
254 }
255};