카테고리 없음

Laravel 10. API Development

테디아저씨 2026. 5. 9. 09:05

 

 

사전준비

pakistan_cities.csv

 

 


database/seeders/seederData/pakistan_cities.csv

 

 

Model

php artisan make:model Address -m

 

database/migrations/xxxxx_create_addresses_table.php

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('addresses', function (Blueprint $table) {
            $table->id();
            $table->string('wikiDataId',50)->nullable();
            $table->string('type',50)->nullable();
            $table->string('city',50)->nullable();
            $table->string('name',50)->nullable();
            $table->string('country',50)->nullable();
            $table->string('countryCode',50)->nullable();
            $table->string('region',50)->nullable();
            $table->string('regionCode',50)->nullable();
            $table->string('regionWdId',100)->nullable();
            $table->decimal('latitude', 11, 8)->nullable();
            $table->decimal('longitude', 11, 8)->nullable();
            $table->integer('population')->default(0);

            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('addresses');
    }
};

 

make table

php artisan migrate

 

 

Data

 

Address.php

php artisan make:seeder AddressSeeder

 

 

database\seeders\AddressSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class AddressSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        //

        $csvFile = fopen('database/seeders/seederData/pakistan_cities.csv', "r");
        $isFirstRow = true; // Flag to skip the first row

        while (($data = fgetcsv($csvFile, 1000, ",")) !== FALSE) {
            if ($isFirstRow) {
                $isFirstRow = false; // Skip the first row
                continue;
            }

            \App\Models\Address::create([
                'id' => $data[0],
                'wikiDataId' => $data[1],
                'type' => $data[2],
                'city' => $data[3],
                'name' => $data[4],
                'country' => $data[5],
                'countryCode' => $data[6],
                'region' => $data[7],
                'regionCode' => $data[8],
                'regionWdId' => $data[9],
                'latitude' => $data[10],
                'longitude' => $data[11],
                'population' => $data[12],
            ]);
        }

    }
}

 

seeding

php artisan db:seed AddressSeeder

 

 

app/Models/Address.php

 

 

 

 

 

 

 

 

기존 웹 개발방식

브라우저요청 => HTML 반환

 

return view('posts.index',["posts"=>$posts]);

 

web

routes/web.php

 

 

api 개발방식

  • 모바일 앱
  • React/Vue 프론트엔드
  • 외부 서비스 연동
return response()->json($posts);

 

api 

routes/api.php

 

기본적으로 /api   를 추가로 가져간다.

 

** 11 버젼부터는 자동생성이 아닙니다.

** starter 구조가 많이 간소화됐습니다.

** 사용을 위해서 

 

bootstrap/app.php

->withRouting(
    web: __DIR__.'/../routes/web.php',
    commands: __DIR__.'/../routes/console.php',
    health: '/up',
)

 

=>

->withRouting(
    web: __DIR__.'/../routes/web.php',
    api: __DIR__.'/../routes/api.php',
    commands: __DIR__.'/../routes/console.php',
    health: '/up',
)

 

 

 

Api/TruckRequestController.php

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Truck;

class TruckController extends Controller
{
    //
    public function index()
    {
        $trucks = Truck::all();
        return response()->json($trucks);
    }
}

 

routes/api.php

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\TruckController;

Route::get('/truck', [TruckController::class, 'index'])->name('truck.index');

 

http://127.0.0.1:8000/api/truck

 

 

 

 

 

 

 

Model

php artisan make:model TruckRequest -m

 

database/migrations/xxxx_create_truck_requests_table.php

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('truck_requests', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained('users')->comment('user id');
            $table->string('name',50)->nullable()->comment('user name');
            $table->string('phone',50)->nullable()->comment('user phone');
            $table->datetime('request_date')->nullable()->comment('request date');
            $table->string('start_address',100)->nullable()->comment('start address');
            $table->string('end_address',100)->nullable()->comment('end address');
            $table->string('weight',50)->nullable()->comment('weight');
            $table->string('description',50)->nullable()->comment('description');
            $table->string('status',1)->nullable()->comment('1: applying, 2: approved, 3: rejected');            
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('truck_requests');
    }
};

 

php artisan migrate

 

 

API 컨트롤러 생성

php artisan make:controller Api/TruckRequestController -r

or 

php artisan make:controller Api/TruckRequestController --resource

 

* Api 를 붙인것은 폴더를 구분하고자 한 것일뿐 필수는 아닙니다.

* -r 

 

 

 

view

resources/views/request/form.blade.php

