radiate-framework / framework

A WordPress plugin and theme framework
https://radiate-framework.github.io/
MIT License
4 stars 0 forks source link

API Resources #43

Closed BenRutlandWeb closed 3 years ago

BenRutlandWeb commented 3 years ago

Is your feature request related to a problem? Please describe. Creating a REST route to return posts - the posts are returned as WP_Post instances, which when encoded as JSON are ugly and full of superfluous data, increasing the response size.

Describe the solution you'd like It would be nice to have a transformer like laravel's JsonResource class to easily convert WP_Query results into a tidy API response. It would also be simple to create API resources with the cli make:resource. The resource class would have attribute accessors so you can write $post->title instead of $post->post_title. This would open up scope to apply filters to API responses in an OOP manner.

Define a resource:

class PostResource extends JsonResource
{
    public function toArray()
    {
        return [
            'id'          => $this->ID,
            'title'       => $this->title,
            'description' => $this->content,
            'slug'        => $this->slug,
            'created_at'  => $this->created_at,
            'updated_at'  => $this->updated_at,
        ];
    }
}

This would be used in a controller like so:

public function index()
{
  $query = WP_Query(['post_type' => 'post']);

  return PostResource::collection($query->posts);
}

This would also be usable in a non-api context, pretty much wherever WP_Query might be used.

Describe alternatives you've considered Manually looping through WP_Query responses and passing them into a class. This pattern is highly repeatable and would be better suited in the framework to simplify dev.

Additional context Until the framework has Eloquent or a similar, nice API for querying the database, specifically the posts table, using WP_Query is the most efficient way to retrieve data. Currently there is no way to change the underlying class used (WP_Post) meaning accessing properties is ugly, and processing for an API response a hefty manual task.

BenRutlandWeb commented 3 years ago

The resource class should be able to handle WP_Post, WP_Term and WP_User (may have missed some wp models). Whilst these all have similar methods, the API isn't consistent. Laravel's resource class relies on instances of Model being passed through.

One idea was to pass the resource a class that wrapped a wp class, this class then proxied the model which was then proxied by the resource class. This didn't work out so well - too many proxies. It also prevented simple model manipulation (aside: the framework currently has no model/db interface due to the varied APIs avaliable in wp. a consistent, simple API will need to be found before that aspect can be continued).

The resource class initially seems like a simple solution, however, how to handle the different classes (WP_User, WP_Term, WP_Post)?

Another idea instead of handling the logic inside the model or resource class is to pass a normalised array of attributes to the resource. I.e. Manually transform a model into an array of attributes, then pass this to the resource class for further processing. In my eyes this results in almost as much boilerplate as the original problem.

What we need is a better way of quering the db so the result is already normalised. Perhaps that could be fluent wrappers around WP_Query.

BenRutlandWeb commented 3 years ago

A basic implementation has be created, ignoring the transform layer between WP_Post and a model with attribute mutators... this can be added in a later . For now, the $query->posts can be passed to a resource class and the underlying resource accessed, including with toArray method. This gives some verstility as to what resource is being manipulated.