| 
1 |  | -# Exceptions [WIP]  | 
 | 1 | +# Exceptions  | 
2 | 2 | 
 
  | 
3 |  | -https://github.com/dotkernel/api/pull/269/files#  | 
 | 3 | +## What are exceptions?  | 
4 | 4 | 
 
  | 
5 |  | -src/App/src/Handler/ResponseTrait.php  | 
 | 5 | +Exceptions are a powerful mechanism for handling errors and other exceptional conditions that may occur during the execution of a script.  | 
 | 6 | +They provide a way to manage errors in a structured and controlled manner, separating error-handling code from regular code.  | 
 | 7 | + | 
 | 8 | +## How we use exceptions?  | 
 | 9 | + | 
 | 10 | +When it comes to handling exceptions, DotKernel API relies on the usage of easy-to-understand, problem-specific exceptions.  | 
 | 11 | + | 
 | 12 | +Ou-of-the-box we provide the following custom exceptions:  | 
 | 13 | + | 
 | 14 | +* `BadRequestException` thrown when:  | 
 | 15 | + | 
 | 16 | +  1. client tries to create/update resource, but the data from the request is invalid/incomplete (example: client tries to create an account, but does not send the required `identity` field)  | 
 | 17 | + | 
 | 18 | +* `ConflictException` thrown when:  | 
 | 19 | + | 
 | 20 | +  1. resource cannot be created because a different resource with the same identifier already exists (example: cannot change existing user's identity because another user with the same identity already exists)  | 
 | 21 | +  2. resource cannot change its state because it is already in the specified state (example: user cannot be activated because it is already active)  | 
 | 22 | + | 
 | 23 | +* `ExpiredException` thrown when:  | 
 | 24 | + | 
 | 25 | +  1. resource cannot be accessed because it expired (example: account activation link)  | 
 | 26 | +  2. resource cannot be accessed because it has been consumed (example: one-time password)  | 
 | 27 | + | 
 | 28 | +* `ForbiddenException` thrown when:  | 
 | 29 | + | 
 | 30 | +  1. resource cannot be accessed by the authenticated client (example: client authenticated as regular user sends a `GET /admin` request)  | 
 | 31 | + | 
 | 32 | +* `MethodNotAllowedException` thrown when:  | 
 | 33 | + | 
 | 34 | +  1. client tries to interact with a resource via an invalid HTTP request method (example: client sends a `PATCH /avatar` request)  | 
 | 35 | + | 
 | 36 | +* `NotFoundException` thrown when:  | 
 | 37 | + | 
 | 38 | +  1. client tries to interact with a resource that does not exist on the server (example: client sends a `GET /resource-does-not-exist` request)  | 
 | 39 | + | 
 | 40 | +* `UnauthorizedException` thrown when:  | 
 | 41 | + | 
 | 42 | +  1. resource cannot be accessed because the client is not authenticated (example: unauthenticated client sends a `GET /admin` request)  | 
 | 43 | + | 
 | 44 | +## How it works?  | 
 | 45 | + | 
 | 46 | +During a request, if there is no uncaught exception DotKernel API will return a JSON response with the data provided by the handler that handled the request.  | 
 | 47 | + | 
 | 48 | +Else, it will build and send a response based on the exception thrown:  | 
 | 49 | + | 
 | 50 | +* `BadRequestException` will return a `400 Bad Request` response  | 
 | 51 | +* `UnauthorizedException` will return a `401 Unauthorized` response  | 
 | 52 | +* `ForbiddenException` will return a `403 Forbidden` response  | 
 | 53 | +* `OutOfBoundsException` and `NotFoundException` will return a `404 Not Found` response  | 
 | 54 | +* `MethodNotAllowedException` will return a `405 Method Not Allowed` response  | 
 | 55 | +* `ConflictException` will return a `409 Conflict` response  | 
 | 56 | +* `ExpiredException` will return a `410 Gone` response  | 
 | 57 | +* `MailException`, `RuntimeException` and the generic `Exception` will return a `500 Internal Server Error` response  | 
 | 58 | + | 
 | 59 | +## How to extend?  | 
 | 60 | + | 
 | 61 | +In this example we will create a custom exception called `CustomException`, place it next to the already existing custom exceptions (you can use your preferred location) and finally return a custom HTTP status code when `CustomException` is encountered.  | 
 | 62 | + | 
 | 63 | +### Step 1: Create exception file  | 
 | 64 | + | 
 | 65 | +Navigate to the directory `src/App/src/Handler/Exception` and create a PHP class called `CustomException.php`.  | 
 | 66 | +Open `CustomException.php` and add the following content:  | 
 | 67 | + | 
 | 68 | +```php  | 
 | 69 | +<?php  | 
 | 70 | + | 
 | 71 | +declare(strict_types=1);  | 
 | 72 | + | 
 | 73 | +namespace Api\App\Exception;  | 
 | 74 | + | 
 | 75 | +use Exception;  | 
 | 76 | + | 
 | 77 | +class CustomException extends Exception  | 
 | 78 | +{  | 
 | 79 | +}  | 
 | 80 | +```  | 
 | 81 | + | 
 | 82 | +Save and close the file.  | 
 | 83 | + | 
 | 84 | +### Step 2: Use exception file  | 
 | 85 | + | 
 | 86 | +Open the file `src/App/src/Handler/HomeHandler.php` and at the beginning of the `get` method, place the following code:  | 
 | 87 | + | 
 | 88 | +```php  | 
 | 89 | +throw new \Api\App\Exception\CustomException('some message');  | 
 | 90 | +```  | 
 | 91 | + | 
 | 92 | +Save and close the file.  | 
 | 93 | + | 
 | 94 | +### Step 3: Test for failure  | 
 | 95 | + | 
 | 96 | +Access your API's home page URL and make sure it returns `500 Internal Server Error` HTTP status code and the following content:  | 
 | 97 | + | 
 | 98 | +```json  | 
 | 99 | +{  | 
 | 100 | +    "error": {  | 
 | 101 | +        "messages": [  | 
 | 102 | +            "some message"  | 
 | 103 | +        ]  | 
 | 104 | +    }  | 
 | 105 | +}  | 
 | 106 | +```  | 
 | 107 | + | 
 | 108 | +### Step 4: Prepare for success  | 
 | 109 | + | 
 | 110 | +Open the file `src/App/src/Handler/ResponseTrait.php` and locate the `handle` method.  | 
 | 111 | +Insert the following lines of code before the first catch statement:  | 
 | 112 | + | 
 | 113 | +```php  | 
 | 114 | +        } catch (\Api\App\Exception\CustomException $exception) {  | 
 | 115 | +            return $this->errorResponse($exception->getMessage(), StatusCodeInterface::STATUS_IM_A_TEAPOT);  | 
 | 116 | +```  | 
 | 117 | + | 
 | 118 | +Save and close the file.  | 
 | 119 | + | 
 | 120 | +### Step 5: Test for success  | 
 | 121 | + | 
 | 122 | +Again, access your API's home page URL, which should return the same content.  | 
 | 123 | +Notice that this time it returns `418 I'm a teapot` HTTP status code.  | 
0 commit comments