7 min read

Laravel Restful API using Docker in three steps (Part I)

In this post series we will see how to build a Laravel Restful application. In addition we will see the basic functionalities of Eloquent ORM, tinker db queries and some relationships between Models.

This post was inspired by the book: Hands-On Full Stack Web Development with Angular 6 and Laravel 5, from Fernando Monteiro, released on July/2018 by Packt.

hands-full-stack-web-development-angular-6-and-laravel-5

We will split this tutorial in three steps. Let's see the first step right now:

1 - Preparing the Docker/Docker-compose environment.

First we are using the foundation (Nginx, MySQL, PHP, Dockerfile, Docker-compose) files for previous mentioned book.

Go to this link and download or clone the repository with the baseline config. For the purpose of this tutorial we will not go into details of the environment configuration, you can check the book to get all the details later.

After the download/clone the baseline environment config, your directory structure will look like this:

your-project-folder
  /docker/
    /nginx/
      nginx.conf
    /php-fpm/
      Dockerfile
  docker-compose.yml

Using Composer to create a Laravel application inside Docker container.

Now that we have a solid Docker baseline. The PHP image we used already has all the dependencies that Laravel needs to run the application including Composer package manager.

So we will use the Composer that we have inside the php-fpm container, this is the safest way to avoid conflicts between your machine/container Composer versions.

Open your Terminal window and type the following command:

docker-compose exec php-fpm bash

Still on your Terminal window, type the following command:

composer create-project laravel/laravel=5.6.12 server --prefer-dist

At the time of this example, we installed version 5.6.12 of Laravel, although we should have no problem installing a more current version, we strongly recommend that you keep the version in 5.6.*.

Note that we create the Laravel application inside a directory called server, this way we will have the following application structure:

your-project-folder
  /docker/
  /server/
  docker-compose.yml

Notice that we have separated the contents of the Laravel application from the Docker configuration folder. This practice is highly recommended since we can make any kind of changes within the project folder without damaging any Docker or docker-compose files accidentally.

Now we need to adjust the docker-compose.yml file, to fit the new path created.

Open docker-compose.yml and let's adjust the php-fpm volumes tag with the new path, as the following block of code:

    php-fpm:
      build: phpdocker/php-fpm
      container_name: php-fpm
      working_dir: /application
      volumes:
        - ./server:/application
        - ./phpdocker/php-fpm/php-ini-overrides.ini:/etc/php/7.2/fpm/conf.d/99-overrides.ini

For the change we just made take effect, we need to stop and restart our containers. Let's go to the next steps.

Still on your Terminal, type exit to exit the php-fpm bash. Now at the root of application folder, type the following command:

docker-compose kill

You must see the following output message:

Stopping webserver ... done
Stopping mysql     ... done
Stopping php-fpm   ... done

On your Terminal type the following command to run the containers again:

docker-compose up -d

And now we can see that php-fpm was recreated and now will reflect our changes:

Recreating php-fpm ... done
Starting webserver ... done
Starting webserver ... done

It is highly recommended that you repeat this procedure whenever you make any changes to the nginx and php-fpm servers.

Now let's check the Laravel installation and configuration, open your default browser and go to the following link: http://localhost:8081/

Great! Congratulations you should see the Laravel welcome page.

Configuring the .env file.

Open .env file at the root of project folder and replace the database config, for the following lines:

  DB_CONNECTION=mysql
  DB_HOST=mysql
  DB_PORT=3306
  DB_DATABASE=databasename
  DB_USERNAME=databaseuser
  DB_PASSWORD=123456

Let's check the connection. Inside the Terminal window type the following command to go inside the php-fpm bash:

docker-compose exec php-fpm bash

Inside the php-fpm bash, type the following command:

php artisan tinker

And finally, type the following command: DB::connection()->getPdo();, you must see something similar to the following output:

=> PDO {#760
     inTransaction: false,
     attributes: {
       CASE: NATURAL,
       ERRMODE: EXCEPTION,
       AUTOCOMMIT: 1,
       PERSISTENT: false,
       DRIVER_NAME: "mysql",
       SERVER_INFO: "Uptime: 2491  Threads: 1  Questions: 9  Slow queries: 0  Opens: 105  Flush tables: 1  Open tables: 98  Queriesper second avg: 0.003",
       ORACLE_NULLS: NATURAL,
       CLIENT_VERSION: "mysqlnd 5.0.12-dev - 20150407 - $Id: 38fea24f2847fa7519001be390c98ae0acafe387 $",
       SERVER_VERSION: "5.7.21",
       STATEMENT_CLASS: [
         "PDOStatement",
       ],
       EMULATE_PREPARES: 0,
       CONNECTION_STATUS: "mysql via TCP/IP",
       DEFAULT_FETCH_MODE: BOTH,
     },
   }

