tobyzerner / json-api-server

A JSON:API server implementation in PHP.
https://tobyzerner.github.io/json-api-server/
MIT License
63 stars 21 forks source link

Allow registration of custom actions #36

Open tobyzerner opened 3 years ago

tobyzerner commented 3 years ago

For implementing behavior not defined by the spec.

Something like:

$type->resourceAction('publish', function ($model, Context $context) {
    $model->publish();
    return $model;
})
    ->authorized(...);

$type->collectionAction('purge', function (Context $context) {
    Post::delete();
    return new Response(204);
})
    ->method('delete')
    ->authorized(...);

Call via:

POST /api/posts/1/actions/publish
DELETE /api/posts/actions/purge
tobyzerner commented 1 year ago

Now technically possible with custom endpoints in v1.0. Providing some Action endpoints out of the box planned for v1.1

bertramakers commented 1 year ago

I'd be interested in this for some of our use-cases. Can you expand on how it is already possible with custom endpoints?

tobyzerner commented 1 year ago

Create a new implementation of Tobyz\JsonApiServer\Endpoint\EndpointInterface - look at the existing implementations for examples (Show, Create, etc). Something like this:

class MyAction implements EndpointInterface
{
    public static function make(): static
    {
        return new static();
    }

    public function handle(Context $context): ?ResponseInterface
    {
        // Endpoint to handle POST /{resource}/my-action

        $segments = explode('/', $context->path());
        if (count($segments) !== 2 || $segments[1] !== 'my-action') {
            return null;
        }

        if ($context->method() !== 'POST') {
            throw new MethodNotAllowedException();
        }

        // Do stuff with $context->resource, $context->body(), etc

        return new Response(204);
    }
}

Then just add a new instance of your endpoint to the endpoints() array for any resources that should support it:

public function endpoints()
{
    return [Endpoint\Show::make(), MyAction::make()];
}

For 1.1 I'm planning to add generic action endpoints that you can instantiate with an action name and a handler function.