Http Status codes and the ErrorController
Category: php, Zend Framework

I am working on a project with a growing API. Our responses are all JSON, and we started to handle errors in the API controllers instead of the ErrorController.

To make it more easy I altered the ErrorController to also response in JSON and use the corresponding HTTP status and created a HttpStatusCode class for use within my Zend Framework Project.

<?php
/**
 * HttpStatusCodes
 * */
class API_Model_HttpStatusCode
{
    // 1xx Informational
    const INFORMATIONAL_CONTINUE = 100;
    const INFORMATIONAL_SWITCHING_PROTOCOLS = 101;
    const INFORMATIONAL_PROCESSING = 102;
    const INFORMATIONAL_CHECKPOINT = 103;
    const INFORMATIONAL_REQUEST_URI_TOO_LONG = 122;

    // 2xx Success
    const SUCCESS_OK = 200;
    const SUCCESS_CREATED = 201;
    const SUCCESS_ACCEPTED = 202;
    const SUCCESS_NON_AUTHORITATIVE_INFORMATION = 203;
    const SUCCESS_NO_CONTENT = 204;
    const SUCCESS_RESET_CONTENT = 205;
    const SUCCESS_PARTIAL_CONTENT = 206;
    const SUCCESS_MULTI_STATUS = 207;
    const SUCCESS_IM_USED = 226;

    // 3xx Redirection
    const REDIRECTION_MULTIPLE_CHOICES = 300;
    const REDIRECTION_MOVED_PERMANETLY = 301;
    const REDIRECTION_FOUND = 302;
    const REDIRECTION_SEE_OTHER = 303;
    const REDIRECTION_NOT_MODIFIED = 304;
    const REDIRECTION_USE_PROXY = 305;
    const REDIRECTION_SWITCH_PROXY = 306;
    const REDIRECTION_TEMPORARY_REDIRECT = 307;
    const REDIRECTION_RESUME_INCOMPLETE = 308;

    // 4xx Client Error
    const CLIENT_ERROR_BAD_REQUEST = 400;
    const CLIENT_ERROR_UNAUTHORIZED = 401;
    const CLIENT_ERROR_PAYMENT_REQUIRED = 402;
    const CLIENT_ERROR_FORBIDDEN = 403;
    const CLIENT_ERROR_NOT_FOUND = 404;
    const CLIENT_ERROR_METHOD_NOT_ALLOWED = 405;
    const CLIENT_ERROR_NOT_ACCEPTABLE = 406;
    const CLIENT_ERROR_PROXY_AUTHENTICATION_REQUIRED = 407;
    const CLIENT_ERROR_REQUEST_TIMEOUT = 408;
    const CLIENT_ERROR_CONFLICT = 409;
    const CLIENT_ERROR_GONE = 410;
    const CLIENT_ERROR_LENGHT_REQUIRED = 411;
    const CLIENT_ERROR_PRECONDITION_FAILED = 412;
    const CLIENT_ERROR_REQUEST_ENTITY_TOO_LARGE = 413;
    const CLIENT_ERROR_REQUEST_URI_TOO_LONG = 414;
    const CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE = 415;
    const CLIENT_ERROR_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
    const CLIENT_ERROR_EXPECTATION_FAILED = 417;
    const CLIENT_ERROR_I_AM_A_TEAPOT = 418;
    const CLIENT_ERROR_UNPROCESSABLE_ENTITY = 422;
    const CLIENT_ERROR_LOCKED = 423;
    const CLIENT_ERROR_FAILED_DEPENDENCY = 424;
    const CLIENT_ERROR_UNORDERED_COLLECTION = 425;
    const CLIENT_ERROR_UPGRADE_REQUIRED = 426;
    const CLIENT_ERROR_NO_RESPONSE = 444;
    const CLIENT_ERROR_RETRY_WITH = 449;
    const CLIENT_ERROR_BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS = 450;
    const CLIENT_ERROR_CLIENT_CLOSED_REQUEST = 499;

