Skip to content

제5.5장: 웹 페이지 라우팅

학습 시간: 40분


1. routes/web.php vs routes/api.php: 두 가지 다른 제어판

근본적인 차이를 다시 한번 확실히 해두는 것이 중요합니다:

특성 routes/web.php (웹 제어판) routes/api.php (API 제어판)
주요 목적 HTML 페이지 표시, 폼 처리 다른 애플리케이션을 위한 JSON 형식 데이터 제공
상태 (State) Stateful (상태 유지) — 세션 및 쿠키 사용 Stateless (무상태) — 각 요청 독립적
기본 미들웨어 web (세션, CSRF 보호, 쿠키 암호화 포함) api ("스로틀링" — 요청 빈도 제한 포함)
URL 접두사 없음 (사이트의 루트) /api/ (RouteServiceProvider에서 설정)
인증 일반적으로 세션 사용 (로그인/비밀번호) 일반적으로 토큰 사용 (Sanctum, Passport)

우리는 실제 사용자를 위한 인터페이스를 구축하기 위해 routes/web.php를 사용합니다.


2. 웹용 리소스 라우트

Route::apiResource와 유사하게, 웹을 위한 Route::resource가 존재합니다. 이것은 생성 및 편집 폼을 표시하는 페이지를 포함하여 전체 CRUD 사이클을 위한 라우트를 생성합니다.

웹 인터페이스를 통해 행성을 관리하기 위한 전체 라우트 세트를 만들어 봅시다.

1단계: routes/web.php에 라우트 생성

기존의 /planets 라우트를 주석 처리하거나 삭제하고 한 줄로 대체합니다:

use App\Http\Controllers\Web\PlanetPageController;

// Route::get('/planets', [PlanetPageController::class, 'index']);
// Route::get('/planets/{planet}', [PlanetPageController::class, 'show']);

Route::resource('planets', PlanetPageController::class);

2단계: 생성된 내용 확인 터미널에서 php artisan route:list --except-vendor 명령을 실행합니다:

+--------+-----------+------------------------+------------------+-------------------------------------------------+------------+
| Method | URI       | Name                   | Action           | Middleware                                      |
+--------+-----------+------------------------+------------------+-------------------------------------------------+------------+
| GET|HEAD | planets                | planets.index          | ...\PlanetPageController@index                    | web        |
| POST   | planets                | planets.store          | ...\PlanetPageController@store                    | web        |
| GET|HEAD | planets/create         | planets.create         | ...\PlanetPageController@create                   | web        |
| GET|HEAD | planets/{planet}       | planets.show           | ...\PlanetPageController@show                     | web        |
| PUT|PATCH | planets/{planet}       | planets.update         | ...\PlanetPageController@update                   | web        |
| DELETE | planets/{planet}       | planets.destroy        | ...\PlanetPageController@destroy                  | web        |
| GET|HEAD | planets/{planet}/edit  | planets.edit           | ...\PlanetPageController@edit                     | web        |
+--------+-----------+------------------------+------------------+-------------------------------------------------+------------+

Route::resource는 다음을 포함하여 7개의 라우트를 생성했습니다:

  • planets.create (GET /planets/create): 생성 폼이 있는 페이지.
  • planets.store (POST /planets): 이 폼 처리.
  • planets.edit (GET /planets/{planet}/edit): 편집 폼이 있는 페이지.
  • planets.update (PUT/PATCH /planets/{planet}): 편집 폼 처리.
  • planets.destroy (DELETE /planets/{planet}): 리소스 삭제.

3. 명명된 라우트: 편리한 "우주 좌표"

Name 열에 주목하세요. Laravel은 각 라우트에 고유한 이름(예: planets.index)을 자동으로 할당했습니다. 하드코딩된 URL 대신 이름을 사용하는 것이 가장 좋은 방법입니다.

왜 그럴까요? URL을 /planets에서 /worlds로 변경하기로 결정하더라도, 템플릿의 모든 링크를 찾아 변경할 필요가 없습니다. 라우트 파일의 한 곳에서만 변경하면 되며, 이름은 그대로 유지됩니다.

Blade에서 사용 예시:

이전에는 다음과 같이 작성했습니다:

<a href="/planets/{{ $planet->id }}">더 알아보기 &rarr;</a>

이제 route() 헬퍼를 사용하여 다음과 같이 작성할 것입니다:

<a href="{{ route('planets.show', ['planet' => $planet->id]) }}">더 알아보기 &rarr;</a>

  • route('planets.show', ...)planets.show라는 이름의 라우트에 대한 URL을 생성합니다.
  • ['planet' => $planet->id] — 필요한 매개변수를 URL에 전달합니다. Laravel은 {planet}에 ID를 자동으로 채워넣습니다. 모델 전체를 전달할 수도 있습니다: ['planet' => $planet].

