Luke Curtis

Luke Curtis

Software Developer and Project Manager

Contact Me

A Full API RESTful Query Builder in Minutes

22/01/2019 (2 months ago) | Luke Curtis

Writing a RESTful API can sometimes be a little tricky. You find yourself sometimes writing functions that go way beyond the scope of what is actually means to be RESTful endpoint.

In this blog I'm going to go over what I believe to be the most rapid and scalable method of creating a query builder that actually works.

The Laravel package we're going to utilise is: Spatie query builder and the frontend Vue package we're going to use is: Vue Api Query

Let's get started.

Laravel

I'm going to assume you're already familiar with setting up routes/models/controller with Laravel so here's the code for that:

Simply run php artisan make:model Post -a and put the following in your migration
Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('user_id');
            $table->text('text');
            $table->foreign('user_id')->references('id')->on('users');
            
            $table->timestamps();
        });

In your model do the following
use App\Models\User;
class Post extends Model
{
    //
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}



Then put the following in your api.php file (note that I have moved the PostController class into it's own folder name `Api`
use App\Http\Controllers\Api\PostController;
Route::resource('post', PostController::class);

Now you can go ahead and install the query builder package composer require spatie/laravel-query-builder


Now we're ready to configure our endpoint to get posts with certain filters, included relations (such as the author) and sorts. So in the index of your PostController you might want to do something like the following:

use Spatie\QueryBuilder\QueryBuilder;
public function index()
{
    //
    return QueryBuilder::for(Post::class)
               ->allowedFilters('user_id')
               ->allowedIncludes('user')
               ->get();
}

Notice how we're getting the post and specifying what filters are allowed and also what includes are allowed. So in this example we're saying we can include the user in a object on the post that is returned from the endpoint.

So now we're technically ready to call the following: /api/post?include=user&filter[user_id]=1


Great you'll see that it works now when you try and query this endpoint. Let's move onto the frontend

Vue

Now we're ready to tackle the frontend. As I said we'd be using Vue Api Query to do this.

npm i vue-api-query


First things first, lets set up a base model that our API query package can hook into. So go ahead and create a file in resources/js/models called Model.js


The next thing we need to do is tell this base model what it's using for its API requests (in this instance it's axios) and what the base URL should be for all our models going forward. You can do this with a Laravel Mix env variable, but for this tutorial, I'm gonna go ahead and hard code it
import { Model as BaseModel } from 'vue-api-query'

export default class Model extends BaseModel {

  // define a base url for a REST API
  baseURL () {
    return ‘https://myapp.test/api';
  }

  // implement a default request method 
  request (config) {
    return this.$http.request(config)
  }
}


Great, now lets create a Post.js in the same directory with the following:
import Model from './Model'

export default class Post extends Model {
    resource()
    {
      return ‘post’
    }
}

Notice how we're extending our base model (to get the correct endpoint) and overriding the resource method to specify which endpoint we'll be using. The one we set up earlier.


Now we're ready to go ahead and get theses posts from the backend and display on our frontend using a pure query builder. So let's set up that route in your web.php file.
Route::get('post', function(){
    return view('posts.index');
});

And then we can create the file resources/posts/index.blade.php with the following (I've removed all the additional stuff for ease of reading but all you really need to do is register the component here:
< posts-index />

Once you've registered the component by creating an empty file such as resources/js/components/PageIndex.vue with something like Vue.component('pages-index', require('./components/PageIndex.vue')); in your app.js we can go ahead and code up this Vue component

To do that you'll need to do something like the following, notice how we're using async and we run a <code>.then((res) => {});</code> to signify that once the async function is complete we can bind that data to our Vue component.

The full Vue component

The full Vue component


If you run up /posts on your test domain you'll see that the posts are now loaded from the API and displayed on the frontend!