Skip to content

제5.2장: API를 위한 간단한 뷰 생성

학습 시간: 45분


1. 목표: 데이터 시각화

제2장에서 우리 API는 JSON 형식으로 데이터를 제공할 수 있습니다. 이는 기계에는 훌륭하지만, 사람들은 잘 꾸며진 웹페이지에서 정보를 보는 것을 선호합니다. 우리의 목표는 다음과 같은 두 가지 페이지를 만드는 것입니다:

  1. 모든 행성 목록 (/planets)
  2. 단일 행성 페이지 (/planets/{id})

이를 위해 우리는 "경로 → 컨트롤러 → 뷰" 조합을 사용할 것입니다.

💡 우주 비유:

API의 JSON은 원시 텔레메트리 데이터, 즉 단순히 숫자의 흐름이라고 상상해 보세요. 오늘 우리의 임무는 우주 관제 센터(ЦУП)에 두 개의 화면(두 개의 "뷰")을 만드는 것입니다:

  • 종합 화면: 시스템 내 모든 객체의 상태를 보여줍니다 (행성 목록).
  • 세부 화면: 객체를 클릭하면 해당 객체의 모든 정보가 표시됩니다 (단일 행성 페이지).

2. 1단계: 웹페이지용 컨트롤러 생성

깔끔한 아키텍처를 위해 API 로직과 웹페이지 로직을 하나의 컨트롤러에 혼합하지 않는 것이 좋습니다. Blade 뷰를 표시하기 위한 새로운 컨트롤러를 생성하겠습니다.

터미널에서 실행하세요:

php artisan make:controller Web/PlanetPageController
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 }}">더 알아보기 &rarr;</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. 컨트롤러에 메서드 생성:

PlanetPageControllershow 메서드를 추가하겠습니다. 경로 모델 바인딩 덕분에 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">&larr; 행성 목록으로 돌아가기</a>
        </div>
    </div>
</body>
</html>

3. routes/web.php에 경로 생성:

// 이 경로를 /planets 경로 뒤에 추가하세요
Route::get('/planets/{planet}', [PlanetPageController::class, 'show']);
- {planet} 매개변수 이름은 경로 모델 바인딩이 올바르게 작동하려면 컨트롤러 메서드의 변수 이름(show(Planet $planet))과 일치해야 합니다.

이제 목록 페이지에서 "더 알아보기" 링크를 클릭하면 특정 행성의 상세 페이지로 이동합니다.


확인 퀴즈

1. API 및 웹 페이지 로직을 분리하는 가장 좋은 방법은 무엇입니까?

2. return view('planets.index', ['planets' => $planets]);는 무엇을 합니까?

3. `show(Planet $planet)` 컨텍스트에서 Route Model Binding은 무엇입니까?

4. Blade에서 `created_at` 필드의 날짜를 어떻게 포맷할 수 있습니까?

5. 경로에 `/posts/{post}`가 지정된 경우, Route Model Binding이 작동하려면 컨트롤러의 메서드 시그니처가 어떻게 되어야 합니까?


🚀 챕터 요약:

Laravel MVC 아키텍처를 사용하여 API의 "진열장"을 성공적으로 만들었습니다. 이제 다음을 갖게 되었습니다:

  • 웹 페이지 로직을 위한 별도의 컨트롤러.
  • DB에서 데이터를 가져오는 모든 행성 목록이 포함된 동적 페이지.
  • Route Model Binding을 사용하여 각 행성에 대한 상세 페이지.
  • 이러한 페이지에 액세스하기 위한 routes/web.php의 두 웹 경로.

원시 데이터를 사용자에게 이해하기 쉽고 유용한 정보로 변환했습니다. 다음 챕터에서는 페이지를 다시 로드하지 않고 API와 상호 작용할 수 있도록 Blade 뷰에 JavaScript를 내장하여 상호 작용을 추가할 것입니다.