메인 콘텐츠로 건너뛰기

응답이란

컨트롤러나 라우트는 사용자의 브라우저에 어떤 형태로든 응답을 반환해야 합니다. Laravel은 문자열·배열·뷰·리다이렉트·JSON 등 다양한 형식의 응답을 단순하게 반환할 수 있는 구조를 제공합니다.

기본 응답

문자열 반환

가장 단순한 응답은 문자열 반환입니다. Laravel은 자동으로 적절한 HTTP 응답으로 변환합니다.
Route::get('/', function () {
    return 'Hello World';
});

배열 반환

배열을 반환하면 Laravel은 그것을 JSON 형식으로 자동 변환하여 응답합니다.
Route::get('/users', function () {
    return [
        ['id' => 1, 'name' => '김철수'],
        ['id' => 2, 'name' => '박영희'],
    ];
});
Eloquent 모델이나 컬렉션을 그대로 return하면 JSON 형식으로 자동 변환됩니다. API를 손쉽게 만들 수 있어 자주 사용되는 패턴입니다.

Eloquent 모델 반환

use App\Models\User;

Route::get('/user/{user}', function (User $user) {
    return $user;
});

Response 객체

response() 헬퍼를 사용하면 HTTP 상태 코드나 헤더를 지정한 상세한 응답을 반환할 수 있습니다.
Route::get('/home', function () {
    return response('Hello World', 200)
        ->header('Content-Type', 'text/plain');
});
response()의 첫 번째 인수는 응답의 본문, 두 번째 인수는 HTTP 상태 코드입니다.

자주 사용되는 HTTP 상태 코드

코드의미
200OK(성공)
201Created(리소스 생성 성공)
204No Content(콘텐츠 없음)
301Moved Permanently(영구적 리다이렉트)
302Found(일시적 리다이렉트)
404Not Found(찾지 못함)
422Unprocessable Entity(유효성 검증 오류)
500Internal Server Error(서버 오류)

뷰 응답

컨트롤러에서 Blade 템플릿을 표시하려면 view()를 사용합니다. 이것이 웹 애플리케이션에서 가장 일반적인 응답입니다.
<?php

namespace App\Http\Controllers;

use Illuminate\View\View;

class HomeController extends Controller
{
    public function index(): View
    {
        $users = [
            ['name' => '김철수', 'email' => '[email protected]'],
            ['name' => '박영희', 'email' => '[email protected]'],
        ];

        return view('users.index', ['users' => $users]);
    }
}
view()의 첫 번째 인수는 뷰 이름, 두 번째 인수는 뷰로 전달할 데이터 배열입니다.
반환 값 타입 힌트에 Illuminate\View\View를 지정하면 코드의 의도가 명확해집니다.

response()->view()로 상세 제어

상태 코드나 헤더도 함께 지정하고 싶은 경우에는 response()->view()를 사용합니다.
return response()
    ->view('errors.404', ['message' => '페이지를 찾을 수 없습니다'], 404);

리다이렉트

기본 리다이렉트

redirect() 헬퍼는 리다이렉트 응답을 반환합니다. 폼 전송 후 다른 페이지로 유도할 때 자주 사용합니다.
use Illuminate\Http\RedirectResponse;

Route::get('/old-page', function (): RedirectResponse {
    return redirect('/new-page');
});
컨트롤러에서의 사용 예시입니다.
<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function store(Request $request): RedirectResponse
    {
        // 게시물을 저장하는 처리...

        return redirect('/posts');
    }
}

이름 지정 라우트로의 리다이렉트

route() 함수를 사용하면 URL을 직접 작성하지 않고 라우트 이름으로 리다이렉트 대상을 지정할 수 있습니다. URL이 바뀌어도 수정이 불필요해지므로 이름 지정 라우트를 활용하는 것이 베스트 프랙티스입니다.
// 라우트에 이름 부여
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
// 이름 지정 라우트로 리다이렉트
return redirect()->route('posts.index');

// 라우트 파라미터를 전달하는 경우
return redirect()->route('posts.show', ['post' => $post->id]);

직전 페이지로 돌아가기

