Todo Resources

Sixth Lesson in the Vue-Todo Series

Posted on July 29, 2016 in Laravel PHP Framework, Vue-Todo Series, vue.js

Todo Resources

We are going to be creating the resources required to implement our Todo part of the API. What is going to be needed? We will need a new controller to handle the CRUD functions. We will need a new model to hold our logic. We will also need a new migration to create the database, and we will need to setup our API endpoints.

Database and Model

Let's create our database migration and model. We can do this in one command via the terminal and Laravel's artisan feature. Run the following from your terminal:

php artisan make:model Todo -m

If all goes correctly, you should see a message saying your model was created, and the migration has also been created. Let's first open and modify the newly created migration. It will be located here database/migrations and be named **_**_**_**_create_todos_table.php. Add the following to the file:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTodosTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('todos', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned();
            $table->string('title');
            $table->boolean('completed')->default(false);
            $table->timestamps();

            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('todos');
    }
}

We are creating a new table with an id column which is our primary key and auto-incremental column. We are also adding user_id so we can identify which todos belong to which user. We are also creating a foreign key, which if the user account gets deleted all of their todos will also get removed. We have a title column which will be our todo, and we have a boolean column called completed which will be defaulted to false. From your terminal run the following:

php artisan migrate

You will get a message saying Migrated: **_**_**_**_create_todos_table. Great, we now have our new table in our database. Let's openTodo.phpand update accordingly. The file is located hereapp/Todo.php`.

<?php

namespace App;

class Todo extends Model
{
    protected $fillable = ['title', 'completed'];

    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

OK, we have added the title and completed to the $fillable variable. We have also created a new function within the class called user(). What we are doing here is defining a relationship between our Todo's and Users. The relationship will be that a User has many Todos, but a Todo belong's to a User. You can read more about Laravel's Eloquent Relationships here. We now need to define the reverse relationship within our User.php model. Open app/User.php and add the following function after the protected $hidden variable.

public function todos()
{
    return $this->hasMany('App\Todo');
}

Now that we have our database table and our model let's create some todos using Laravel's database seeder. First off let's create our Todo factory. Open database/ModelFactory.php and add the following to the bottom of the file.

$factory->define(App\Todo::class, function (Faker\Generator $faker) {
    return [
        'title' => $faker->sentence,
        'user_id' => 1
    ];
});

Now open database/seeds/DatabaseSeeder.php and add the following to the run() method.

factory(App\Todo::class, 10)->create();

Now from the terminal run php artisan db:seed. The console should not return any errors and will likely look like it hasn't done anything. So how can we check the factory worked. Well, you could open the SQLite database in an application or you can use php artisan tinker from within your terminal. Let's see how we can do it using tinker. From your terminal run php artisan tinker. You should see

Image of Artisan tinker

Now enter the following lines. After each one press the return key and then type the next line.

  1. $user = App\User::find(1);
  2. $user->todos;

You should see a list of ten todos we just created using the seeder. How great is that? We have the function todos from our User model which we created earlier. This is the power of Eloquent Relationships which makes it so easy to get the data we need. If you type exit within the terminal, it will exit the tinker program.

Todo controller

Let's create our TodosController. Create it here app/Api/Controllers and add the following:

<?php

namespace Api\Controllers;

use App\Todo;
use Dingo\Api\Facade\Api;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use Api\Transformers\TodoTransformer;

class TodosController extends BaseController
{
    public function getUsersTodos()
    {
        $user = JWTAuth::parseToken()->authenticate();
        $todos = $user->todos;

        return $this->collection($todos, new TodoTransformer());
    }
}

We will create the remaining methods in future lessons when we come to use them. So what are we doing here? We have created a function called getUsersTodos() which is getting the authenticated user from the token provided. We are then getting the users todos and returning them as a collection and running them through the TodoTransformer, which we will create now. Create a new file here app/Api/Transformers/TodoTransformer.php and add the following:

<?php

namespace Api\Transformers;

use App\Todo;
use League\Fractal\TransformerAbstract;

class TodoTransformer extends TransformerAbstract
{
    public function transform(Todo $todo)
    {
        return [
            'id'    => (int) $todo->id,
            'title' => $todo->title,
            'completed' => (bool) $todo->completed,
            'created'   => $todo->created_at->toIso8601String(),
            'updated'   => $todo->updated_at->toIso8601String()
        ];
    }
}

So, much of the above is similar to the UserTransformer, but we are casting the completed value to bool. Why do this? Well if we didn't it would return either 1 for a true value or 0 for a false value. What we will get now is either true or false depending on the todo status. This is much nicer to work with. Now open app/Http/routes.php add the following under the $api->get('users/details', 'AuthController@authenticatedUser'); entry:

$api->get('todos', 'TodosController@getUsersTodos');

So we have added a new endpoint to our API under the jwt.auth group which will keep our endpoint only accessible to authenticated users. Let's test the endpoint. Open Postman and get a new token for the test user created in an earlier tutorial. Once you have the token update the header value with the new token and make sure Postman is set to send a GET request to http://vue-todo-series.dev/api/todos and you should hopefully see the following:

Image of Postman Todos

Next Time

In the next tutorial we will start creating our Frontend application to start seeing our API in use using Vue.js.


comments powered by Disqus