This means everything goes well. Congratulation we have a database up and running.

Creating Migrations and Database seed.

Now, the funny part will start right now, let's create a Model.

Remember you should running every Artisan command inside the php-fpm bash to avoid compatibility issues.

Open your Terminal window inside your-project folder and type the following command:

docker-compose exec php-fpm bash

Inside bash, type the following command:

php artisan make:model Band -m

Note the flag -m that we are using to create the migration file together with the Model creation. So now we have two new files on our Application.

  • server/app/Band.php
  • server/database/migrations/###_##_##_######_create_bands_table.php

Creating the migration boilerplate

The newly created files only have the boilerplate code generated by Laravel engine. Let's add some content to Band Model and migration file.

Open server/app/Band.php and add the following code, inside the Band Model function:

    protected $fillable = [
        'name',
        'country',
        'genre'
    ];

Now we need to add the same properties to the migration file created before. Open server/database/migrations/####_##_##_######_create_bands_table.php and add the following properties inside the up() function:

    $table->string('name');
    $table->string('country');
    $table->string('genre');

Well, congratulations we created our first migration file and it is time to execute the command to feed our database.

Open your Terminal window and type the following command:

php artisan migrate

The output of the previous command will be similar to the following:

Migration table created successfully.
Migrating: ####_##_##_######_create_users_table
Migrated:  ####_##_##_######_create_users_table
Migrating: ####_##_##_######_create_password_resets_table
Migrated:  ####_##_##_######_create_password_resets_table
Migrating: ####_##_##_######_create_bands_table
Migrated:  ####_##_##_######_create_bands_table

Creating our first database seed using a JSON file

Instead use the popular Faker library to create our data, we will use an external JSON file with the data we want to insert into our database. Although Faker is a very useful tool, easy and fast to create data during the development of applications with Laravel. In this example we want to keep the control over the data created.

  • Inside the server/database folder, create a new folder called: data-sample.
  • Inside the server/database/data-sample folder, create a new file called: bands.json and add the following code:
[{
	"id": 1,
	"name": "Motorhead",
	"country": "England",
	"genre": "Heavy Metal"
}, {
	"id": 2,
	"name": "Slayer",
	"country": "USA",
	"genre": "Thrash Metal"
}, {
	"id": 3,
	"name": "Truckfighters",
	"country": "Sweeden",
	"genre": "Stoner Rock"
}]

Now it's time to create our seed file, on your Terminal window type the following command:

  php artisan make:seeder BandsTableSeeder

The previous command added a new file called: BandsTableSeeder.php inside: server/database/seeds folder.

Open server/database/seeds/BandsTableSeeder.php and replace the code for the following block of code:

  use Illuminate\Database\Seeder;
  use App\Band;

  class BandsTableSeeder extends Seeder
  {
      /**
       * Run the database seeds.
       *
       * @return void
      */
      public function run()
      {
          DB::table('bands')->delete();
          $json = File::get("database/data-sample/bands.json");
          $data = json_decode($json);
          foreach ($data as $obj) {
            Bike::create(array(
                'id' => $obj->id,
                'name' => $obj->name,
                'country' => $obj->country,
                'genre' => $obj->genre
            ));
          }
      }
  }

Note the first line we using the Eloquent ORM shortcut (DB::table()) to previously delete the bands tables if exist. On next post we go deeper on Eloquent ORM, for now let's focus on create our first seed.

Open server/database/seeds/DatabaseSeeder.php and add the following line of code, right after the UsersTableSeeder comment:

  $this->call(BikesTableSeeder::class);

You can read more about Eloquent ORM at chapter 5 - Creating a Restful API using Laravel Framework (Part I).

Now is time to running our seed and fill the database. We can do this in two ways, we can just run the BandSeeder command: php artisan db:seed --class=BandsTableSeeder individually or use the command: php artisan db:seed that will run all seeds in our project.

As we are at the beginning of our development we will execute the command to load all the seeds.

Open your Terminal window and type the following command:

php artisan db:seed

At the end of the previous command we see a success message Seeding: BandsTableSeeder, Bravo! now we have our first records on our database. Let's check the records.

Still on you terminal window, type the tinker command:

php artisan tinker

Now let's check our database table with the following command:

DB::table('bands')->get();

The output on terminal window will be something like a JSON representing the three records with our bands.

This post was inpired by the book: Hands-On Full Stack Web Development with Angular 6 and Laravel 5, from Fernando Monteiro, released on July/2018 by Packt.

Continues on the next post...