Skip to content

Commit 9c2277f

Browse files
committed
Adjust: give the request object to ApiCore
1 parent dfce4b7 commit 9c2277f

File tree

4 files changed

+115
-104
lines changed

4 files changed

+115
-104
lines changed

application/controllers/ApiController.php

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ public function indexAction(): never
5353
private function dispatchEndpoint(Request $request, Response $response): void
5454
{
5555
$params = $request->getParams();
56-
$getParams = Url::fromRequest()->getQueryString();
5756
$method = $request->getMethod();
5857
$methodName = strtolower($method);
5958
$moduleName = $request->getModuleName();
@@ -74,6 +73,7 @@ private function dispatchEndpoint(Request $request, Response $response): void
7473
$this->httpNotFound(404, "Endpoint $endpoint does not exist.");
7574
}
7675

76+
// TODO: move this to an api core or version class?
7777
$parsedMethodName = ($method === 'GET' && empty($identifier)) ? $methodName . 'Any' : $methodName;
7878

7979
if (!in_array($parsedMethodName, get_class_methods($className))) {
@@ -84,25 +84,12 @@ private function dispatchEndpoint(Request $request, Response $response): void
8484
}
8585
}
8686

87-
// Validate that Method with parameters or identifier is allowed
88-
if ($method !== 'GET' && !empty($getParams)) {
89-
$this->httpBadRequest(
90-
"Invalid request: $method with query parameters, only GET is allowed with query parameters."
91-
);
92-
} elseif ($method === 'GET' && !empty($identifier) && !empty($getParams)) {
93-
$this->httpBadRequest(
94-
"Invalid request: $method with identifier and query parameters, it's not allowed to use both together."
95-
);
96-
}
97-
9887
// Choose the correct constructor call based on the endpoint
99-
if (strtolower($endpoint) === ApiCore::OPENAPI_ENDPOINT) {
100-
(new $className($moduleName, $response))->$parsedMethodName();
101-
} elseif (in_array($method, ['POST', 'PUT'])) {
88+
if (in_array($method, ['POST', 'PUT'])) {
10289
$data = $this->getValidatedJsonContent($request);
103-
(new $className($response, $getParams, $identifier))->$parsedMethodName($data);
90+
(new $className($request, $response))->$parsedMethodName($data);
10491
} else {
105-
(new $className($response, $getParams, $identifier))->$parsedMethodName();
92+
(new $className($request, $response))->$parsedMethodName();
10693
}
10794
}
10895

library/Notifications/Api/ApiCore.php

Lines changed: 82 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88
use Icinga\Exception\ProgrammingError;
99
use Icinga\Module\Notifications\Common\Database;
1010
use Icinga\Util\Environment;
11+
use Icinga\Web\Request;
1112
use Icinga\Web\Response;
1213
use ipl\Sql\Connection;
13-
use OpenApi\Attributes as OA;
14-
15-
1614

1715
abstract class ApiCore
1816
{
@@ -30,12 +28,6 @@ abstract class ApiCore
3028
* @var array
3129
*/
3230
protected array $results = [];
33-
/**
34-
* The HTTP response code to be returned.
35-
*
36-
* @var int
37-
*/
38-
protected int $responseCode = 200;
3931
/**
4032
* The database connection used for API operations.
4133
*
@@ -50,47 +42,32 @@ abstract class ApiCore
5042
protected string $version;
5143

5244
public function __construct(
45+
/**
46+
* The HTTP request object containing the API request data.
47+
*
48+
* @var Request
49+
*/
50+
readonly private Request $request,
5351
/**
5452
* The HTTP response object used to send responses back to the client.
5553
*
5654
* @var Response
5755
*/
58-
protected Response $response,
59-
)
60-
{
56+
readonly private Response $response,
57+
) {
6158
$this->db = Database::get();
59+
$this->init();
6260
}
6361

