제5.2장: API를 위한 간단한 뷰 생성
학습 시간: 45분
1. 목표: 데이터 시각화
제2장에서 우리 API는 JSON 형식으로 데이터를 제공할 수 있습니다. 이는 기계에는 훌륭하지만, 사람들은 잘 꾸며진 웹페이지에서 정보를 보는 것을 선호합니다. 우리의 목표는 다음과 같은 두 가지 페이지를 만드는 것입니다:
- 모든 행성 목록 (
/planets
) - 단일 행성 페이지 (
/planets/{id}
)
이를 위해 우리는 "경로 → 컨트롤러 → 뷰" 조합을 사용할 것입니다.
💡 우주 비유:
API의 JSON은 원시 텔레메트리 데이터, 즉 단순히 숫자의 흐름이라고 상상해 보세요. 오늘 우리의 임무는 우주 관제 센터(ЦУП)에 두 개의 화면(두 개의 "뷰")을 만드는 것입니다:
- 종합 화면: 시스템 내 모든 객체의 상태를 보여줍니다 (행성 목록).
- 세부 화면: 객체를 클릭하면 해당 객체의 모든 정보가 표시됩니다 (단일 행성 페이지).
2. 1단계: 웹페이지용 컨트롤러 생성
깔끔한 아키텍처를 위해 API 로직과 웹페이지 로직을 하나의 컨트롤러에 혼합하지 않는 것이 좋습니다. Blade 뷰를 표시하기 위한 새로운 컨트롤러를 생성하겠습니다.
터미널에서 실행하세요:
API 컨트롤러와 분리하기 위해Web
하위 폴더에 생성합니다.
생성된 파일 app/Http/Controllers/Web/PlanetPageController.php
을(를) 여세요.
2단계: 모든 행성 목록 페이지
1. 컨트롤러에 메서드 생성:
PlanetPageController
에 데이터베이스에서 모든 행성을 가져와 뷰로 전달하는 index
메서드를 추가하세요.
<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Models\Planet; // 모델을 임포트하는 것을 잊지 마세요
class PlanetPageController extends Controller
{
/**
* 모든 행성 목록 페이지를 표시합니다.
*/
public function index()
{
// 1. DB에서 모든 행성을 가져옵니다
$planets = Planet::all();
// 2. 뷰를 반환하고 데이터를 전달합니다
return view('planets.index', ['planets' => $planets]);
}
}
2. Blade 뷰 생성:
resources/views/planets/index.blade.php
파일을 생성하세요. 지난 장에서 생성한 레이아웃을 사용할 것입니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Planets</title>
<style>
body {
font-family: sans-serif;
background-color: #f4f4f9;
color: #333;
margin: 0;
padding: 2em;
}
.container {
max-width: 960px;
margin: 0 auto;
}
h2 {
color: #1a202c;
}
hr {
border: none;
border-top: 1px solid #e2e8f0;
margin: 1.5em 0;
}
.planet-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5em;
}
.planet-card {
background-color: #fff;
border: 1px solid #e2e8f0;
border-radius: 0.5em;
padding: 1.5em;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
transition: transform 0.2s;
}
.planet-card:hover {
transform: translateY(-5px);
}
.planet-card h3 {
margin-top: 0;
color: #2d3748;
}
.planet-card p {
margin-bottom: 0.5em;
color: #4a5568;
}
.planet-card a {
color: #4299e1;
text-decoration: none;
font-weight: bold;
}
.planet-card a:hover {
text-decoration: underline;
}
.no-planets {
color: #718096;
}
</style>
</head>
<body>
<div class="container">
<h2>알려진 모든 행성 목록</h2>
<hr>
<div class="planet-list">
@forelse($planets as $planet)
<div class="planet-card">
<h3>{{ $planet->name }}</h3>
<p>태양계: {{ $planet->solar_system }}</p>
<p>직경: {{ number_format($planet->size_km, 0, '.', ' ') }} km</p>
<a href="/planets/{{ $planet->id }}">더 알아보기 →</a>
</div>
@empty
<p class="no-planets">데이터베이스에 행성이 없습니다. 시더를 실행해주세요.</p>
@endforelse
</div>
</div>
</body>
</html>
number_format(...)
은 숫자를 보기 좋게 서식 지정하는 일반적인 PHP 함수입니다. Blade에서 직접 사용할 수 있습니다.
3. routes/web.php
에 경로 생성:
use App\Http\Controllers\Web\PlanetPageController;
// ...
Route::get('/planets', [PlanetPageController::class, 'index']);
/planets
주소로 이동하면 행성 목록 페이지를 볼 수 있습니다!
4. 3단계: 단일 행성 페이지
1. 컨트롤러에 메서드 생성:
PlanetPageController
에 show
메서드를 추가하겠습니다. 경로 모델 바인딩 덕분에 Laravel은 ID로 행성을 자동으로 찾아 메서드로 전달합니다.
<?php
// PlanetPageController 클래스 내부
/**
* 특정 행성의 페이지를 표시합니다.
*/
public function show(Planet $planet)
{
// Laravel이 이미 우리를 위해 행성을 찾았습니다.
// 찾을 수 없는 경우 자동으로 404 오류를 반환합니다.
return view('planets.show', ['planet' => $planet]);
}
2. Blade 뷰 생성:
resources/views/planets/show.blade.php
파일을 생성하세요.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $planet->name }}</title>
<style>
body {
font-family: sans-serif;
background-color: #f4f4f9;
color: #333;
margin: 0;
padding: 2em;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
max-width: 600px;
width: 100%;
}
.planet-detail {
background-color: #fff;
border: 1px solid #e2e8f0;
border-radius: 0.5em;
padding: 2em;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.planet-detail h1 {
margin-top: 0;
color: #2d3748;
}
.planet-detail p {
margin-bottom: 1em;
color: #4a5568;
font-size: 1.1em;
}
.back-link {
display: inline-block;
margin-top: 1.5em;
color: #4299e1;
text-decoration: none;
font-weight: bold;
}
.back-link:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<div class="planet-detail">
@if($planet->image_url)
<img src="{{ $planet->image_url }}" alt="{{ $planet->name }}의 이미지" style="max-width: 100%; height: auto; border-radius: 0.5em; margin-bottom: 1em;">
@endif
<h1>{{ $planet->name }}</h1>
@if($planet->description)
<p>{{ $planet->description }}</p>
@endif
<p><strong>태양계:</strong> {{ $planet->solar_system }}</p>
<p><strong>직경:</strong> {{ number_format($planet->size_km, 0, '.', ' ') }} km</p>
<a href="/planets" class="back-link">← 행성 목록으로 돌아가기</a>
</div>
</div>
</body>
</html>
3. routes/web.php
에 경로 생성:
// 이 경로를 /planets 경로 뒤에 추가하세요
Route::get('/planets/{planet}', [PlanetPageController::class, 'show']);
{planet}
매개변수 이름은 경로 모델 바인딩이 올바르게 작동하려면 컨트롤러 메서드의 변수 이름(show(Planet $planet)
)과 일치해야 합니다.
이제 목록 페이지에서 "더 알아보기" 링크를 클릭하면 특정 행성의 상세 페이지로 이동합니다.
확인 퀴즈
🚀 챕터 요약:
Laravel MVC 아키텍처를 사용하여 API의 "진열장"을 성공적으로 만들었습니다. 이제 다음을 갖게 되었습니다:
- 웹 페이지 로직을 위한 별도의 컨트롤러.
- DB에서 데이터를 가져오는 모든 행성 목록이 포함된 동적 페이지.
- Route Model Binding을 사용하여 각 행성에 대한 상세 페이지.
- 이러한 페이지에 액세스하기 위한
routes/web.php
의 두 웹 경로.
원시 데이터를 사용자에게 이해하기 쉽고 유용한 정보로 변환했습니다. 다음 챕터에서는 페이지를 다시 로드하지 않고 API와 상호 작용할 수 있도록 Blade 뷰에 JavaScript를 내장하여 상호 작용을 추가할 것입니다.