Skip to content

Commit f852d52

Browse files
author
celer
committed
A few tweaks to the custom error filter
1 parent 5d1d3ae commit f852d52

File tree

4 files changed

+108
-31
lines changed

4 files changed

+108
-31
lines changed

examples/test/app.js

+16
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ UnitTestService.dualComplete=function(input,onComplete){
112112
onComplete(null,true);
113113
}
114114

115+
UnitTestService.customError=function(input,onComplete){
116+
return onComplete("INTERNAL ERROR");
117+
}
118+
115119

116120
Hop.defineModel("UnitTestService",function(model){
117121
model.field("modelFloat").float();
@@ -128,6 +132,7 @@ Hop.defineClass("UnitTestService",UnitTestService,function(api){
128132
api.post("testHeaders","/testHeaders");
129133
api.post("sendHeaders","/sendHeaders");
130134
api.get("dualComplete","/dualComplete");
135+
api.get("customError","/customError");
131136
api.post("testForm","/form/test").optionals("textValue","selectValue","multipleValue","checkbox1","radio1");
132137
api.post("testPost","/ts/").demands("string","number","float","object","date","booleanTrue","booleanFalse","nullValue","modelMinMax","modelArray","modelObject","modelString","modelBool","modelFloat","modelStringArray").inputModel("UnitTestService");
133138
api.get("testGet","/ts/").demands("string","number","float","object","date","booleanTrue","booleanFalse","nullValue","modelMinMax","modelArray","modelObject","modelString","modelBool","modelFloat","modelStringArray").inputModel("UnitTestService");
@@ -136,6 +141,13 @@ Hop.defineClass("UnitTestService",UnitTestService,function(api){
136141
api.post("testPostOptionals","/ts/optionals").optionals("string","number","float","object","date","booleanTrue","booleanFalse","nullValue","modelMinMax","modelArray","modelObject","modelString","modelBool","modelFloat","modelStringArray").inputModel("UnitTestService");
137142
api.get("testGetOptionals","/ts/optionals").optionals("string","number","float","object","date","booleanTrue","booleanFalse","nullValue","modelMinMax","modelArray","modelObject","modelString","modelBool","modelFloat","modelStringArray").inputModel("UnitTestService");
138143
api.put("testPutOptionals","/ts/optionals").optionals("string","number","float","object","date","booleanTrue","booleanFalse","nullValue","modelMinMax","modelArray","modelObject","modelString","modelBool","modelFloat","modelStringArray").inputModel("UnitTestService");
144+
145+
api.errorHandler(function(method,request,input,error,stack){
146+
if(error=="INTERNAL ERROR"){
147+
return "Error";
148+
} else return null;
149+
});
150+
139151
});
140152

141153
function basicTest(method, funcName,test){
@@ -158,6 +170,10 @@ function basicTest(method, funcName,test){
158170
test.do(funcName+"Optionals").with(testValue).outputContains(expectedValue);
159171
}
160172

173+
Hop.defineTestCase("UnitTestService.customError",function(test){
174+
test.do("UnitTestService.customError").with({}).errorContains("Error");
175+
});
176+
161177
Hop.defineTestCase("UnitTestService.sendTemplate",function(test){
162178
test.do("UnitTestService.sendTemplate").with({}).outputContains("<h1>Template Title</h1>").noError();
163179
});

lib/api.js

+88-24
Original file line numberDiff line numberDiff line change
@@ -32,34 +32,44 @@ Hop.log=console.log;
3232
Hop.error=console.error;
3333
Hop.warn=console.warn;
3434

35-
Hop.logResult=function(err,result){
36-
if(err){
37-
var error = new Error();
38-
39-
//This function attempts to provide an easy to read stack trace for results from calls
40-
var lines = error.stack.split("\n");
41-
var stack=[];
42-
var capture=false;
43-
for(var i=lines.length-1;i>0;i--){
44-
var l = lines[i];
45-
var f = (l.replace(/^\s+at\s+([^ ]+).+/,"$1"));
46-
if(f=="Hop_call_preTask"){
47-
capture=true;
48-
}
49-
if(f=="Hop_call_postTask"){
50-
capture=false;
51-
}
52-
if(capture==true && f.indexOf("Hop_call")!=0){
53-
stack.push(l);
54-
}
55-
}
56-
if(stack.length>0){
57-
Hop.error(err+"\n"+stack.join("\n"));
35+
/**
36+
Given a string representation of a stack for a trace made during a call, return a more focused stack trace
37+
38+
This function will attempt to cull a larger stack trace into something more relevant for what went on during
39+
a call.
40+
41+
@param {String} errorStack a stack trace captured from an error
42+
43+
@returns stack a focused stack trace
44+
45+
*/
46+
Hop.callStack=function(errorStack){
47+
var lines = errorStack.split("\n");
48+
var stack=[];
49+
var capture=false;
50+
for(var i=lines.length-1;i>0;i--){
51+
var l = lines[i];
52+
var f = (l.replace(/^\s+at\s+([^ ]+).+/,"$1"));
53+
if(f=="Hop_call_preTask"){
54+
capture=true;
5855
}
56+
if(f=="Hop_call_postTask"){
57+
capture=false;
58+
}
59+
if(capture==true && f.indexOf("Hop_call")!=0){
60+
stack.push(l);
61+
}
62+
}
63+
return stack.join("\n");
64+
}
5965

60-
}
66+
Hop.logCall=function(method,type,err,result){
67+
var error = new Error();
68+
var stack = Hop.callStack(error.stack);
69+
Hop[type](method,err+"\n"+stack);
6170
}
6271

72+
6373
Hop.sendFile=function(file,options){
6474
return new Hop.File(file,options);
6575
}
@@ -439,6 +449,60 @@ Hop.Object.wrap=function(objectName){
439449
}
440450

441451

452+
453+
Hop.Object.prototype.callOnError=function(method,request,input,error,stack){
454+
if(!stack){
455+
var exp = new Error();
456+
var stack = Hop.callStack(exp.stack);
457+
} else {
458+
stack = Hop.callStack(stack);
459+
}
460+
if(this.onError){
461+
var res = this.onError(method,request,input,error,stack);
462+
if(res!==null)
463+
return res;
464+
}
465+
Hop.error(method.getMethod(),":returned an error result of '"+error+"'\n"+stack);
466+
return error;
467+
}
468+
469+
/**
470+
Provide a function that will be called when an error occured for any call in the class
471+
472+
This function can be used to filter error messages. A typical use case would be to have a small
473+
set of allowed error messages, and return a generic error message in all other cases. Or to attach
474+
a unique number to each error and provide details in the console log. This function should return a string
475+
for the desired error string or null if no custom error is returned. This function is not asynchronous.
476+
477+
@param {Function} onError function to be called when an error has occured
478+
@param {Object} onError.method The method call associated with the error
479+
@param {Object} onError.request The request for the call
480+
@param {Object} onError.input The input for the call
481+
@param {String} onError.error The error string
482+
@param {String} onError.stack A stack trace of where the error occured
483+
484+
@example
485+
Hop.defineClass("UserService",function(api){
486+
api.post("update","/user/:userID");
487+
488+
api.errorHandler(function(method,request,input,error,stack){
489+
//If we know what the error is simply return it
490+
if(allowedErrors.contains(error)){
491+
return null;
492+
} else {
493+
//If we don't recognize the error produce a unique ID for it and spit it out in the logs
494+
var id = Date.now();
495+
var err = "Error ("+id+")";
496+
Log.error(method.getName(),request,input,id,error,stack);
497+
return err;
498+
}
499+
});
500+
});
501+
*/
502+
Hop.Object.prototype.errorHandler=function(onError){
503+
this.onError=onError;
504+
}
505+
442506
Hop.Object.prototype.setLocalInterface=function(){
443507
this._localInterface=true;
444508
}

lib/express.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Hop.apiHook=function(basePath,app,options){
9292
Hop.call(obj.name+"."+method.name,input,function(err,result){
9393
var m = obj.name+"."+method.name;
9494
if(called){
95-
Hop.logResult(m+": called onComplete twice");
95+
Hop.logCall(m,"warn","called onComplete twice");
9696
} else {
9797
called=true;
9898
try {
@@ -102,26 +102,23 @@ Hop.apiHook=function(basePath,app,options){
102102
return res.render(template,{ result: result, error: err, request: req});
103103

104104
if(err){
105+
err=obj.callOnError(method,req,input,err);
105106
res.send(500,err);
106-
Hop.logResult(m+": "+err);
107107
} else {
108108
if(result instanceof Hop.File){
109109
result.send(res);
110-
Hop.logResult(null,res);
111110
} else if(result instanceof Hop.Template){
112111
result.send(res);
113-
Hop.logResult(null,res);
114112
} else {
115113
if(result===null || result===undefined){
116114
res.send(404,"Not found");
117115
} else {
118116
res.json(result);
119-
Hop.logResult(null,result);
120117
}
121118
}
122119
}
123120
} catch(e){
124-
Hop.error(e);
121+
Hop.error(e.stack);
125122
}
126123
}
127124
},req);

testresults.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111
#ex3:
1212
Pass 3 Fail 0 100.00%
1313
#test:
14-
Pass 34 Fail 0 100.00%
14+
Pass 35 Fail 0 100.00%
1515
#intro:
1616
Pass 18 Fail 0 100.00%

0 commit comments

Comments
 (0)