6462
/**
65-
* Immediately respond w/ HTTP 400
66-
*
67-
* @param string $message Exception message or exception format string
68-
* @param mixed ...$arg Format string argument
69-
*
70-
* @return never
71-
*
72-
* @throws HttpBadRequestException
73-
*/
74-
public function httpBadRequest(string $message, mixed ...$arg) :never
75-
{
76-
throw HttpBadRequestException::create(func_get_args());
77-
}
78-
79-
80-
/**
81-
* Immediately respond w/ HTTP 404
63+
* Initialize the API core.
8264
*
83-
* @param string $message Exception message or exception format string
84-
* @param mixed ...$arg Format string argument
65+
* This method is called in the constructor and should be implemented by subclasses
66+
* to perform any necessary initialization tasks.
8567
*
86-
* @return never
87-
*
88-
* @throws HttpNotFoundException
68+
* @return void
8969
*/
90-
public function httpNotFound(string $message, mixed ...$arg): never
91-
{
92-
throw HttpNotFoundException::create(func_get_args());
93-
}
70+
abstract protected function init(): void;
9471

9572
/**
9673
* Get the files including the ApiCore.php file and any other files matching the given filter.
@@ -128,17 +105,80 @@ protected function getFilesIncludingDocs(string $fileFilter = '*'): array
128105
return $files;
129106
}
130107

108+
/**
109+
* Get the Request object
110+
*
111+
* @return Request
112+
*/
113+
protected function getRequest(): Request
114+
{
115+
return $this->request;
116+
}
117+
118+
/**
119+
* Get the Response object
120+
*
121+
* This method returns the response object that is used to send back the API response.
122+
*
123+
* @return Response
124+
*/
125+
protected function getResponse(): Response
126+
{
127+
return $this->response;
128+
}
129+
130+
/**
131+
* Immediately respond w/ HTTP 400
132+
*
133+
* @param string $message Exception message or exception format string
134+
* @param mixed ...$arg Format string argument
135+
*
136+
* @return never
137+
*
138+
* @throws HttpBadRequestException
139+
*/
140+
public function httpBadRequest(string $message, mixed ...$arg): never
141+
{
142+
throw HttpBadRequestException::create(func_get_args());
143+
}
144+
145+
146+
/**
147+
* Immediately respond w/ HTTP 404
148+
*
149+
* @param string $message Exception message or exception format string
150+
* @param mixed ...$arg Format string argument
151+
*
152+
* @return never
153+
*
154+
* @throws HttpNotFoundException
155+
*/
156+
public function httpNotFound(string $message, mixed ...$arg): never
157+
{
158+
throw HttpNotFoundException::create(func_get_args());
159+
}
160+
161+
/**
162+
* Send a JSON response with the given print function.
163+
*
164+
* This method clears the output buffer, raises the execution time,
165+
* sets the appropriate headers for a JSON response, and then calls
166+
* the provided print function to output the JSON data.
167+
*
168+
* @param callable $printFunc A function that prints the JSON data.
169+
*
170+
* @return void
171+
*/
131172
protected function sendJsonResponse(callable $printFunc): void
132173
{
133174
ob_end_clean();
134175
Environment::raiseExecutionTime();
135176

136177
$this->getResponse()
137-
->setHeader('Content-Type', 'application/json')
138-
->setHeader('Cache-Control', 'no-store')
139-
->sendResponse();
178+
->setHeader('Content-Type', 'application/json')
179+
->setHeader('Cache-Control', 'no-store')
180+
->sendResponse();
140181

141182
$printFunc();
142183
}
143-
144184
}

library/Notifications/Api/V1/ApiV1.php

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
use Exception;
66
use Icinga\Exception\Http\HttpBadRequestException;
77
use Icinga\Module\Notifications\Api\ApiCore;
8-
use Icinga\Web\Response;
98
use ipl\Sql\Compat\FilterProcessor;
109
use ipl\Web\Filter\QueryString;
10+
use ipl\Web\Url;
1111
use Ramsey\Uuid\Uuid;
1212
use OpenApi\Attributes as OA;
1313

