개요
라라벨은 기본적으로 서버사이드 렌더링을 통해 페이지를 응답하기 위한 Web Route 와 비동기를 통한 Response Body 를 응답하기 위한 API Route 를 제공한다. Route 의 식별은 URI 의 prefix 를 통해 /api 로 시작하는 경우 API Route 에 정의된 경로를 맵핑하도록 되어있다.
이 장에서는 해당 라우팅 정책을 URI 의 prefix 가 아닌 도메인(정확히는 서브 도메인)을 통해 식별되도록 변경하는 방법을 소개하고자 한다.
※ 해당 문서는 PHP에 대한 기본지식 및 Laravel Framework 전반의 구조와 라이프사이클을 이해하고 있다는 전제로 작성되었습니다.
- Laravel v8.72.0 (PHP v7.4.25)
주요 파일 경로
# 라우팅의 맵핑이 정의된 파일
{ProjectRoot}/routes
ㄴ api.php
ㄴ web.php
# web route 와 api route 식별정책을 정의한 Service Provider
{ProjectRoot}/app/Providers
ㄴ RouteServiceProvider.php
수정 및 실행
- API Route 에 맵핑을 정의
- RouteServiceProvider 의 prefix 를 통해 API Route를 식별하도록 정의된 구문을 도메인 기준으로 식별하도록 변경.
# routes/web.php
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
# http(s)://your-domain/box1
Route::get('/box1', function () {
return 'this is web route box1.';
});
# routes/api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
# AS-IS : http(s)://your-domain/api/box1
# TO-BE : http(s)://api.your-domain/box1
Route::get('/box1', function () {
return 'this is api route box1.';
});
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.
*
* @var string
*/
public const HOME = '/home';
/**
* The controller namespace for the application.
*
* When present, controller route declarations will automatically be prefixed with this namespace.
*
* @var string|null
*/
// protected $namespace = 'App\\Http\\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
# prefix를 통한 api route 식별
/*Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));*/
# 도메인 기반의 api route 식별 방식으로 변경
Route::domain('api.tailerbox.com')
// 도메인은 .env 의 환경변수 등록을 통해 아래와 같은 형태로 사용하길 권장함.
// Route::domain(env('API_DOMAIN'))
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
});
}
/**
* Configure the rate limiters for the application.
*
* @return void
*/
protected function configureRateLimiting()
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
});
}
}
RouteServiceProvider 의 수정 전과 후는 아래와 같이 다르게 접근되어야 한다.
- AS-IS : http://tailerbox.com/api/box1
- TO-BE : http://api.tailerbox.com/box1
여기서 잠깐
RouteServiceProvider 의 API와 Web Route는 $this->routes() 라는 부모 메소드를 통해 바인딩 되며 콜백함수가 단일 인자로 전달되어 선언된 것을 확인할 수 있다.
따라서, /routes/api.php 파일에서 box1 이라는 맵핑이 존재하지 않는 경우 /routes/web.php 에서 해당 맵핑을 찾도록 동작한다는 것을 알 수 있다.
prefix 를 통해 /api 로 들어오는 이하의 URI를 모두 API로 간주하는 경우 문제될게 없겠지만 domain 기반으로 변경한 이후에는 동일한 이름의 라우트 맵핑이 얼마든지 존재할 수 있기 때문에 이에 대한 조치가 필요하다.
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Http\Request;
# 동일한 이름의 Request 객체가 이미 있으므로 Class 의 Alias 를 지정
use Illuminate\Support\Facades\Request as FacadeRequest;
use Illuminate\Support\Facades\Route;
//use Illuminate\Support\Facades\URL;
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.
*
* @var string
*/
public const HOME = '/home';
/**
* The controller namespace for the application.
*
* When present, controller route declarations will automatically be prefixed with this namespace.
*
* @var string|null
*/
// protected $namespace = 'App\\Http\\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
# prefix를 통한 api route 식별
/*Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));*/
if (FacadeRequest::server('HTTP_HOST') === env('API_DOMAIN')) {
# 도메인 기반의 api route 식별 방식으로 변경
Route::domain(env('API_DOMAIN'))
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
} elseif (FacadeRequest::server('HTTP_HOST') === env('WEB_DOMAIN')) {
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
});
}
/**
* Configure the rate limiters for the application.
*
* @return void
*/
protected function configureRateLimiting()
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
});
}
}
'Framework > Laravel' 카테고리의 다른 글
[Laravel] i18n 국제화 적용하기 (0) | 2021.11.19 |
---|---|
[Laravel] Error 핸들링 (CustomException) (0) | 2021.11.19 |
[Laravel] 설치하기 (0) | 2021.11.18 |