Welcome Guest, Not a member yet? Register   Sign In
how to throw exception that returns 400 HTTP response code
#1

I have some Codeigniter 4 projects where I extend the base controller with my own base controller. I have a function in this base controller that I call from my various autorouted controller methods if I want to be sure the request is a POST request. Sadly, this results in a 500 error code. I'd like to throw an exception to halt further code execution but I want to return 400 to indicate the error is on the client end. Here's the function in my base controller:

PHP Code:
/**
     * If the page request method is not POST, show an error and die
     */
    
protected function post_or_error() {
        if (!
$this->request->is('post')) {
            
// TODO send 400 BAD REQUEST
            
throw new \Exception('BAD REQUEST');
        }
    } 

From some autorouted controller method, I can use it like so:

PHP Code:
    public function form_handler() {
        
$this->post_or_error();
        
// BLAH BLAH
    


The CI4 docs hint this is possible using HTTPExceptionInterface but don't provide any detail at all about how that might be done.

What is considered best practice in this case?
Reply
#2

(This post was last modified: 02-18-2023, 06:40 PM by kenjis.)

Implement an Exception class that implements HTTPExceptionInterface, and set the error code 400.
And throw it.

I think this is not good, but try:
PHP Code:
throw new class ('BAD REQUEST'400) extends \Exception implements \CodeIgniter\Exceptions\HTTPExceptionInterface {}; 
Reply
#3

(02-18-2023, 06:40 PM)kenjis Wrote: Implement an Exception class that implements HTTPExceptionInterface, and set the error code 400.
And throw it.

I think this is not good, but try:
PHP Code:
throw new class ('BAD REQUEST'400) extends \Exception implements \CodeIgniter\Exceptions\HTTPExceptionInterface {}; 

Hmmm thank you for the suggestion. That looks pretty clever but doesn't really look ideal. Perhaps I shouldn't be throwing an exception? I like throwing an exception because I get the debug/trace information when environment is "development" and it responds with a generic WOOPS message when environment is "production." Perhaps there's some way to utilize the Response class? It already has statusCodes defined for all the usual HTTP codes.

I made my own exception class as you suggested. Sadly, I can't just retrieve the standard phrase for each error code from the Response class because that array, while static, is protected. I sorta borrowed from PageNotFoundException:
PHP Code:
<?php
/**
 * CI4 lacks a generic exception to easily throw an exception for the usual HTTP response codes
 * so I cooked up this custom exception class which lets you just specify empty string and
 * the response code and it'll look up the standard phrase for that HTTP code. 
 */

namespace App\Exceptions;

use 
CodeIgniter\Exceptions\HTTPExceptionInterface;

class 
HTTPGenericException extends \OutOfBoundsException implements HTTPExceptionInterface
{
    
    protected static 
$statusCodes = [
            
// 1xx: Informational
            
100 => 'Continue',
            
101 => 'Switching Protocols',
            
102 => 'Processing'// http://www.iana.org/go/rfc2518
            
103 => 'Early Hints'// http://www.ietf.org/rfc/rfc8297.txt
            // 2xx: Success
            
200 => 'OK',
            
201 => 'Created',
            
202 => 'Accepted',
            
203 => 'Non-Authoritative Information'// 1.1
            
204 => 'No Content',
            
205 => 'Reset Content',
            
206 => 'Partial Content',
            
207 => 'Multi-Status'// http://www.iana.org/go/rfc4918
            
208 => 'Already Reported'// http://www.iana.org/go/rfc5842
            
226 => 'IM Used'// 1.1; http://www.ietf.org/rfc/rfc3229.txt
            // 3xx: Redirection
            
300 => 'Multiple Choices',
            
301 => 'Moved Permanently',
            
302 => 'Found'// Formerly 'Moved Temporarily'
            
303 => 'See Other'// 1.1
            
304 => 'Not Modified',
            
305 => 'Use Proxy'// 1.1
            
306 => 'Switch Proxy'// No longer used
            
307 => 'Temporary Redirect'// 1.1
            
308 => 'Permanent Redirect'// 1.1; Experimental; http://www.ietf.org/rfc/rfc7238.txt
            // 4xx: Client error
            
400 => 'Bad Request',
            
401 => 'Unauthorized',
            
402 => 'Payment Required',
            
403 => 'Forbidden',
            
404 => 'Not Found',
            
405 => 'Method Not Allowed',
            
406 => 'Not Acceptable',
            
407 => 'Proxy Authentication Required',
            
408 => 'Request Timeout',
            
409 => 'Conflict',
            
410 => 'Gone',
            
411 => 'Length Required',
            
412 => 'Precondition Failed',
            
413 => 'Content Too Large'// https://www.iana.org/assignments/http-status-codes/http-status-codes.xml
            
414 => 'URI Too Long'// https://www.iana.org/assignments/http-status-codes/http-status-codes.xml
            
415 => 'Unsupported Media Type',
            
416 => 'Requested Range Not Satisfiable',
            
417 => 'Expectation Failed',
            
418 => "I'm a teapot"// April's Fools joke; http://www.ietf.org/rfc/rfc2324.txt
            // 419 (Authentication Timeout) is a non-standard status code with unknown origin
            
421 => 'Misdirected Request'// http://www.iana.org/go/rfc7540 Section 9.1.2
            
422 => 'Unprocessable Content'// https://www.iana.org/assignments/http-status-codes/http-status-codes.xml
            
423 => 'Locked'// http://www.iana.org/go/rfc4918
            
424 => 'Failed Dependency'// http://www.iana.org/go/rfc4918
            
425 => 'Too Early'// https://datatracker.ietf.org/doc/draft-ietf-httpbis-replay/
            
426 => 'Upgrade Required',
            
428 => 'Precondition Required'// 1.1; http://www.ietf.org/rfc/rfc6585.txt
            
429 => 'Too Many Requests'// 1.1; http://www.ietf.org/rfc/rfc6585.txt
            
431 => 'Request Header Fields Too Large'// 1.1; http://www.ietf.org/rfc/rfc6585.txt
            
451 => 'Unavailable For Legal Reasons'// http://tools.ietf.org/html/rfc7725
            
499 => 'Client Closed Request'// http://lxr.nginx.org/source/src/http/ngx_http_request.h#0133
            // 5xx: Server error
            
500 => 'Internal Server Error',
            
501 => 'Not Implemented',
            
502 => 'Bad Gateway',
            
503 => 'Service Unavailable',
            
504 => 'Gateway Timeout',
            
505 => 'HTTP Version Not Supported',
            
506 => 'Variant Also Negotiates'// 1.1; http://www.ietf.org/rfc/rfc2295.txt
            
507 => 'Insufficient Storage'// http://www.iana.org/go/rfc4918
            
508 => 'Loop Detected'// http://www.iana.org/go/rfc5842
            
510 => 'Not Extended'// http://www.ietf.org/rfc/rfc2774.txt
            
511 => 'Network Authentication Required'// http://www.ietf.org/rfc/rfc6585.txt
            
599 => 'Network Connect Timeout Error'// https://httpstatuses.com/599
    
];
    
    
    
/**
     * Customized constructor fetches generic message and, like DebugTraceableTrait, 
     * Tweaks the exception's constructor to assign the file/line to where
     * it is actually raised rather than were it is instantiated.
     */
    
public function __construct(string $message ''int $code 0, ?Throwable $previous null)
    {
    
        if (!
$message) {
            
$message array_key_exists($codeself::$statusCodes) ? self::$statusCodes[$code] : 'Error';
        }
        
        
parent::__construct($message$code$previous);
        
        
$trace $this->getTrace()[0];
        
        if (isset(
$trace['class']) && $trace['class'] === static::class) {
            [
            
'line' => $this->line,
            
'file' => $this->file,
            ] = 
$trace;
        }
    }

Reply
#4

Hi, guys,

I'm using exceptions to define a filter that uses IP restriction on my routes.

I use this method and I get the file error_403.php :
PHP Code:
throw new class ('BAD REQUEST'403) extends \Exception implements \CodeIgniter\Exceptions\HTTPExceptionInterface {};  
but with an entry 200

and if I use :
PHP Code:
throw new \Exception('BAD REQUEST'403); 


I get a 500 header but no 403.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB