Skip to content

Commit

Permalink
feat: allow adding endpoints before/after others
Browse files Browse the repository at this point in the history
  • Loading branch information
SychO9 committed Nov 16, 2024
1 parent 4feb4a3 commit 6780af1
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
4 changes: 4 additions & 0 deletions framework/core/src/Api/Endpoint/Endpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ public function handle(\Tobyz\JsonApiServer\Context $context): ?Response
return json_api_response($this->showResource($context, $data));
}

if (is_array($data)) {
return json_api_response($data);
}

return null;
}
}
66 changes: 66 additions & 0 deletions framework/core/src/Extend/ApiResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
class ApiResource implements ExtenderInterface
{
private array $endpoints = [];
private array $endpointsBefore = [];
private array $endpointsAfter = [];
private array $removeEndpoints = [];
private array $endpoint = [];
private array $fields = [];
Expand Down Expand Up @@ -55,6 +57,45 @@ public function endpoints(callable|string $endpoints): self
return $this;
}

/**
* Add endpoints to the resource before a certain endpoint.
*
* @param string $before the name of the endpoint to add the new endpoints before.
* @param callable|class-string $endpoints must be a callable that returns an array of objects that implement \Flarum\Api\Endpoint\Endpoint.
*/
public function endpointsBefore(string $before, callable|string $endpoints): self
{
$this->endpointsBefore[] = [$before, $endpoints];

return $this;
}

/**
* Add endpoints to the resource after a certain endpoint.
*
* @param string $after the name of the endpoint to add the new endpoints after.
* @param callable|class-string $endpoints must be a callable that returns an array of objects that implement \Flarum\Api\Endpoint\Endpoint.
*/
public function endpointsAfter(string $after, callable|string $endpoints): self
{
$this->endpointsAfter[] = [$after, $endpoints];

return $this;
}

/**
* Add endpoints to the resource before all other endpoints.
*
* @param string $after the name of the endpoint to add the new endpoints after.
* @param callable|class-string $endpoints must be a callable that returns an array of objects that implement \Flarum\Api\Endpoint\Endpoint.
*/
public function endpointsBeforeAll(callable|string $endpoints): self

Check failure on line 92 in framework/core/src/Extend/ApiResource.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.2

PHPDoc tag @param references unknown parameter: $after

Check failure on line 92 in framework/core/src/Extend/ApiResource.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.4

PHPDoc tag @param references unknown parameter: $after
{
$this->endpointsBefore[] = [0, $endpoints];

return $this;
}

/**
* Remove endpoints from the resource.
*
Expand Down Expand Up @@ -214,6 +255,31 @@ function (array $endpoints, Resource $resource) use ($container): array {
$endpoints = array_merge($endpoints, $newEndpointsCallback());
}

foreach ($this->endpointsBefore as [$before, $newEndpointsCallback]) {
$newEndpointsCallback = ContainerUtil::wrapCallback($newEndpointsCallback, $container);

if ($before === 0) {
array_unshift($endpoints, ...$newEndpointsCallback());
} else {
$newEndpoints = $newEndpointsCallback();
$beforeIndex = array_search($before, array_column($endpoints, 'name'));

if ($beforeIndex !== false) {
array_splice($endpoints, $beforeIndex, 0, $newEndpoints);
}
}
}

foreach ($this->endpointsAfter as [$after, $newEndpointsCallback]) {
$newEndpointsCallback = ContainerUtil::wrapCallback($newEndpointsCallback, $container);
$newEndpoints = $newEndpointsCallback();
$afterIndex = array_search($after, array_column($endpoints, 'name'));

if ($afterIndex !== false) {
array_splice($endpoints, $afterIndex + 1, 0, $newEndpoints);
}
}

foreach ($this->removeEndpoints as $removeEndpointClass) {
[$endpointsToRemove, $condition] = $removeEndpointClass;

Expand Down
61 changes: 61 additions & 0 deletions framework/core/tests/integration/extenders/ApiResourceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use Carbon\Carbon;
use Flarum\Api\Context;
use Flarum\Api\Endpoint\Endpoint;
use Flarum\Api\Endpoint\Index;
use Flarum\Api\Endpoint\Show;
use Flarum\Api\Resource\AbstractDatabaseResource;
Expand Down Expand Up @@ -91,6 +92,66 @@ public function after_endpoint_callback_works_if_added()
$this->assertEquals('dataSerializationPrepCustomTitle', $payload['data']['attributes']['title'], $body);
}

#[Test]
public function custom_endpoint_works_if_added()
{
$this->extend(
(new Extend\ApiResource(DiscussionResource::class))
->endpoints(fn () => [
Endpoint::make('custom')
->route('GET', '/{id}/custom')
->action(function (Context $context) {
$discussion = $context->model;

return [
'data' => [
'message' => 'custom endpoint '.$discussion->id,
],
];
}),
])
);

$response = $this->send(
$this->request('GET', '/api/discussions/1/custom', [
'authenticatedAs' => 1,
])
);

$payload = json_decode($body = $response->getBody()->getContents(), true);

$this->assertEquals('custom endpoint 1', $payload['data']['message'], $body);
}

#[Test]
public function custom_endpoint_works_if_added_before_all()
{
$this->extend(
(new Extend\ApiResource(DiscussionResource::class))
->endpointsBeforeAll(fn () => [
Endpoint::make('custom')
->route('GET', '/custom')
->action(function (Context $context) {
return [
'data' => [
'message' => 'custom endpoint',
],
];
}),
])
);

$response = $this->send(
$this->request('GET', '/api/discussions/custom', [
'authenticatedAs' => 1,
])
);

$payload = json_decode($body = $response->getBody()->getContents(), true);

$this->assertEquals('custom endpoint', $payload['data']['message'], $body);
}

#[Test]
public function after_endpoint_callback_works_with_invokable_classes()
{
Expand Down

0 comments on commit 6780af1

Please sign in to comment.