Table Of Contents
Problem
You need API routes that work with or without certain parameters, like /api/users
and /api/users/{category}
using the same controller method.
Solution
Use the ?
operator to make route parameters optional:
// routes/api.php
Route::get('/users/{category?}', [UserController::class, 'index']);
// Controller
public function index(Request $request, $category = null)
{
$query = User::query();
if ($category) {
$query->where('category', $category);
}
return $query->get();
}
Multiple optional parameters:
// Route with multiple optional parameters
Route::get('/posts/{category?}/{tag?}', [PostController::class, 'index']);
public function index(Request $request, $category = null, $tag = null)
{
$query = Post::query();
if ($category) {
$query->where('category', $category);
}
if ($tag) {
$query->whereHas('tags', fn($q) => $q->where('name', $tag));
}
return $query->paginate(15);
}
Alternative approach using query parameters:
// Single route handling optional filtering
Route::get('/products', [ProductController::class, 'index']);
public function index(Request $request)
{
$query = Product::query();
// Handle optional filters via query params
if ($request->has('category')) {
$query->where('category_id', $request->category);
}
if ($request->has('price_min')) {
$query->where('price', '>=', $request->price_min);
}
if ($request->has('search')) {
$query->where('name', 'like', '%' . $request->search . '%');
}
return $query->get();
}
Why It Works
Adding ?
after a route parameter makes it optional. Laravel will match both /users
and /users/electronics
to the same route. The controller receives null
for missing parameters, allowing you to handle different scenarios in the same method.
Advanced pattern with constraints:
// Optional parameter with validation
Route::get('/users/{id?}', [UserController::class, 'show'])
->where('id', '[0-9]+');
// Multiple routes for better control
Route::get('/api/search', [SearchController::class, 'all']);
Route::get('/api/search/{type}', [SearchController::class, 'byType'])
->where('type', 'users|products|posts');
public function byType(Request $request, string $type)
{
return match($type) {
'users' => User::search($request->q)->get(),
'products' => Product::search($request->q)->get(),
'posts' => Post::search($request->q)->get(),
};
}
Related: Laravel Collections: Beyond Basic Array Operations | Laravel Events and Listeners: Building Decoupled Applications | Laravel API Development: Best Practices and Security | Laravel Route Model Binding: Beyond the Basics | REST API Design Best Practices Tutorial 2025
Add Comment
No comments yet. Be the first to comment!