DEV Community

pirvanm
pirvanm

Posted on

How do you make FullStack Demo App for Interviews using Laravel + React with Dockerize Part 3

This is a new part of my Laravel + React dockerized series. Before moving on, you can check out the previous parts.

Laravel + React and Docker Part 1
Laravel + React and Docker

I will continue now with the next part of the backend. This time, we’ll go a little deeper into Laravel, and even touch on some PHP-level details, starting with the bootstrap file located in:

backend/bootstrap
/app.php

Basically, we slightly overwrote Laravel’s core:

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        //
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();
Enter fullscreen mode Exit fullscreen mode

I added four lines to bring the API into our app, which improves performance and reminds me of Lumen, or even other microframeworks like Slim PHP.

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withProviders([
            App\Infrastructure\Providers\AppServiceProvider::class,
    ])
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
        then: function () {

        }
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->statefulApi();
        $middleware->redirectGuestsTo('/v1/login');
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();
Enter fullscreen mode Exit fullscreen mode

Because we want to communicate between the backend and frontend via HTTP, we need to allow access in Laravel by defining some configurations. One of them is creating a new file in backend/config named cors.php with the following code:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */

    'paths' => ['api/*', 'sanctum/csrf-cookie', "*"],

    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => false,

];
Enter fullscreen mode Exit fullscreen mode

We are still working in the config folder, but this time we overwrite an existing file instead of creating a new one: database.php.

Inside the 'sqlite' => [ section, after 'synchronous' => null, we add:

'transaction_mode' => 'DEFERRED',
Enter fullscreen mode Exit fullscreen mode

At the JavaScript level, Axios is already included in Laravel 12, so there’s no need to install it separately. Since we are not using Inertia or Blade in Laravel, we can skip the resources/views folder.

There are no navigation pages, commands, or console interactions on the Laravel backend side, so in this case we can also skip web.php and console.php from the routes folder.

However, some routes are still required to send data from the database to React. For this purpose, we use api.php in the routes folder, which contains the following code:

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Infrastructure\Http\Controllers\API\User\MeController;
use App\Infrastructure\Http\Controllers\API\User\LoginController;
use App\Infrastructure\Http\Controllers\API\User\LogoutController;
use App\Infrastructure\Http\Controllers\API\User\RegisterController;
use App\Infrastructure\Http\Controllers\API\Mentor\MentorListController;
use App\Infrastructure\Http\Controllers\API\Mentor\MentorProfileController;

// we can have the api routes here, no issue
Route::prefix('v1')->group(function () {
    Route::middleware('guest')->group(function () {
        Route::post('/register', RegisterController::class);
        Route::post('/login', LoginController::class);
        Route::get('/mentors', MentorListController::class);
        Route::get('/mentors/{id}', MentorProfileController::class);
    });

    Route::middleware('auth:sanctum')->group(function () {
        Route::get('/me', MeController::class);
        Route::post('/logout', LogoutController::class);
    });
});
Enter fullscreen mode Exit fullscreen mode

Even though we are not talking about Sail, we should still discuss composer.json. We also mention Docker briefly, since in this case it’s just a small part.

Because we updated the folder structure to follow DDD, we defined our own namespaces. We then used them in our code, and it looks like this:

in array : "autoload": {
"psr-4": {

}
I added:

"App\\Domain\\": "app/Domain",  
"App\\Application\\": "app/Application",  
"App\\Infrastructure\\": "app/Infrastructure"
Enter fullscreen mode Exit fullscreen mode

And finally, it looks like this:

"autoload": {
        "psr-4": {
            "App\\": "app/",
            "App\\Domain\\": "app/Domain",
            "App\\Application\\": "app/Application",
            "App\\Infrastructure\\": "app/Infrastructure",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    },
Enter fullscreen mode Exit fullscreen mode

The rest is the same with compose.json. The final step to dockerize a basic Laravel app is as follows: in the backend folder, create a new folder called docker. Inside it, create a file named Dockerfile (without any extension). Also, inside the docker folder, create another folder called nginx.

Our Dockerfile contains the following code:

# docker/Dockerfile
FROM php:8.3-fpm

# Install system dependencies including PostgreSQL dev headers
RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    unzip \
    libpq-dev   
RUN rm -rf /var/lib/apt/lists/*

# Install PHP extensions (now pdo_pgsql will work)
RUN docker-php-ext-install pdo pdo_pgsql mbstring exif pcntl bcmath

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

WORKDIR /var/www/html

# Copy composer files
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-scripts

# Copy the rest of the application
COPY . .

# Fix permissions
RUN chown -R www-data:www-data /var/www/html \
    && chmod -R 775 storage bootstrap/cache

EXPOSE 9000

CMD ["php-fpm"]

Enter fullscreen mode Exit fullscreen mode

Our last file default.conf which is inside of nginx folder had following code :

server {
    listen 80;
    server_name localhost;
    root /var/www/html/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME /var/www/html/public/index.php;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}

Enter fullscreen mode Exit fullscreen mode

To start this project (backend only for now), you need to follow these steps:

Install backend
Infrastructure following the DDD(ish) way of organizing the application.

1.cd backend

2.cp .env.example .env

3../dc.sh build ( docker compose buid )

4../dc.sh up -d ( docker compose up -d )

5../install.sh ( composer install, migrate and seed database )

Backend URL: http://localhost:8001/

Enter fullscreen mode Exit fullscreen mode

I hope we can move forward with React after this. If you need a course—whether you’re at a junior or senior level—feel free to message me, or you can follow me on LinkedIn at LevelCoding

Top comments (0)