Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ See [keep a changelog] for information about writing changes to this log.

## [Unreleased]

- [PR-52](https://github.com/itk-dev/event-database-api/pull/52)
Pin the problem+json error contract: 401 served as RFC 7807, resource reads in problem+json yield 406
- [PR-51](https://github.com/itk-dev/event-database-api/pull/51)
Show the API-spec diff summary inline in the PR comment (collapsed) alongside the oasdiff review link
- [PR-49](https://github.com/itk-dev/event-database-api/pull/49)
Expand Down
54 changes: 54 additions & 0 deletions tests/ApiPlatform/Contract/ErrorContractTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,58 @@ public function testNotFoundErrorShape(): void
$this->assertSame(404, $data['status']);
$this->assertSame('/errors/404', $data['type']);
}

/**
* `rfc_7807_compliant_errors: true` (config/packages/api_platform.yaml)
* registers problem+json as an error format, so an auth error requested as
* `application/problem+json` is served as RFC 7807 (unprefixed
* title/detail/status/type) rather than hydra. The 401 also short-circuits
* before resource content negotiation, so the format is honoured.
*
* @see https://api-platform.com/docs/core/content-negotiation/
*/
public function testUnauthenticatedErrorIsAvailableAsProblemJson(): void
{
$client = self::createClient(defaultOptions: [
'headers' => ['accept' => ['application/problem+json']],
]);
$response = $client->request('GET', '/api/v2/events');

$this->assertSame(Response::HTTP_UNAUTHORIZED, $response->getStatusCode());
$this->assertStringContainsString('application/problem+json', $response->getHeaders(false)['content-type'][0] ?? '');

$data = $response->toArray(false);
$this->assertSame(401, $data['status']);
$this->assertSame('/errors/401', $data['type']);
$this->assertArrayHasKey('title', $data);
$this->assertArrayHasKey('detail', $data);
}

/**
* The only resource format configured under `formats` in
* config/packages/api_platform.yaml is `application/ld+json`, so content
* negotiation cannot satisfy `Accept: application/problem+json` on a resource
* read: it yields 406 Not Acceptable (NOT a 404), and the 406 body is itself
* a problem+json error. Pinning this documents that problem+json is not a
* resource representation (consumers must read resources as ld+json) and
* guards the `formats` allow-list — adding problem+json there would flip this.
*
* @see https://api-platform.com/docs/core/content-negotiation/
*/
public function testProblemJsonIsNotAcceptableForResourceReads(): void
{
$client = self::createClient(defaultOptions: [
'headers' => [
'accept' => ['application/problem+json'],
'x-api-key' => 'test_api_key',
],
]);
$response = $client->request('GET', '/api/v2/events/99999');

$this->assertSame(Response::HTTP_NOT_ACCEPTABLE, $response->getStatusCode());
$this->assertStringContainsString('application/problem+json', $response->getHeaders(false)['content-type'][0] ?? '');

$data = $response->toArray(false);
$this->assertSame(406, $data['status']);
}
}