4. 컨트롤러에 누락된 메서드 구현

Route::resource는 라우트를 생성했지만, PlanetPageController에 해당하는 메서드는 우리가 직접 생성해야 합니다.

app/Http/Controllers/Web/PlanetPageController.php를 열고 추가해 봅시다.

<?php
use Illuminate\Http\Request; // <-- 추가

class PlanetPageController extends Controller
{
    // index()와 show()는 이미 있습니다

    /**
     * 새 행성을 생성하기 위한 폼을 표시합니다.
     */
    public function create()
    {
        return view('planets.create'); // 단순히 폼이 있는 뷰를 반환합니다
    }

    /**
     * 새 행성을 데이터베이스에 저장합니다.
     */
    public function store(Request $request)
    {
        // 폼 데이터 유효성 검사
        $validated = $request->validate([
            'name' => 'required|string|max:255|unique:planets',
            'solar_system' => 'required|string|max:100',
            // ... 기타 규칙
        ]);

        Planet::create($validated);

        // 사용자에게 성공 메시지와 함께 목록 페이지로 리디렉션합니다
        return redirect()->route('planets.index')->with('success', '행성이 성공적으로 생성되었습니다!');
    }

    /**
     * 행성 편집 폼을 표시합니다.
     */
    public function edit(Planet $planet)
    {
        return view('planets.edit', ['planet' => $planet]);
    }

    /**
     * 데이터베이스에서 행성 데이터를 업데이트합니다.
     */
    public function update(Request $request, Planet $planet)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255|unique:planets,name,' . $planet->id,
            'solar_system' => 'required|string|max:100',
        ]);

        $planet->update($validated);

        return redirect()->route('planets.show', $planet)->with('success', '행성 데이터가 업데이트되었습니다!');
    }

    /**
     * 행성을 삭제합니다.
     */
    public function destroy(Planet $planet)
    {
        $planet->delete();

        return redirect()->route('planets.index')->with('success', '행성이 폐기되었습니다.');
    }
}
  • redirect()->route(...) — 사용자를 다른 명명된 라우트로 리디렉션합니다.
  • ->with('success', '...') — 세션에 "플래시 메시지"를 추가하며, 이 메시지는 다음 페이지에서 정확히 한 번만 사용할 수 있습니다. 이 메시지를 Blade 템플릿에 표시할 수 있습니다.

5. 라우트 그룹화

공통 특성을 가진 많은 라우트(예: 모두 관리자 패널용이며 /admin 접두사와 특별한 미들웨어를 가져야 함)가 있다면, 이들을 그룹화할 수 있습니다.

<?php
Route::middleware(['auth', 'admin'])->prefix('admin')->name('admin.')->group(function () {
    // 이 그룹 내의 모든 라우트는 다음을 가집니다:
    // 1. 'auth' 및 'admin' 미들웨어
    // 2. URL 접두사 '/admin' (예: /admin/planets)
    // 3. 이름 접두사 'admin.' (예: admin.planets.index)

    Route::resource('planets', PlanetPageController::class);
    // Route::get('/dashboard', ...)->name('dashboard'); // -> admin.dashboard
});

복습 퀴즈

1. `routes/web.php` 파일에서 웹 인터페이스를 위한 완전한 CRUD 경로 집합을 생성하는 명령어는 무엇입니까?

2. 명명된 경로를 사용하는 것의 주요 장점은 무엇입니까?

3. `Route::resource('articles', ...)`에서 `create()` 메서드를 위해 어떤 경로가 생성됩니까?

4. `redirect()->route('home')->with('status', 'OK')` 코드는 무엇을 합니까?

5. `Route::prefix('dashboard')`는 무엇을 위해 사용됩니까?

🚀 챕터 요약:

Laravel에서 웹 경로를 구성하는 구조화되고 전문적인 접근 방식을 마스터했습니다. 이제 다음을 할 수 있습니다:

  • webapi 경로와 그 목적을 구별합니다.
  • Route::resource를 사용하여 표준 CRUD 경로를 빠르게 생성합니다.
  • 유연하고 유지보수 가능한 코드를 생성하기 위해 명명된 경로를 사용합니다.
  • 유효성 검사 및 리디렉션을 통해 컨트롤러에서 완전한 CRUD 작업을 생성합니다.
  • 공통 규칙을 적용하기 위해 경로를 그룹화합니다.

이제 당신의 "함선"의 내비게이션 시스템은 오류 허용적이며 확장을 위한 준비가 되었습니다. 이 섹션의 마지막 챕터에서는 지금까지 얻은 모든 지식을 통합하여 Fetch를 통해 얻은 행성 데이터를 우리의 Blade 페이지에 표시할 것입니다.