back()으로 사용자가 직전에 있던 페이지로 돌아갈 수 있습니다. 유효성 검증 실패 시의 리다이렉트에 자주 사용됩니다.
return back();

// 입력 데이터를 보존하고 돌아간다
return back()->withInput();

플래시 메시지가 포함된 리다이렉트

with()로 세션에 메시지를 붙여 리다이렉트할 수 있습니다. 폼 전송 성공 후의 메시지 표시에 편리합니다.
return redirect('/posts')->with('success', '게시물을 생성했습니다.');
Blade 템플릿에서 메시지를 표시합니다.
@if (session('success'))
    <div class="alert alert-success">
        {{ session('success') }}
    </div>
@endif

JSON 응답

API를 만드는 경우에는 response()->json()을 사용해 JSON 응답을 반환합니다. Content-Type: application/json 헤더가 자동으로 설정됩니다.
use Illuminate\Http\JsonResponse;

Route::get('/api/users', function (): JsonResponse {
    $users = [
        ['id' => 1, 'name' => '김철수'],
        ['id' => 2, 'name' => '박영희'],
    ];

    return response()->json($users);
});
상태 코드도 지정할 수 있습니다.
return response()->json(['message' => '생성했습니다'], 201);
컨트롤러에서의 사용 예시입니다.
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function index(): JsonResponse
    {
        $users = User::all();

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

    public function store(Request $request): JsonResponse
    {
        // 검증 완료된 데이터로 생성(폼 리퀘스트 또는 $request->validate() 이후)
        $user = User::create($request->validated());

        return response()->json($user, 201);
    }
}
단순히 배열이나 Eloquent 모델을 return하는 것만으로도 JSON 응답이 되지만, response()->json()을 사용하면 상태 코드나 헤더를 세밀하게 제어할 수 있습니다.

응답 헤더

header() 메서드로 응답에 HTTP 헤더를 추가할 수 있습니다.
return response('Hello World')
    ->header('Content-Type', 'text/plain')
    ->header('X-Custom-Header', 'MyValue');
여러 헤더를 함께 설정하는 경우에는 withHeaders()를 사용합니다.
return response('Hello World')
    ->withHeaders([
        'Content-Type' => 'text/plain',
        'X-Custom-Header' => 'MyValue',
        'Cache-Control' => 'no-cache',
    ]);

실전 예시: 컨트롤러에서의 구분 사용

용도에 맞게 응답을 구분 사용하는 예시를 정리한 것입니다.
1

라우트 정의

use App\Http\Controllers\PostController;

Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create');
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('posts.destroy');
2

컨트롤러 구현

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class PostController extends Controller
{
    // 목록 표시: 뷰를 반환
    public function index(): View
    {
        $posts = Post::latest()->get();

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

    // 생성 폼: 뷰를 반환
    public function create(): View
    {
        return view('posts.create');
    }

    // 저장: 리다이렉트를 반환
    public function store(Request $request): RedirectResponse
    {
        // 검증 완료된 데이터로 생성(폼 리퀘스트를 사용하고 있는 경우)
        $post = Post::create($request->validated());

        return redirect()
            ->route('posts.show', ['post' => $post->id])
            ->with('success', '게시물을 생성했습니다.');
    }

    // 상세 표시: 뷰를 반환
    public function show(Post $post): View
    {
        return view('posts.show', ['post' => $post]);
    }

    // 삭제: 리다이렉트를 반환
    public function destroy(Post $post): RedirectResponse
    {
        $post->delete();

        return redirect()
            ->route('posts.index')
            ->with('success', '게시물을 삭제했습니다.');
    }
}
웹 앱에서는 ViewRedirectResponse의 구분 사용이 기본입니다. 표시 계열의 액션은 View를, 변경 계열(생성·갱신·삭제)의 액션은 처리 후 RedirectResponse를 반환하는 것이 일반적인 패턴입니다.

다음 단계

유효성 검증

응답을 반환하기 전에 입력 데이터를 유효성 검증으로 검사하는 방법을 확인합니다.
마지막 수정일 2026년 7월 13일