Laravel allows us to structure code in many ways, right? But with APIs, it's important to avoid some bad practices, cause it may break API clients and confuse other developers.
1. Returning Status Code 200 When Errors Occur
One of the most common mistakes is returning a 200 OK status code when something has actually gone wrong.
Bad Practice:
public function store(Request $request){ try { if (!$request->has('name')) { return response()->json([ 'success' => false, 'error_message' => 'Name is required' ], 200); // WRONG! Using 200 for an error } // ... } catch (\Exception $e) { return response()->json([ 'success' => false, 'error_message' => 'Something went wrong' ], 200); // WRONG again! }}
Better Approach:
public function store(Request $request){ try { $validated = $request->validate([ 'name' => 'required|string|max:255', ]); $user = User::create($validated); return response()->json([ 'data' => $user ], 201); // Good 201 status code for success } catch (ValidationException $e) { return response()->json([ 'message' => 'Validation failed', 'errors' => $e->errors() ], 422); // Not 200 anymore! } catch (\Exception $e) { return response()->json([ 'error_message' => 'Server error' ], 500); // Also not 200! }}
There's even a classical meme about it, found on Reddit:
And it's not just about error/success status code. As you can see in the example, we're returning 4xx code for validation, and 5xx code for general Exception on the server.
So, use appropriate HTTP status codes - 201 for creation, 422 for validation errors, 404 for not found, etc. This helps API clients properly understand the response.
2. Not Following RESTful Conventions
For REST APIs, developers typically use Resource Controllers in Laravel. Some different non-standard naming and HTTP methods can make your API confusing and hard to maintain.
Bad Practice:
// Routes fileRoute::get('/getUserById/{id}', [UserController::class, 'getOneUser']);Route::post('/createUser', [UserController::class, 'makeUser']);Route::post('/deleteUser/{id}', [UserController::class, 'removeUser']);Route::get('/getAllUsers', [UserController::class, 'fetchAllUsers']);
Better Approach:
Use Laravel's resource Controllers to enforce RESTful conventions:
// Routes fileRoute::apiResource('users', UserController::class); // UserController.phpclass UserController extends Controller{ // GET /users public function index() { // ... } // POST /users public function store(Request $request) { // ... } // GET /users/{id} public function show(User $user) { // ... } // PUT/PATCH /users/{id} public function update(Request $request, User $user) { // ... } // DELETE /users/{id} public function destroy(User $user) { // ... }}
This automatically maps HTTP verbs to CRUD actions and follows conventional REST naming patterns.
3. Making Breaking API Changes Without Versioning
If you have real API clients already using your API, changing...