@@ -58,50 +58,47 @@
5858
)]
5959
abstract class ApiV1 extends ApiCore
6060
{
61-
public function __construct(
62-
Response $response,
63-
/**
64-
* The filter string used to filter results.
65-
* This is typically a query string parameter that specifies conditions for filtering.
66-
*
67-
* @var string|null
68-
*/
69-
protected ?string $filterStr = null,
70-
/**
71-
* The identifier for the resource being accessed.
72-
*
73-
* @var string|null
74-
*/
75-
protected ?string $identifier = null
76-
) {
77-
parent::__construct($response);
78-
$this->version = 'v1';
79-
// var_dump($response, $params, $identifier);
80-
$this->validateIdentifier();
81-
}
82-
61+
protected string $identifier;
8362
/**
84-
* Get the Response object
63+
* Initialize the API
8564
*
86-
* @return Response
65+
* @return void
66+
* @throws HttpBadRequestException
8767
*/
88-
public function getResponse(): Response
68+
protected function init(): void
8969
{
90-
return $this->response;
70+
$this->version = 'v1';
71+
$this->validateIdentifier();
72+
$method = $this->getRequest()->getMethod();
73+
$filterStr = Url::fromRequest()->getQueryString();
74+
75+
// Validate that Method with parameters or identifier is allowed
76+
if ($method !== 'GET' && !empty($filterStr)) {
77+
$this->httpBadRequest(
78+
"Invalid request: $method with query parameters, only GET is allowed with query parameters."
79+
);
80+
} elseif ($method === 'GET' && !empty($this->identifier) && !empty($filterStr)) {
81+
$this->httpBadRequest(
82+
"Invalid request: $method with identifier and query parameters, it's not allowed to use both together."
83+
);
84+
}
9185
}
9286

9387
/**
9488
* Validate the identifier to ensure it is a valid UUID.
95-
*
9689
* If the identifier is not valid, it will throw a Bad Request HTTP exception.
90+
* If a valid identifier is provided, it will be stored in the `identifier` property.
9791
*
9892
* @return void
9993
* @throws HttpBadRequestException
10094
*/
10195
protected function validateIdentifier(): void
10296
{
103-
if (($i = $this->identifier) && !Uuid::isValid($i)) {
104-
$this->httpBadRequest('The given identifier is not a valid UUID');
97+
if ($identifier = $this->getRequest()->getParams()['identifier'] ?? null) {
98+
if (!Uuid::isValid($identifier)) {
99+
$this->httpBadRequest('The given identifier is not a valid UUID');
100+
}
101+
$this->identifier = $identifier;
105102
}
106103
}
107104

@@ -117,9 +114,9 @@ protected function validateIdentifier(): void
117114
*/
118115
protected function createFilterFromFilterStr(callable $listener): array|bool
119116
{
120-
if (!empty($this->filterStr)) {
117+
if (!empty($filterStr = Url::fromRequest()->getQueryString())) {
121118
try {
122-
$filterRule = QueryString::fromString($this->filterStr)
119+
$filterRule = QueryString::fromString($filterStr)
123120
->on(
124121
QueryString::ON_CONDITION,
125122
$listener

library/Notifications/Api/V1/OpenApi.php

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,6 @@
6767
)]
6868
class OpenApi extends ApiV1
6969
{
70-
public function __construct(
71-
/**
72-
* The name of the module for which the OpenAPI documentation is generated.
73-
* This is used to identify the module in the API documentation.
74-
*
75-
* @var string
76-
*/
77-
protected string $moduleName,
78-
Response $response
79-
) {
80-
parent::__construct($response);
81-
}
82-
8370
/**
8471
* Generate OpenAPI documentation for the Notifications API
8572
*

0 commit comments

Comments
 (0)