<html>
<head>
    <title>Transportation HTML-5 Template </title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
    <div class="container mt-5">
        <h2>Request a Quote</h2>

            <!-- form -->
            <form id="request_form" method="POST" class="contact-form">
                @csrf
                <div class="row ">
                    <div class="col-lg-6 col-md-6 mb-3">
                        Name
                        <div class="input-form">
                            <input type="text" name="name" placeholder="Name" class="form-control">
                        </div>
                    </div>
                    <div class="col-lg-6 col-md-6 mb-3">
                        Email
                        <div class="input-form">
                            <input type="text" name="email" class="form-control" placeholder="Email">
                        </div>
                    </div>
                    <div class="col-lg-6 col-md-6 mb-3">
                        <label>Freight Type</label>
                        <div class="select-items">
                            <select name="category" class="form-control">
                                <option value="">선택</option>
                                <option value="general">일반 화물</option>
                                <option value="refrigerated">냉장</option>
                                <option value="hazardous">위험물</option>
                            </select>
                        </div>
                    </div>
                    <div class="col-lg-6 col-md-6 mb-3">
                        <label>Departure City</label>
                        <div class="input-form">
                            <input type="text" name="departure" class="form-control" placeholder="City of Departure">
                        </div>
                    </div>
                    <div class="col-lg-6 col-md-6 col-sm-6">
                        <label>Destination</label>
                        <div class="input-form">
                            <input type="text" name="destination" class="form-control" placeholder="City of Destination">
                        </div>
                    </div>

                    <div class="col-lg-12 col-md-12 mb-3">
                        <label>Weight</label>
                        <div class="input-form">
                            <input type="text" name="weight" class="form-control" placeholder="Weight">
                        </div>
                    </div>
                    <!-- Checkbox -->
                    <div class="col-lg-12 mb-3">
                        <div class="radio-wrapper mb-30 mt-15">
                            <label>Extra services:</label>
                            <div class="select-radio d-flex gap-3 flex-wrap">
                                <div class="checkbox d-flex align-items-center">
                                    <input id="checkbox-2" name="service_express" type="checkbox">
                                    <label for="checkbox-2" class="radio-label ms-2 mb-0">Express Delivery</label>
                                </div>
                                <div class="checkbox d-flex align-items-center">
                                    <input id="checkbox-4" name="service_insurance" type="checkbox">
                                    <label for="checkbox-4" class="radio-label ms-2 mb-0">Insurance</label>
                                </div>
                                <div class="checkbox d-flex align-items-center">
                                    <input id="checkbox-5" name="service_packaging" type="checkbox">
                                    <label for="checkbox-5" class="radio-label ms-2 mb-0">Packaging</label>
                                </div>
                            </div>
                        </div> 
                    </div>
                </div>
            </form>	
            <div id="response_message" class="mt-3"></div>
            <!-- Button -->
            <div class="col-lg-12">
                <button type="button" onclick="create_request()" class="btn btn-primary">Request a Quote</button>
            </div>
    </div>
    <script>
        function create_request() {
            var box = document.getElementById('response_message');
            box.textContent = '';

            fetch('/api/truck_request/request', {
                method: 'POST',
                body: new FormData(document.getElementById('request_form')),
                headers: {
                    Accept: 'application/json',
                    'X-Requested-With': 'XMLHttpRequest',
                },
            })
                .then(function (response) {
                    return response.json().then(function (data) {
                        if( response.ok ) {
                            box.className = 'mt-3 text-success';
                            box.textContent = '요청 성공';
                        } else {
                            box.className = 'mt-3 text-danger';
                            box.textContent = '요청 실패';
                        }
                        //box.className = 'mt-3 p-3 bg-light border rounded small';
                        box.textContent = JSON.stringify(data, null, 2);
                    });
                })
                .catch(function () {
                    box.className = 'mt-3 text-danger';
                    box.textContent = '요청 실패';
                });
        }
    </script>
    

</body>
</html>

 

 

 

php artisan make:controller RequestController -r

 

    public function create()
    {
        // form
        return view('request.form');
    }

 

api/

use App\Http\Controllers\Api\TruckRequestController;
...


Route::post('/truck_request/request', [TruckRequestController::class, 'store'])->name('truck_request.store');

 

route

use App\Http\Controllers\RequestController;

