berlindb / core

All of the required core code
MIT License
255 stars 29 forks source link

Built in REST / GraphQL API #26

Open binaryfire opened 4 years ago

binaryfire commented 4 years ago

Hi all

I've been chatting to @JJJ via email regarding a baked-in REST / GraphQL API for BerlinDB and I figure it makes sense to open an issue for it. I'm hoping to use BerlinDB as the db engine for a headless project. Here are 2 features I'd love to see in an implementation:

  1. Built in caching using the Transients API, or at least native ways to enable caching and selectively flush endpoint caches. At the moment I'm using custom REST endpoints plus https://wordpress.org/plugins/wp-rest-cache/ and it makes a huge difference for performance. They also uses the Transients API which, meaning we can leverage Redis for API endpoints.

  2. This might not be possible, but is there a way of querying data without having to load the theme, all plugins etc first? My understanding is that both WPGraphQL and the REST API do this and that it really impacts performance. Since BerlinDB is designed to be a performance-oriented DB framework, some kind of bespoke API that is just as performance-oriented would be a good fit for the the project.

Is something like this planned and what would be an approximate timeframe for a dev version?

Cheers

alexstandiford commented 3 years ago

Hey there! Looking through the issues today and I stumbled on this one. Thought I'd add some insight to help move it along.

This might not be possible, but is there a way of querying data without having to load the theme, all plugins etc first

I've made several REST Endpoints using BerlinDB and it has ran with no issues. Based on that, I would say that yes, this is possible, and doesn't require any strange configuration to make it behave in this way.

approximate timeframe

Aaaabsolutely no idea!

Is something like this planned

I don't think anything is officially planned, but I have aspirations to be able to automatically query from BerlinDB a little easier. It's technically possible, but there's some hurdles we have to overcome before we can talk seriously about it in any way.

I think that if we were going to do this, we would probably need to add some arguments to the schema class to make it possible to determine which columns should be visible via REST, and probably add some kind of way to configure permissions for the table's REST Endpoint.

We can probably configure the REST response with the JSON Serializable interface, filtering out the items that should not be displayed in the REST endpoint.

GraphQL would be a completely different paradigm, but ideally we would be able to lean on the same schema to support both GraphQL and REST without adding a bunch of extra things in the process.

Mte90 commented 2 years ago

I was looking at the code to see how it is possible to implement it using the rest api from wordpress. I think that should be something that should enabled on Schema class, like:

public $columns = [

        //id
        'id'           => [
            'name'     => 'id',
            'type'     => 'bigint',
            'length'   => '20',
            'unsigned' => true,
            'extra'    => 'auto_increment',
            'primary'  => true,
            'sortable' => true,
            'rest' => array( // if this is not set it is disabled by default to not create compatibility issues
                'create' => true,
                'read' => true, // this will be in get like /wp/v2/<table name without prefix>/(?P<id>[\d]+)
                'update' => true,
                'delete' => true,
            // or
                'crud' => true // to enable all the CRUD cases
            // other options
                'search' => true, // enables something like &args=id,otherfield&search=[string] in this way it will enable to search by specific key
            )
        ],

To avoid custom callbacks and filters for the permission on the schema class it is the case to add some filters, like:

Create a class just for those filters to me seems a bit over engineering as often are very simple and those can be put also in other parts of the plugin code but if we want to enforce a code style with a class, a way can be create like a Rest_Callbacks class.
Like:

class Books_Rest extends \BerlinDB\Database\Rest {

    public function <key name>_read() {
        return current_user_can('manage_options');
    }

    public function <key name>_update_value( $value ) {
        if ( isNAN($value) ) {
            return new WP_Error( 'broke', __( "I've fallen and can't get up", "my_textdomain" ) );
        }
        return $value;
    }

In both the cases we can use permission_callback and sanitize_callback arguments of rest api, so in the library should be enough just declare the endpoints.

Mte90 commented 2 years ago

So I started working on a REST prototype in a custom repo with the wordpress-example: https://github.com/Mte90/BerlinDB-Rest

You can find a first implementation with some endpoints, the readme should include the various changes, what is implemented etc

I have some doubts about the internals stuff of BerlinDB so I think that you guys can help me and also review the code on that repo. My idea is to do 2 PR (core/example) when is finished without annoying there with discussions etc.

Mte90 commented 2 years ago

I implemented the CRUD methods and also search, so to me everything as starting point is there. I am looking for feedback, in the meantime I will improve the code etc.

As thre isn't any documentation is difficult to me see what I can add for REST...

Mte90 commented 2 years ago

Ok so just to let you know that I finished implementing the REST integration in my repo.

I am looking for feedbacks before to do a PR there in case there is something to do (maybe new endpoints?). I didn added anything for meta as example.

JJJ commented 2 years ago

I will review and leave comments there!

I am also very, very open to PRs here or changes to make adding any API on top of Berlin as simple as we can possibly make it. 💛

Really excited to see how you did!

Mte90 commented 2 years ago

And a pull request it's here https://github.com/berlindb/core/pull/150 :-)

Just reference my repo that has also the example working so you can see in action :-)