    // 5xx Server Error
    const SERVER_ERROR_INTERNAL_SERVER_ERROR = 500;
    const SERVER_ERROR_NOT_IMPLEMENTED = 501;
    const SERVER_ERROR_BAD_GATEWAY = 502;
    const SERVER_ERROR_SERVICE_UNAVAILABLE = 503;
    const SERVER_ERROR_GATEWAY_TIMEOUT = 504;
    const SERVER_ERROR_HTTP_VERSION_NOT_SUPPORTED = 505;
    const SERVER_ERROR_VARIANT_ALSO_NEGOTIATES = 506;
    const SERVER_ERROR_INSUFFICIENT_STORAGE = 507;
    const SERVER_ERROR_BANDWITH_LIMIT_EXCEEDED = 509;
    const SERVER_ERROR_NOT_EXTENDED = 510;
    const SERVER_ERROR_NETWORK_READ_TIMEOUT_ERROR = 598;
    const SERVER_ERROR_NETWORK_CONNECT_TIMEOUT_ERROR = 599;
}

<?php
/**
 * Basic error controller
 */
class ErrorController extends Zend_Controller_Action
{
    /**
     * Catches the error. Displays a error page..
     *
     * @return void
     */
    public function errorAction ()
    {
        /** @var Zend_Exception */
        $errors = $this->_getParam('error_handler');
        /* @var $error Zend_Exception */
        $error = $errors->exception;
        switch ($error->getCode()) {
            case API_Model_HttpStatusCode::INFORMATIONAL_CONTINUE:
            case API_Model_HttpStatusCode::INFORMATIONAL_SWITCHING_PROTOCOLS:
            case API_Model_HttpStatusCode::INFORMATIONAL_PROCESSING:
            case API_Model_HttpStatusCode::INFORMATIONAL_CHECKPOINT:
            case API_Model_HttpStatusCode::INFORMATIONAL_REQUEST_URI_TOO_LONG:
            case API_Model_HttpStatusCode::SUCCESS_OK:
            case API_Model_HttpStatusCode::SUCCESS_CREATED:
            case API_Model_HttpStatusCode::SUCCESS_ACCEPTED:
            case API_Model_HttpStatusCode::SUCCESS_NON_AUTHORITATIVE_INFORMATION:
            case API_Model_HttpStatusCode::SUCCESS_NO_CONTENT:
            case API_Model_HttpStatusCode::SUCCESS_RESET_CONTENT:
            case API_Model_HttpStatusCode::SUCCESS_PARTIAL_CONTENT:
            case API_Model_HttpStatusCode::SUCCESS_MULTI_STATUS:
            case API_Model_HttpStatusCode::SUCCESS_IM_USED:
            case API_Model_HttpStatusCode::REDIRECTION_MULTIPLE_CHOICES:
            case API_Model_HttpStatusCode::REDIRECTION_MOVED_PERMANETLY:
            case API_Model_HttpStatusCode::REDIRECTION_FOUND:
            case API_Model_HttpStatusCode::REDIRECTION_SEE_OTHER:
            case API_Model_HttpStatusCode::REDIRECTION_NOT_MODIFIED:
            case API_Model_HttpStatusCode::REDIRECTION_USE_PROXY:
            case API_Model_HttpStatusCode::REDIRECTION_SWITCH_PROXY:
            case API_Model_HttpStatusCode::REDIRECTION_TEMPORARY_REDIRECT:
            case API_Model_HttpStatusCode::REDIRECTION_RESUME_INCOMPLETE:
            case API_Model_HttpStatusCode::CLIENT_ERROR_BAD_REQUEST:
            case API_Model_HttpStatusCode::CLIENT_ERROR_UNAUTHORIZED:
            case API_Model_HttpStatusCode::CLIENT_ERROR_PAYMENT_REQUIRED:
            case API_Model_HttpStatusCode::CLIENT_ERROR_FORBIDDEN:
            case API_Model_HttpStatusCode::CLIENT_ERROR_NOT_FOUND:
            case API_Model_HttpStatusCode::CLIENT_ERROR_METHOD_NOT_ALLOWED:
            case API_Model_HttpStatusCode::CLIENT_ERROR_NOT_ACCEPTABLE:
            case API_Model_HttpStatusCode::CLIENT_ERROR_PROXY_AUTHENTICATION_REQUIRED:
            case API_Model_HttpStatusCode::CLIENT_ERROR_REQUEST_TIMEOUT:
            case API_Model_HttpStatusCode::CLIENT_ERROR_CONFLICT:
            case API_Model_HttpStatusCode::CLIENT_ERROR_GONE:
            case API_Model_HttpStatusCode::CLIENT_ERROR_LENGHT_REQUIRED:
            case API_Model_HttpStatusCode::CLIENT_ERROR_PRECONDITION_FAILED:
            case API_Model_HttpStatusCode::CLIENT_ERROR_REQUEST_ENTITY_TOO_LARGE:
            case API_Model_HttpStatusCode::CLIENT_ERROR_REQUEST_URI_TOO_LONG:
            case API_Model_HttpStatusCode::CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE:
            case API_Model_HttpStatusCode::CLIENT_ERROR_REQUESTED_RANGE_NOT_SATISFIABLE:
            case API_Model_HttpStatusCode::CLIENT_ERROR_EXPECTATION_FAILED:
            case API_Model_HttpStatusCode::CLIENT_ERROR_I_AM_A_TEAPOT:
            case API_Model_HttpStatusCode::CLIENT_ERROR_UNPROCESSABLE_ENTITY:
            case API_Model_HttpStatusCode::CLIENT_ERROR_LOCKED:
            case API_Model_HttpStatusCode::CLIENT_ERROR_FAILED_DEPENDENCY:
            case API_Model_HttpStatusCode::CLIENT_ERROR_UNORDERED_COLLECTION:
            case API_Model_HttpStatusCode::CLIENT_ERROR_UPGRADE_REQUIRED:
            case API_Model_HttpStatusCode::CLIENT_ERROR_NO_RESPONSE:
            case API_Model_HttpStatusCode::CLIENT_ERROR_RETRY_WITH:
            case API_Model_HttpStatusCode::CLIENT_ERROR_BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS:
            case API_Model_HttpStatusCode::CLIENT_ERROR_CLIENT_CLOSED_REQUEST:
            case API_Model_HttpStatusCode::SERVER_ERROR_INTERNAL_SERVER_ERROR:
            case API_Model_HttpStatusCode::SERVER_ERROR_NOT_IMPLEMENTED:
            case API_Model_HttpStatusCode::SERVER_ERROR_BAD_GATEWAY:
            case API_Model_HttpStatusCode::SERVER_ERROR_SERVICE_UNAVAILABLE:
            case API_Model_HttpStatusCode::SERVER_ERROR_GATEWAY_TIMEOUT:
            case API_Model_HttpStatusCode::SERVER_ERROR_HTTP_VERSION_NOT_SUPPORTED:
            case API_Model_HttpStatusCode::SERVER_ERROR_VARIANT_ALSO_NEGOTIATES:
            case API_Model_HttpStatusCode::SERVER_ERROR_INSUFFICIENT_STORAGE:
            case API_Model_HttpStatusCode::SERVER_ERROR_BANDWITH_LIMIT_EXCEEDED:
            case API_Model_HttpStatusCode::SERVER_ERROR_NOT_EXTENDED:
            case API_Model_HttpStatusCode::SERVER_ERROR_NETWORK_READ_TIMEOUT_ERROR:
            case API_Model_HttpStatusCode::SERVER_ERROR_NETWORK_CONNECT_TIMEOUT_ERROR:
                $this->getResponse()->setHttpResponseCode($error->getCode());
                $priority = Zend_Log::NOTICE;
                $this->_helper->json->sendJson( array('Error' => $error->getMessage()));
                break;
            default:

                 switch ($error->getCode()) {
                    case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
                    case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
                    case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                        // 404 error -- controller or action not found
                        $this->getResponse()->setHttpResponseCode(404);
                        $priority = Zend_Log::NOTICE;
                        $this->_helper->json->sendJson(
                        array('Error' => $error->getMessage()));
                        break;
                    default:
                        // application error
                        $this->getResponse()->setHttpResponseCode(500);
                        $priority = Zend_Log::CRIT;
                        $this->_helper->json->sendJson(array('Error' => $error->getMessage()));
                    break;
                 }
        }
    }
}

If you have an exception somewhere just throw a new one, and the ErrorController will handle the rest

throw new Zend_Exception ( "Error connection to database",
   API_Model_HttpStatusCode::SERVER_ERROR_SERVICE_UNAVAILABLE );

Make sure to set in your application.ini

resources.frontController.throwExceptions = 0

Tags: , ,

One Response to “Http Status codes and the ErrorController”

  1. webpatser says:

    updated the errorController to fix a small bug..

Leave a Comment