Route::middleware('auth')->group(function () {
    Route::get('/dashboard', [IndexController::class, 'dashboard'])->name('dashboard');
    Route::get('/myphoto', [UserController::class, 'myphoto'])->name('myphoto');
    Route::post('/myphoto', [UserController::class, 'myphoto_submit'])->name('myphoto.submit');
    Route::post('/myphoto/delete', [UserController::class, 'myphoto_delete'])->name('myphoto.delete');


    Route::get('/mytruck', [TruckController::class, 'mytruck'])->name('mytruck');
    Route::get('/truck_form', [TruckController::class, 'truck_form'])->name('truck_form');
    Route::post('/truck', [TruckController::class, 'truck_store'])->name('truck.store');


    // request
    Route::get('/request_form', [RequestController::class, 'create'])->name('request.create');
});

 

 

Create

    public function store(Request $request)
    {

        // Accept: application/json 이면 실패 시 자동 422 + { message, errors } JSON
        $validated = $request->validate([
            'name' => 'required|string|min:2|max:100',
            'email' => 'required|email|max:100',
            'category' => 'required|string|max:100',
            'weight' => 'required|string|max:50',
            'departure' => 'required|string|max:100',
            'destination' => 'required|string|max:100',
        ], [
            'name.required' => '이름을 입력해 주세요.',
            'email.required' => '이메일을 입력해 주세요.',
            'category.required' => '화물 유형을 선택해 주세요.',
            'weight.required' => '중량을 입력해 주세요.',
            'departure.required' => '출발지를 입력해 주세요.',
            'destination.required' => '도착지를 입력해 주세요.',
        ]);
        //
        $truckRequest = TruckRequest::create([
            'name' => $validated['name'],
            'email' => $validated['email'],
            'category' => $validated['category'],
            'weight' => $validated['weight'],
            'departure' => $validated['departure'],
            'destination' => $validated['destination'],
            'service_express' => $request->boolean('service_express'),
            'service_insurance' => $request->boolean('service_insurance'),
            'service_packaging' => $request->boolean('service_packaging'),
            'status' => '1',
        ]);

        if( $truckRequest ) {
            return response()->json(['message' => 'Truck request created successfully'], 201);
        } else {
            return response()->json(['message' => 'Truck request creation failed'], 400);
        }
    }

 

List

 

view

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
  </head>
  <body>
    <div class="container mt-5 col-lg-3 col-md-4 col-sm-12 mx-auto">
        <div class="row">   
            <div class="col text-end">

                    <div class="">
                        @if( isset($user) && !empty($user) )
                            Welcome {{ $user['name'] }}
                            <a href="{{ route('mytruck') }}">My Truck</a>
                            <a href="{{ route('signout') }}">Logout</a>
                        @else
                            Welcome Guest
                            <a href="{{ route('login') }}">Login</a> | 
                            <a href="{{ route('register') }}">Register</a>
                        @endif
                    </div> 

            </div>
        </div>
        <div class="row text-center mt-5">   
            <h1>
                Request List Page
            </h1>
            <div class="row" id="request-list"></div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
    <script>
        fetch('/api/truck_request', { headers: { Accept: 'application/json' } })
            .then(function (res) { return res.json(); })
            .then(function (items) {
                var list = document.getElementById('request-list');
                if (!list || !Array.isArray(items)) return;
                items.forEach(function (item) {
                    list.innerHTML +=
                        '<div class="col-md-12 card mb-2"><div class="card-body">' +
                        '<p>' + item.name + '</p>' +
                        '<p>' + item.email + '</p>' +
                        '<p>' + item.weight + '</p>' +
                        '<p>' + item.departure + ' => ' + item.destination + '</p>' +
                        '</div>' +  
                        '<div class="card-footer">' + item.created_at.split('T')[0] + '</p>' +
                        '</div>';
                    });
                })
                .catch(function (err) { console.error('Error:', err); });
        </script>
    </body>
</html>

 

app/Http/Controllers/Api/TruckRequestController.php

    public function index()
    {
        //
        $truckRequests = TruckRequest::all();
        return response()->json($truckRequests);
    }

 

 

 

 

 

 

 

설명만

 

Update

public function update(Request $request, $id)
{
    $post = TruckRequest::find($id);
    $post->update($request->all());

    return response()->json($post);
}

 

Delete

public function destroy($id)
{
    Truck::destroy($id);

    return response()->json([
        'message' => '삭제 완료'
    ]);
}

 

Validation 는 동일합니다

$request->validate([
    'title' => 'required'
]);

 

예시

GET /api/posts
POST /api/posts
PUT /api/posts/1
DELETE /api/posts/1

 

 

POST Man

 

 

HTTP 상태

 

성공시

200 OK
201 Created

 

실패시

404 Not Found
422 Validation Error
500 Server Error

 

 

REST API

 

Resource