The final Controller that we didn't finalize is AuthController
. In fact, it's pretty small and doesn't need many changes—only a few small ones.
app/Http/Controllers/Api/AuthController.php
use App\Models\User; class AuthController extends ApiController{ public function login(LoginUserRequest $request) { $request->validated($request->all()); $credentials = $request->only('email', 'password'); if (! Auth::attempt($credentials)) { throw ValidationException::withMessages([ 'email' => ['The provided credentials are incorrect.'], 'password' => ['The provided credentials are incorrect.'], ]); } $user = User::firstWhere('email', $request->email); $token = $user?->createToken('authToken', Abilities::getAbilities($user), now()->addHours(8))->plainTextToken; $user = auth()->user(); $token = $user->createToken('authToken', Abilities::getAbilities($user), now()->addHours(8))->plainTextToken; return $this->responseSuccess( 'Authenticated', [ // 'user' => $user, 'token' => $token, ], ); return $this->responseSuccess('Authenticated', ['token' => $token]); } public function logout(Request $request) { $request->user()->currentAccessToken()->delete(); return $this->responseSuccess('Logged out'); }}
What I've changed here:
- Removed the line
$request->validated($request->all());
- what did that even mean?.. - Removed the DB call to
User::firstWhere()
- by this time, the User would be logged in already, so we can callauth()->user()
- Simplify the
responseSucces()
to fit in one line for readability
TESTS (Yup, Again!)
And yes, surprise, surprise - the login/logout mechanism also didn't have any tests either. Let's fix this!
php artisan make:test AuthTest
tests/Feature/AuthTest.php
namespace Tests\Feature; use App\Models\User;use App\Permissions\V1\Abilities;use Illuminate\Foundation\Testing\RefreshDatabase;use Tests\TestCase; class AuthTest extends TestCase{ use RefreshDatabase; public function test_user_can_login_with_correct_credentials() { $user = User::factory()->create([ 'password' => bcrypt('password123'), ]); $response = $this ->postJson('/api/login', [ 'password' => 'password123', ]); $response->assertStatus(200) ->assertJsonStructure([ 'message', 'data' => [ 'token' ] ]); } public function test_user_cannot_login_with_incorrect_credentials() { $user = User::factory()->create([ 'password' => bcrypt('password123'), ]); $response = $this ->postJson('/api/login', [ 'password' => 'wrongpassword', ]); $response->assertStatus(422) ->assertJsonValidationErrors(['email', 'password']); } public function test_login_validation_requires_email_and_password() { $response = $this ->postJson('/api/login', [ 'email' => '', 'password' => '', ]); $response->assertStatus(422) ->assertJsonValidationErrors(['email', 'password']); } public function test_user_can_logout() { $user = User::factory()->create(); $token = $user->createToken('authToken', Abilities::getAbilities($user), now()->addHours(8))->plainTextToken; $response = $this ->withHeader('Authorization', 'Bearer ' . $token) ->postJson('/api/logout'); $response->assertStatus(200) ->assertJson([ 'message' => 'Logged out' ]); }}
Our final test suite consists of 22 tests now. All green!
Here's the GitHub commit for this change with AuthController.
Running Pint One More Time
I didn't set up any code styling automation for this project, so I had to rerun it:
Here's the final GitHub commit for this Pint change and this whole course.
Course Conclusion and Summary of Code Review
So, we're done refactoring all Controllers/Routes/Traits/Exceptions structure in 15 lessons.
What problems we were trying to solve:
- Over-complicated structure of Base API Controller + Trait
- Too long Controllers with unnecessary try-catch blocks
- Laravel framework core features were not utilized enough (Route Model Binding, API Resource returns, Exception handling, etc)
- Duplicated code with no specific reasons
- Lack of automated tests
Overall, I'm pretty happy with the result. What do you think?
If I had to describe the original codebase in one word, it would be unfinished.
- Inconsistency: some methods had try-catch or authorization check, others didn't
- Seems like some Controllers were started but not finished/utilized/tested properly
However, this is my personal opinion. I may be wrong in some of my refactoring or misinterpret some of the code author's original intentions. We can discuss it all in the comments section below!
No comments yet…