
사전준비
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