Skip to content

enh : Improve CRUD implementation for transactions #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions app/Http/Controllers/API/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@
namespace App\Http\Controllers\API;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Validator;
use OpenApi\Attributes as OA;

#[OA\OpenApi(
security: [
['bearerAuth' => []],
]
)]
#[OA\Info(title: 'Trakli API', version: '1.0.0')]
#[OA\Server(url: 'http://localhost:8000/api/v1', description: 'Development server')]
#[OA\Server(url: 'https://api.trakli.io/v1', description: 'Production server')]
Expand All @@ -18,8 +26,68 @@
// new OA\ServerVariable(name: "host", default: "api.trakli.io", enum: ["api.trakli.io", "api.staging.example.com"])
// ]
)]
#[OA\Components(
securitySchemes: [
new OA\SecurityScheme(
securityScheme: 'bearerAuth',
type: 'http',
scheme: 'bearer',
description: 'Bearer token authentication'
),
]
)]
class ApiController extends BaseController
{
/**
* Check if the authenticated user can access the given resource.
*
* @param mixed $resource
* @param string|null $ownerKey
* @return void
*
* @throws \Illuminate\Http\Exceptions\HttpResponseException
*/
public function userCanAccessResource($resource, $ownerKey = 'user_id')
{
if (is_null($resource)) {
abort(Response::HTTP_NOT_FOUND, 'Resource not found.');
}

if (auth()->id() !== $resource->{$ownerKey}) {
abort(Response::HTTP_FORBIDDEN, 'You are not authorized to access this resource.');
}
}

/**
* Validate the request data.
*/
protected function validateRequest(Request $request, array $rules): array
{
$validator = Validator::make($request->all(), $rules);

if ($validator->fails()) {
$errors = $validator->errors();

if ($errors->hasAny(array_keys($rules))) {
return [
'isValidated' => false,
'message' => 'Server failed to validate request.',
'code' => 422,
'errors' => $errors->toArray(),
];
}

return [
'isValidated' => false,
'message' => 'Server unable to process request.',
'code' => 400,
'errors' => $errors->toArray(),
];
}

return ['isValidated' => true, 'data' => $validator->validated()];
}

Comment on lines +64 to +90
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use Form Requests for this

Copy link
Contributor Author

@nfebe nfebe Jan 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but we would have to write FormRequests for each endpoint! I did not want to do that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. It makes the code cleaner in my own opinion

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true. It usually does make things cleaner when you have large and complex requests. There is no need to have 4 different FormRequests (4 + files) for the CRUD operations in this file and then we would have to repeat this across all the models, in reality only a few of the requests (e.g store) are big a enough to need the FormRequests which I do use in other code bases but in this case I think this small function takes the bull by the horn we can use to validate all the simple requests based on the rules passed without adding any new files to the project.

/**
* Return a success response.
*
Expand Down
3 changes: 3 additions & 0 deletions app/Http/Controllers/API/v1/Auth/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
use Illuminate\Support\Facades\Validator;
use OpenApi\Attributes as OA;

#[OA\Tag(name: 'Authentication', description: 'Endpoints for user authentication')]
class AuthController extends ApiController
{
#[OA\Post(
path: '/register',
tags: ['Authentication'],
security: [],
summary: 'Register a new user',
requestBody: new OA\RequestBody(
required: true,
Expand Down Expand Up @@ -68,6 +70,7 @@ public function register(Request $request)
#[OA\Post(
path: '/login',
tags: ['Authentication'],
security: [],
summary: 'User login',
requestBody: new OA\RequestBody(
required: true,
Expand Down
3 changes: 3 additions & 0 deletions app/Http/Controllers/API/v1/Auth/PasswordResetController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
use Illuminate\Support\Facades\Validator;
use OpenApi\Attributes as OA;

#[OA\Tag(name: 'Authentication', description: 'Endpoints for password reset')]
class PasswordResetController extends ApiController
{
public function __construct(private NotificationService $notificationService) {}

#[OA\Post(
path: '/password/reset-code',
tags: ['Authentication'],
security: [],
summary: 'Send password reset code',
requestBody: new OA\RequestBody(
required: true,
Expand Down Expand Up @@ -84,6 +86,7 @@ public function sendPasswordResetCode(Request $request)
#[OA\Post(
path: '/password/reset',
tags: ['Authentication'],
security: [],
summary: 'Reset password using verification code',
requestBody: new OA\RequestBody(
required: true,
Expand Down
Loading
Loading