Javascript for error handling in api ?

Not applicable

I need to use a javascript for generic error handling say for different http error codes such as 404,500,501.... I will attach this policy for every API I build. Has anyone implemented the same if yes can you please share sample javascript.

Or, is there any other better way to do error handling.

Thanks in advance

0 2 738
2 REPLIES 2

alan
New Member

Not 100% sure, but I'm assuming you are trying to do some sort of logging of errors based on the type of http code. If that's the case, you might want to checkout the Javascript SDK since it has out of box monitoring of all errors coming back from the server side:

http://docs.apigee.com/app-services/content/app-monitoring

If you want to do it yourself, you can use monkeypatching to generically wrap httpclient to catch all errors. Checkout the code if you want to learn more about monkey patching.

https://github.com/apigee/apigee-javascript-sdk

Not applicable

Here is a genericized example of a error translation routine - intended to ensure that we provide sufficient, but not too much detail to the consumer in error cases, that the errors are consistent regardless of the upstream target, and translate status codes that are semantically inconsistent with the overall API:

var targetName = context.getVariable("route.target");

if (targetName !== "foo") 
{
    var originalResponse = context.getVariable("message.content");
    var statusCode = context.getVariable("message.status.code");
    var environmentName = context.getVariable("environment.name");
    var contentType = context.getVariable("message.header.Content-Type");
    var flowName = context.getVariable("current.flow.name");
    var proxyPathSuffix = context.getVariable("proxy.pathsuffix");
    var result = {};
    var faultName =  context.getVariable("apigee.edge.execution.fault_policy_name");

    var errorCode = proxyPathSuffix + "." + targetName + "." + flowName + "." + errorStep + "." + statusCode;


    switch (statusCode) {
        case 200:
            break;
        case 400:
            if (/xml/.test(contentType))
                result = {
                    fault: {
                        detail: {
                            message: "One or more request parameters is invalid or missing."
                        },
                        faultstring: "Bad Request"
                    }
                };
            else
                result = {
                    fault: {
                        detail: {
                            message: "The request was not recognized by the server."
                        },
                        faultstring: "Bad Request"
                    }
                };
            break;


            case 401:
            if (context.getVariable("error.auth.401_auth_expired") || originalResponse.indexOf("ENotAuthorized") > -1)
                result = {
                    fault: {
                        detail: {
                            message: "Authorization Expired"
                        },
                        faultstring: "Unauthorized"
                    }
                };
            else if (originalResponse.indexOf("oauth.v2.InvalidApiKey") > -1)
                result = {
                    fault: {
                        detail: {
                            errorcode: "oauth.v2.InvalidApiKey"
                        },
                        faultstring: "Invalid ApiKey"
                    }
                };
            else if (context.getVariable("error.auth.401_auth_invalidtoken"))
                result = {
                    fault: {
                        detail: {
                            message: "Invalid Authorization Token"
                        },
                        faultstring: "Unauthorized"
                    }
                };
            else if (context.getVariable("error.auth.401_auth_insufficientscope"))
                result = {
                    fault: {
                        detail: {
                            message: "Insufficient Scope"
                        },
                        faultstring: "Unauthorized"
                    }
                };
            else {
                //default unauthorized case
                result = {
                    fault: {
                        detail: {
                            message: "Unauthorized"
                        },
                        faultstring: "Unauthorized"
                    }
                };
            }
            break;


        case 404:
            result = {
                fault: {
                    detail: {
                        message: "The requested resource was not found."
                    },
                    faultstring: "Resource Not Found"
                }
            };
            break;


        case 409:
            result = {
                fault: {
                    detail: {
                        message: "Access Control: FOO_MESSAGE"
                    },
                    faultstring: "Conflict"
                }
            };
            break;


        case 500:
            if (originalResponse.indexOf("ResponseCode 404") > -1) {
                result = {
                    fault: {
                        detail: {
                            message: "The requested resource was not found."
                        },
                        faultstring: "Resource Not Found"
                    }
                };
                context.setVariable("message.status.code", 404);
                statusCode=404;
            }
            else
                result = {
                    fault: {
                        detail: {
                            message: "The server encountered an error while attempting to fulfill the request."
                        },
                        faultstring: "Internal Server Error"
                    }
                };
            break;
        default:
            result = {
                fault: {
                    detail: {
                        message: "Error."
                    },
                    faultstring: "Error"
                }
            };


    }




    if (/somepath/.test(context.getVariable("proxy.pathsuffix"))) {
        context.setVariable("message.header.Access-Control-Allow-Origin", "*");
        context.setVariable("message.header.Access-Control-Allow-Headers", "origin, x-requested-with, accept, authorization, authorization2, X-Client-Session-ID,Content-Type");
        context.setVariable("message.header.Access-Control-Max-Age", "86400");
        context.setVariable("message.header.Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
    }


    if (statusCode !== 200) {
        if (originalResponse === "") {
            result.fault.detail.debug = {};
            result.fault.detail.debug.originalResponse = "OriginalResponse was an empty string.";
        }
        else {
            //the original response may already be stringified
            //if so we need to expand it
            //this is expensive (if the object is already an object) so we only do it for the two environments
            try {
                originalResponse = JSON.parse(originalResponse);
                extractFromOriginalResponse(originalResponse);
            } catch (e) {}

        }
    }

context.setVariable("message.header.Content-Type", "application/json; charset=utf-8");


function extractFromOriginalResponse(originalResponse) {
    if(originalResponse.messages && originalResponse.messages.infos) {
        result.fault.detail.code = originalResponse.messages.infos[0].code;
        result.fault.detail.message = "Access Control: " + originalResponse.messages.infos[0].decision;
    }
    if(originalResponse.obligations){
        result.fault.detail.obligations = originalResponse.obligations;
    }
    if(originalResponse.decision) {
        result.fault.detail.message = "Access Control: " + originalResponse.decision;
    }


    if(originalResponse.Error && originalResponse.Error.Message){
        result.fault.detail.message = originalResponse.Error.Message;
    }


    if(originalResponse.returnString && originalResponse.returnString.content){
        result.fault.detail.message = originalResponse.returnString.content;
    }

    if(originalResponse.fault && originalResponse.fault.detail.message){
        result.fault.detail.message = originalResponse.fault.detail.message;
    }
    else if (originalResponse.fault && originalResponse.fault.faultstring){
        result.fault.detail.message = originalResponse.fault.faultstring;
    }
}

These are not trivial to implement and may well be something that can be replaced with a policy based approach using Fault Handling and AssignMessage policies. In this customers case having one place to go to edit the messaging, the ability to unit test a single javascript function, offset the convenience of doing this entirely with policies.