-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/http api new approach #348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
9a3a6aa
to
aa2b625
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This review covers only the early parts of routing and dispatching.
run.php
Outdated
$this->addRoute('notifications/api-v1-contacts', new Zend_Controller_Router_Route_Regex( | ||
'notifications/api/v1/contacts(?:\/(.+)|\?(.+))?', | ||
[ | ||
'controller' => 'api-v1-contacts', | ||
'action' => 'index', | ||
'module' => 'notifications', | ||
'identifier' => null | ||
], | ||
[ | ||
1 => 'identifier' | ||
] | ||
)); | ||
|
||
$this->addRoute('notifications/api-v1-contactgroups', new Zend_Controller_Router_Route_Regex( | ||
'notifications/api/v1/contactgroups(?:\/(.+)|\?(.+))?', | ||
[ | ||
'controller' => 'api-v1-contactgroups', | ||
'action' => 'index', | ||
'module' => 'notifications', | ||
'identifier' => null | ||
], | ||
[ | ||
1 => 'identifier' | ||
] | ||
)); | ||
|
||
$this->addRoute('notifications/api-v1-channels', new Zend_Controller_Router_Route_Regex( | ||
'notifications/api/v1/channels(?:\/(.+)|\?(.+))?', | ||
[ | ||
'controller' => 'api-v1-channels', | ||
'action' => 'index', | ||
'module' => 'notifications', | ||
'identifier' => null | ||
], | ||
[ | ||
1 => 'identifier' | ||
] | ||
)); | ||
|
||
$this->addRoute('notifications/api-v1-channels', new Zend_Controller_Router_Route_Regex( | ||
'notifications/api(?:\/(v[0-9\.]+))(?:\/([^\/\?]+))?(?:[\/\?]([^\/\?]+))?', | ||
[ | ||
'controller' => 'api', | ||
'action' => 'index', | ||
'version' => 'v1', | ||
'module' => 'notifications', | ||
'endpoint' => null, | ||
'identifier' => null | ||
], | ||
[ | ||
1 => 'version', | ||
2 => 'endpoint', | ||
3 => 'identifier' | ||
] | ||
)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please replace this with:
$this->addRoute('notifications/api-v1-contacts', new Zend_Controller_Router_Route_Regex( | |
'notifications/api/v1/contacts(?:\/(.+)|\?(.+))?', | |
[ | |
'controller' => 'api-v1-contacts', | |
'action' => 'index', | |
'module' => 'notifications', | |
'identifier' => null | |
], | |
[ | |
1 => 'identifier' | |
] | |
)); | |
$this->addRoute('notifications/api-v1-contactgroups', new Zend_Controller_Router_Route_Regex( | |
'notifications/api/v1/contactgroups(?:\/(.+)|\?(.+))?', | |
[ | |
'controller' => 'api-v1-contactgroups', | |
'action' => 'index', | |
'module' => 'notifications', | |
'identifier' => null | |
], | |
[ | |
1 => 'identifier' | |
] | |
)); | |
$this->addRoute('notifications/api-v1-channels', new Zend_Controller_Router_Route_Regex( | |
'notifications/api/v1/channels(?:\/(.+)|\?(.+))?', | |
[ | |
'controller' => 'api-v1-channels', | |
'action' => 'index', | |
'module' => 'notifications', | |
'identifier' => null | |
], | |
[ | |
1 => 'identifier' | |
] | |
)); | |
$this->addRoute('notifications/api-v1-channels', new Zend_Controller_Router_Route_Regex( | |
'notifications/api(?:\/(v[0-9\.]+))(?:\/([^\/\?]+))?(?:[\/\?]([^\/\?]+))?', | |
[ | |
'controller' => 'api', | |
'action' => 'index', | |
'version' => 'v1', | |
'module' => 'notifications', | |
'endpoint' => null, | |
'identifier' => null | |
], | |
[ | |
1 => 'version', | |
2 => 'endpoint', | |
3 => 'identifier' | |
] | |
)); | |
$this->addRoute('notifications/api-plural', new Zend_Controller_Router_Route( | |
'notifications/api/:version/:endpoint', | |
[ | |
'module' => 'notifications', | |
'controller' => 'api', | |
'action' => 'index' | |
] | |
)); | |
$this->addRoute('notifications/api-single', new Zend_Controller_Router_Route( | |
'notifications/api/:version/:endpoint/:identifier', | |
[ | |
'module' => 'notifications', | |
'controller' => 'api', | |
'action' => 'index' | |
] | |
)); |
Note that Zend processes routes in reverse order. So notifications/api-single
will be processed first. It cannot match without an identifier, because there is no forward slash in our endpoint names. notifications/api-plural
on the other hand cannot match with an identifier, because notifications/api-single
is processed first. 😉
*/ | ||
public function indexAction(): never | ||
{ | ||
$this->assertPermission('notifications/api/v1'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know the issues requires this. But now I'm not sure anymore, whether it makes sense to have the api version in the permission's name. Why would someone, permitted to use v1, not be able to use v2?
Though, do not change anything yet. Leave this for later.
* @throws HttpBadRequestException If the request is not valid. | ||
* @throws SecurityException | ||
* @throws HttpException|HttpNotFoundException | ||
* @throws Zend_Controller_Request_Exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return type is missing
$version = StringHelper::cname($params['version'] ?? null, '-'); | ||
$endpoint = StringHelper::cname($params['endpoint'] ?? null, '-'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use ipl-stdlib's Str::camel
here.
if (empty($version) || empty($endpoint)) { | ||
throw new HttpException(404, "Version and endpoint are required parameters."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The routes I suggested should verify this and make this check obsolete.
throw new HttpException(404, "Version and endpoint are required parameters."); | ||
} | ||
|
||
$module = ($moduleName !== null) ? 'Module\\' . StringHelper::cname($moduleName, '-') . '\\' : ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None of our modules use dashes in their name.
} | ||
|
||
$module = ($moduleName !== null) ? 'Module\\' . StringHelper::cname($moduleName, '-') . '\\' : ''; | ||
$className = sprintf('Icinga\\%sApi\\%s\\%s', $module, $version, $endpoint); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that this may already be compatible with an Icinga Web API 😃
$className = sprintf('Icinga\\%sApi\\%s\\%s', $module, $version, $endpoint); | ||
|
||
// Check if the required class and method are available and valid | ||
if (! class_exists($className) || (new ReflectionClass($className))->isAbstract()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why the abstract check is required. If an abstract class matches an endpoint, this should result in a server error, not a not found.
// TODO: move this to an api core or version class? | ||
$parsedMethodName = ($method === 'GET' && empty($identifier)) ? $methodName . 'Any' : $methodName; | ||
|
||
if (! in_array($parsedMethodName, get_class_methods($className))) { | ||
if ($method === 'GET' && in_array($methodName, get_class_methods($className))) { | ||
$parsedMethodName = $methodName; | ||
} else { | ||
throw new HttpException(405, "Method $method does not exist."); | ||
} | ||
} | ||
|
||
// Choose the correct constructor call based on the endpoint | ||
if (in_array($method, ['POST', 'PUT'])) { | ||
$data = $this->getValidatedJsonContent($request); | ||
(new $className($request, $response))->$parsedMethodName($data); | ||
} else { | ||
(new $className($request, $response))->$parsedMethodName(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do this without depending on any Zend objects. Including request and response.
Once you've identified a class using the endpoint, instantiate it and interact with it by expecting it to be of type RequestHandlerInterface
.
The identifier should be part of the request object in the form of an attribute (The last paragraph of the linked section).
The end result should be that this controller is the last part in the chain that is built on top of Zend routing and dispatching. Everything else is PSR7/15 compliant and can then easily migrated to an alternative in the future.
$this->version = 'v1'; | ||
$this->validateIdentifier(); | ||
$method = $this->getRequest()->getMethod(); | ||
$filterStr = Url::fromRequest()->getQueryString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Get the query string from the request please, do not use a url object for this. Once this is PSR15 compliant, everything should be inferred from the request. Singletons are not an option.
Oh, and I got the postgres tests working in my environment. Please get back to me for this. |
f53b374
to
1705125
Compare
ICINGA_NOTIFICATIONS_SCHEMA=/path/to/notifications/schema.sql ICINGAWEB_PATH=/icingaweb2 /usr/share/icinga-php/ipl/vendor/bin/phpunit --bootstrap test/php/bootstrap.php Note that you will need a database for this, and propagate this via env as well: * Name | Description * ----------------- | ------------------------ * *_TESTDB | The database to use * *_TESTDB_HOST | The server to connect to * *_TESTDB_PORT | The port to connect to * *_TESTDB_USER | The user to connect with * *_TESTDB_PASSWORD | The password of the user
1705125
to
fe816f8
Compare
$this->assertSame(404, $response->getStatusCode(), $content); | ||
$this->assertSame('{"status":"error","message":"Channel not found"}', $content); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add the following test cases:
- The POST, PUT and DELETE methods should respond with an HTTP code 400: "Method (POST|PUT|DELETE) is not supported"
- If an invalid UUID is specified, the response should be HTTP code 400.
- If an invalid filter is specified, the response should be HTTP code 400.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the JSON is valid, but a required field is missing or invalid, use the code 422
// missing username | ||
$response = $this->sendRequest('POST', 'contacts', [ | ||
'id' => '0817d973-398e-41d7-9ef2-61cdb7ef41a1', | ||
'full_name' => 'Test', | ||
'default_channel' => BaseApiV1TestCase::CHANNEL_UUID, | ||
'groups' => [], | ||
'addresses' => [] | ||
]); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertEquals(201, $response->getStatusCode(), $content); | ||
|
||
// missing groups | ||
$response = $this->sendRequest('POST', 'contacts', [ | ||
'id' => '0817d973-398e-41d7-9ef2-61cdb7ef41a2', | ||
'full_name' => 'Test', | ||
'username' => 'test', | ||
'default_channel' => BaseApiV1TestCase::CHANNEL_UUID | ||
]); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertEquals(201, $response->getStatusCode(), $content); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are optional columns and are valid. Please move them to a separate test.
// missing addresses | ||
$response = $this->sendRequest('POST', 'contacts', [ | ||
'id' => '0817d973-398e-41d7-9ef2-61cdb7ef41a4', | ||
'full_name' => 'Test', | ||
'default_channel' => BaseApiV1TestCase::CHANNEL_UUID, | ||
'groups' => [] | ||
]); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertEquals(201, $response->getStatusCode(), $content); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
// missing id | ||
$response = $this->sendRequest('POST', 'contacts/0817d973-398e-41d7-9ef2-61cdb7ef41a2', [ | ||
'full_name' => 'Test', | ||
'default_channel' => BaseApiV1TestCase::CHANNEL_UUID | ||
]); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertSame(400, $response->getStatusCode(), $content); | ||
$this->assertSame( | ||
'{"status":"error","message":"Invalid request body: ' | ||
. 'the fields id, full_name and default_channel must be present and of type string"}', | ||
$content | ||
); | ||
|
||
// missing name | ||
$response = $this->sendRequest('POST', 'contacts/0817d973-398e-41d7-9ef2-61cdb7ef41a2', [ | ||
'id' => '0817d973-398e-41d7-9ef2-61cdb7ef41a2', | ||
'default_channel' => BaseApiV1TestCase::CHANNEL_UUID | ||
]); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertSame(400, $response->getStatusCode(), $content); | ||
$this->assertSame( | ||
'{"status":"error","message":"Invalid request body: ' | ||
. 'the fields id, full_name and default_channel must be present and of type string"}', | ||
$content | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have the similar test cases in the test method above. I would suggest adding one separate test instead, e.g.: testPostWithMissingRequiredField
.
'default_channel' => BaseApiV1TestCase::CHANNEL_UUID, | ||
]); | ||
|
||
$this->assertSame(201, $response->getStatusCode(), $response->getBody()->getContents()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also check the contents.
$this->sendRequest('PUT', 'contacts/0817d973-398e-41d7-9ef2-61cdb7ef41a2', [ | ||
'id' => '0817d973-398e-41d7-9ef2-61cdb7ef41a2', | ||
'full_name' => 'Test', | ||
'default_channel' => BaseApiV1TestCase::CHANNEL_UUID | ||
]); | ||
$this->sendRequest('PUT', 'contacts/0817d973-398e-41d7-9ef2-61cdb7ef41a3', [ | ||
'id' => '0817d973-398e-41d7-9ef2-61cdb7ef41a3', | ||
'full_name' => 'Test (2)', | ||
'default_channel' => BaseApiV1TestCase::CHANNEL_UUID | ||
]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the POST
method to create contacts here. PUT should mainly be used for update or replace.
*/ | ||
public function testGetWithMatchingIdentifier(): void | ||
{ | ||
$this->sendRequest('PUT', 'contacts/0817d973-398e-41d7-9ef2-61cdb7ef41a2', [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, use POST
please.
*/ | ||
public function testGetWithMatchingFilter(): void | ||
{ | ||
$this->sendRequest('PUT', 'contacts/0817d973-398e-41d7-9ef2-61cdb7ef41a2', [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, use POST
please.
*/ | ||
public function testGetWithNonMatchingFilter(): void | ||
{ | ||
$this->sendRequest('PUT', 'contacts/0817d973-398e-41d7-9ef2-61cdb7ef41a2', [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, use POST
please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you are not retrieving this contact anyway, this is superfluous. GET is sufficient here.
@@ -0,0 +1,863 @@ | |||
<?php |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fix the phpDoc.
|
||
public function __construct() | ||
{ | ||
$this->setResponse((new HttpFactory())->createResponse()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead, please use new Response()
, as used internally by (new HttpFactory())->createResponse()
.
* @param Connection $db | ||
* @return void | ||
*/ | ||
protected function setDB(Connection $db): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please let the setter
return the class (: static) instead.
Apply this to all setter.
*/ | ||
protected function setVersion(string $version): void | ||
{ | ||
if (! isset($this->version)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this isset
check necessary? If the code is not allowed to overwrite the version, please use a constant instead of a setter.
* @return array | ||
* @throws ProgrammingError | ||
*/ | ||
protected function getFilesIncludingDocs(string $fileFilter = '*'): array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to be specific to OpenApi
, so please move it there.
* | ||
* @var string | ||
*/ | ||
public const OPENAPI_ENDPOINT = 'openapi'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this to the OpenApi
please.
'status' => $statusCode, | ||
'body' => $body, | ||
'headers' => $additionalHeaders, | ||
], static fn($v) => $v !== null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This callback is superfluous, as this is the default for array_filter
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method can be removed, please create an array manually instead.
$response = $response->withStatus($responseData['status']); | ||
} | ||
if (isset($responseData['headers']) && is_array($responseData['headers'])) { | ||
foreach ($responseData['headers'] as $name => $values) { | ||
if (is_array($values)) { | ||
foreach ($values as $value) { | ||
$response = $response->withHeader($name, $value); | ||
} | ||
} else { | ||
$response = $response->withHeader($name, $values); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each call on $response
creates a clone. Change it as discussed offline, please.
$result = $this->getDB()->fetchOne($stmt); | ||
|
||
if (empty($result)) { | ||
throw HttpNotFoundException::create(['Channel not found']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HttpNotFoundException::create()
requires an array, use new HttpNotFoundException('Channel not found')
instead.
|
||
$this->createGETRowFinalizer()($result); | ||
|
||
return $this->createArrayOfResponseData(body: Json::sanitize($result)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As commented above, this method can be removed. Use return ['body' => Json::sanitize($result)]
.
throw HttpBadRequestException::create(['Identifier is required']); | ||
} | ||
|
||
$data = $this->getValidatedRequestBodyData($requestBody); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method only validates the given $requestBody
and does not change it. It can be void. Please change the name to : assertValidRequestBody(): void
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have looked at channels and contact tests so far, next I will look at contactgroup tests.
try { | ||
$methodName = HttpMethod::from($httpMethod)->name; | ||
} catch (ValueError $e) { | ||
throw new HttpException(405, "HTTP method $httpMethod is not supported"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allow header is required for 405
.
See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Allow
$this->assertSame('{"status":"success","message":"Contact created successfully"}', $content); | ||
} | ||
|
||
// TODO: send 409 instead of 422? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, 409
please
|
||
// TODO: additional POST tests | ||
// TODO: send 422 instead of 400? | ||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, 422
please.
*/ | ||
public function testPostWithInvalidData(): void | ||
{ | ||
// TODO: send 409 or 422? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes :)
); | ||
} | ||
|
||
// TODO: send 422 instead of 400? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
); | ||
} | ||
|
||
// TODO: send 422 instead of 400? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes pelase.
$response = $this->sendRequest('DELETE', 'contacts'); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertSame(400, $response->getStatusCode(), $content); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be 422
.
$response = $this->sendRequest('PATCH', 'contacts'); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertSame(405, $response->getStatusCode(), $content); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check if the required header allow
is set.
$response = $this->sendRequest('PATCH', 'channels'); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertSame(405, $response->getStatusCode(), $content); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error code 405
always requires an allow
header, as mentioned in the comment above. Please check whether this is present.
$this->assertSame(404, $response->getStatusCode(), $content); | ||
$this->assertSame('{"status":"error","message":"Channel not found"}', $content); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the JSON is valid, but a required field is missing or invalid, use the code 422
* | ||
* @dataProvider databases | ||
*/ | ||
public function testPostWithInvalidContent(): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a general test that is not really related to the specified endpoint. This test could be moved to a class that tests basic API functions.
Since the basic API implementation may be moved anyway, we can look at this later, once everything else is working as expected.
* | ||
* @dataProvider databases | ||
*/ | ||
public function testPostWithInvalidContentType(): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here and the same applies to other test classes.
* @dataProvider databases | ||
*/ | ||
public function testPostWithFilter(): void | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
$this->assertCount(1, $response->getHeader('Location')); | ||
$this->assertSame( | ||
'notifications/api/v1/contactgroups/0817d973-398e-41d7-9ef2-61cdb7ef41a3', | ||
$response->getHeader('Location')[0] | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead, you can do the following, which makes assertCount
superfluous:
$this->assertSame(
['notifications/api/v1/contactgroups/0817d973-398e-41d7-9ef2-61cdb7ef41a3'],
$$response->getHeader('Location')
);
]); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertSame(422, $response->getStatusCode(), $content); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are reusing theid
here, so this is a ‘409 conflict’.
$this->assertSame( | ||
'', | ||
$content | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oneline please.
$response = $this->sendRequest('DELETE', 'contactgroups'); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertSame(400, $response->getStatusCode(), $content); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be 422
.
* | ||
* @dataProvider databases | ||
*/ | ||
public function testPutWithNonMatchingIdentifierAndMissingRequiredFields(): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Status code should be 422
here.
]); | ||
$content = $response->getBody()->getContents(); | ||
|
||
$this->assertEquals(400, $response->getStatusCode(), $content); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be 422
.
$this->assertSame( | ||
'', | ||
$content | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oneline please.
Initial setup for the new approach of the http-api with openapi description.
Resolves:
require:
external_uuid
tocontact/contactgroup
table icinga-notifications#216