File modules/cms/output/APIOutput.class.php
Last commit: Sat Oct 17 01:14:30 2026 +0200 Jan Dankert New: Using a structured class for the API-Response. The output for GET-Requests is now without the "output" layer.
1 <?php 2 3 namespace cms\output; 4 5 use cms\action\RequestParams; 6 use cms\api\APIResponse; 7 use cms\api\TraceElement; 8 use cms\base\Startup; 9 use Exception; 10 use Throwable; 11 use util\exception\ClientException; 12 use util\Hydrator; 13 use util\Session; 14 15 /** 16 * Entrypoint for all API requests. 17 */ 18 abstract class APIOutput extends BaseOutput 19 { 20 /** 21 * Converting an exception to an array. 22 * 23 * This will contain all exceptions out of the exception chain. 24 * 25 * @param $e Exception 26 */ 27 private static function exceptionToArray( Throwable $e): \cms\api\Exception 28 { 29 $previous = $e->getPrevious(); 30 if ( $previous != null ) 31 $cause = self::exceptionToArray($previous ); 32 else 33 $cause = null; 34 35 return new \cms\api\Exception( 36 get_class($e), 37 $e->getMessage(), 38 $e->getCode(), 39 array_map( 40 function( $trace ) { 41 return new TraceElement( 42 $trace['file'], 43 $trace['line'], 44 @$trace['function'], 45 @$trace['class'], 46 // no 'args' for security reasons 47 );} 48 ,$e->getTrace()), 49 $cause ); 50 } 51 52 /** 53 * This method is executed before the dispatcher is called. 54 * Subclasses may override this to prepare the response. 55 * @param $request RequestParams 56 * @return void 57 */ 58 protected function beforeAction( $request ) 59 { 60 if ( ! $request->action ) 61 throw new ClientException('no action set'); 62 if ( ! $request->method ) 63 throw new ClientException('no subaction set'); 64 } 65 66 67 68 69 protected function outputData(RequestParams|null $request, $data): void 70 { 71 $output = $this->renderOutput( $data ); 72 73 // HTTP Spec: 74 // "Applications SHOULD use this field to indicate the transfer-length of the 75 // message-body, unless this is prohibited by the rules in section 4.4." 76 // 77 // And the overhead of 'Transfer-Encoding: chunked' is eliminated... 78 header('Content-Length: ' . strlen($output)); 79 echo $output; 80 } 81 82 abstract protected function renderOutput(array $data ): string; 83 84 /** 85 * @param string $text 86 * @param Exception $cause 87 */ 88 protected function setError(string $text, Exception $cause): void 89 { 90 // Traces only in DEVELOPMENT mode 91 // for security reasons, because traces may contain sensitive information. 92 if (!defined('DEVELOPMENT') || DEVELOPMENT) 93 $apiException = $this->exceptionToArray($cause); 94 else 95 $apiException = null; 96 97 $apiResponse = new APIResponse( 98 $text, 99 [ [ 100 'status'=> 'error', 101 'text' => $text, 102 'log' => (!defined('DEVELOPMENT') || DEVELOPMENT) ? $cause->getMessage() : '', 103 ] 104 ], 105 [], 106 '', 107 '', 108 false, 109 '', 110 Startup::VERSION, 111 Startup::API_LEVEL, 112 $apiException 113 ); 114 115 $this->outputData(null,Hydrator::toArray($apiResponse) ); 116 } 117 118 }
Downloadmodules/cms/output/APIOutput.class.php
History Sat, 17 Oct 2026 01:14:30 +0200 Jan Dankert New: Using a structured class for the API-Response. The output for GET-Requests is now without the "output" layer. Tue, 13 Oct 2026 22:52:59 +0200 Jan Dankert New: The UI is now able to send hierarchical form data and the server is converting it into an object. This is a very nice feature, because this enables a better OpenAPI interface. Mon, 13 Jun 2022 22:00:39 +0200 Jan Dankert Fix: Show the error description in the UI notice. Sat, 19 Mar 2022 01:29:19 +0100 dankert Fix: PreviewOutput should inherit from UIOutput. Fri, 11 Mar 2022 12:13:10 +0100 dankert Fix: Show notice on internal server error. Wed, 2 Feb 2022 01:12:42 +0100 dankert Better support for API requests. Sun, 30 Jan 2022 23:38:42 +0100 dankert Refactoring: Only 1 http-endpoint for both the UI and the API. Path "/api" is not available any more, all API data is served under "/".