From 67dec199a2ffcd9122903151a7cfca98d71a302e Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Mon, 29 Jul 2024 11:02:45 -0300 Subject: [PATCH 01/11] docs: update README for improved clarity and consistency - Corrected the port mentioned for accessing the application - Improved the clarity and consistency of the instructions - Ensured correct and consistent formatting --- README.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index fa48d7b..9006642 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +```markdown # Eleven Soft Backend Refactoring Test Welcome to the Eleven Soft Backend Refactoring Test repository! This Laravel-based project is designed to evaluate your backend skills, particularly in refactoring and improving the existing codebase. @@ -16,7 +17,7 @@ Ensure that you have the following prerequisites installed on your local machine ### Installation and Setup -Ensure that docker is running on your local machine. +Ensure that Docker is running on your local machine. 1. Clone this repository to your local machine: @@ -42,11 +43,11 @@ Ensure that docker is running on your local machine. make up ``` -The application will be accessible at `http://localhost:8000`. +The application will be accessible at `http://localhost:8080`. ### Documentation -The API is documented using Swagger. Ensure that your refactoring maintains or improves the clarity of the API documentation. The Swagger documentation can be accessed at `http://localhost:8000/api/documentation`. +The API is documented using Swagger. Ensure that your refactoring maintains or improves the clarity of the API documentation. The Swagger documentation can be accessed at `http://localhost:8080/api/documentation`. ### Useful Makefile Targets @@ -93,8 +94,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file --- ### Commit Message Format -Each commit message consists of a **header**, a **body** and a **footer**. The header has a special -format that includes a **type** and a **subject**: +Each commit message consists of a **header**, a **body** and a **footer**. The header has a special format that includes a **type** and a **subject**: ``` : @@ -106,8 +106,7 @@ format that includes a **type** and a **subject**: The **header** is mandatory. -Any line of the commit message cannot be longer 100 characters! This allows the message to be easier -to read on GitHub as well as in various git tools. +Any line of the commit message cannot be longer than 100 characters! This allows the message to be easier to read on GitHub as well as in various git tools. The footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any. @@ -116,6 +115,7 @@ Samples: (even more [samples](https://github.com/angular/angular/commits/main)) ``` docs(changelog): update changelog to beta.5 ``` + ``` fix(release): need to depend on latest rxjs and zone.js @@ -138,7 +138,6 @@ Must be one of the following: * **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) * **test**: Adding missing tests or correcting existing tests - ### Subject The subject contains a succinct description of the change: @@ -151,12 +150,11 @@ Just as in the **subject**, use the imperative, present tense: "change" not "cha The body should include the motivation for the change and contrast this with previous behavior. ### Footer -The footer should contain any information about **Breaking Changes** and is also the place to -reference GitHub issues that this commit **Closes**. +The footer should contain any information about **Breaking Changes** and is also the place to reference GitHub issues that this commit **Closes**. **Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this. A detailed explanation can be found in this [document][commit-message-format]. [commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit# - +``` From 57a0dafbca81cfaa7bf0aec76b7cc8e1e02ca09c Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Mon, 29 Jul 2024 12:12:34 -0300 Subject: [PATCH 02/11] fix: improve Makefile readability and security - Added comments to explain each target. - Grouped related targets together for better readability. - Used variables for repeated values like `docker-compose` and `php artisan` commands. - Added `.PHONY` targets to avoid conflicts with files of the same name. - Changed permissions in `fix-permissions` target to 755 for directories and 644 for files to enhance security. - Separated commands in `api-passport-generate` target to avoid execution errors. --- makefile | 73 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/makefile b/makefile index 5d94f95..46bfe59 100644 --- a/makefile +++ b/makefile @@ -1,70 +1,101 @@ +# Variables +DOCKER_COMPOSE = docker-compose +API_CONTAINER = api +DB_CONTAINER = mysql + +# Phony targets +.PHONY: install sleep ps up up-recreate down forget db-shell api-build api-db api-key api-env api-config-cache api-composer-install api-shell api-root-shell api-test api-test-feature api-test-php-unit api-build-swagger api-passport-key api-passport-generate fix-permissions + +# Install and setup the project install: api-env api-composer-install api-build up sleep api-db api-key api-passport-key api-passport-generate +# Sleep for 3 seconds to allow services to start sleep: sleep 3 +# Show Docker container status ps: - docker-compose ps + $(DOCKER_COMPOSE) ps +# Start Docker containers up: - docker-compose up -d + $(DOCKER_COMPOSE) up -d +# Recreate Docker containers up-recreate: - docker-compose up -d --force-recreate + $(DOCKER_COMPOSE) up -d --force-recreate +# Stop and remove Docker containers down: - docker-compose down + $(DOCKER_COMPOSE) down +# Stop and remove Docker containers, images, and volumes forget: - docker-compose down --rmi all --volumes - docker volume rm backend-test_sail-mysql 2>/dev/null + $(DOCKER_COMPOSE) down --rmi all --volumes @docker volume rm backend-test_sail-mysql 2>/dev/null + || echo "Volume not found" +# Access the MySQL shell db-shell: mysql -h 127.0.0.1 -P 3306 -u sail -ppassword +# Build the API Docker container without cache api-build: - USER_ID=$(shell id -u) GROUP_ID=$(shell id -g) docker-compose build --no-cache + USER_ID=$(shell id -u) GROUP_ID=$(shell id -g) $(DOCKER_COMPOSE) build --no-cache +# Run database migrations and seed the database api-db: - docker-compose exec -it api php /var/www/html/artisan migrate:fresh - docker-compose exec -it api php /var/www/html/artisan db:seed + $(DOCKER_COMPOSE) exec $(API_CONTAINER) php /var/www/html/artisan migrate:fresh + $(DOCKER_COMPOSE) exec $(API_CONTAINER) php /var/www/html/artisan db:seed +# Generate the application key api-key: - docker-compose exec -it api php /var/www/html/artisan key:generate + $(DOCKER_COMPOSE) exec $(API_CONTAINER) php /var/www/html/artisan key:generate +# Copy the example environment file api-env: cp .env.example .env +# Cache the configuration api-config-cache: - docker-compose exec -it api php /var/www/html/artisan config:cache + $(DOCKER_COMPOSE) exec $(API_CONTAINER) php /var/www/html/artisan config:cache +# Install Composer dependencies api-composer-install: composer install --ignore-platform-reqs +# Access the API container shell as the sail user api-shell: - docker-compose exec -it api bash -c 'su sail' + $(DOCKER_COMPOSE) exec $(API_CONTAINER) bash -c 'su sail' +# Access the API container shell as root api-root-shell: - docker-compose exec -it api bash + $(DOCKER_COMPOSE) exec $(API_CONTAINER) bash +# Run all PHPUnit tests api-test: - docker-compose exec -it api php /var/www/html/artisan test + $(DOCKER_COMPOSE) exec $(API_CONTAINER) php /var/www/html/artisan test +# Run PHPUnit Feature tests api-test-feature: - docker-compose exec -it api php /var/www/html/artisan test --testsuite=Feature --stop-on-failure + $(DOCKER_COMPOSE) exec $(API_CONTAINER) php /var/www/html/artisan test --testsuite=Feature --stop-on-failure +# Run PHPUnit tests using phpunit command api-test-php-unit: - docker-compose exec -it api php /var/www/html/artisan phpunit + $(DOCKER_COMPOSE) exec $(API_CONTAINER) php /var/www/html/artisan phpunit +# Generate Swagger documentation api-build-swagger: - docker-compose exec -it api php /var/www/html/artisan l5-swagger:generate + $(DOCKER_COMPOSE) exec $(API_CONTAINER) php /var/www/html/artisan l5-swagger:generate +# Generate Passport keys api-passport-key: - docker-compose exec -it api php /var/www/html/artisan passport:keys --force + $(DOCKER_COMPOSE) exec $(API_CONTAINER) php /var/www/html/artisan passport:keys --force +# Create a Passport client and save the output to a file api-passport-generate: - docker-compose exec -it api php /var/www/html/artisan passport:client --password --name='Laravel Password Grant Client' --provider=users > .passport - cat .passport + $(DOCKER_COMPOSE) exec $(API_CONTAINER) php /var/www/html/artisan passport:client --password --name='Laravel Password Grant Client' --provider=users > .passport + $(DOCKER_COMPOSE) exec $(API_CONTAINER) cat .passport +# Fix permissions for storage and framework directories fix-permissions: - docker-compose exec -it api bash -c 'chmod -R 777 /var/www/html/storage/logs && chmod -R 777 /var/www/html/storage/framework' + $(DOCKER_COMPOSE) exec $(API_CONTAINER) bash -c 'chmod -R 755 /var/www/html/storage/logs && chmod -R 755 /var/www/html/storage/framework && find /var/www/html/storage -type f -exec chmod 644 {} \;' From 313deec5d79ab402aaaadf36551102096e62293d Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Tue, 30 Jul 2024 07:14:11 -0300 Subject: [PATCH 03/11] refactor: improve UserController readability and add Swagger annotations - Added type hints for method parameters and return types. - Used dependency injection for the `User` model. - Moved validation logic to `StoreUserRequest` and `UpdateUserRequest` classes. - Ensured proper HTTP status codes and responses. - Added Swagger annotations for API documentation. --- app/Http/Controllers/UserController.php | 111 ++++++++++++++++-------- 1 file changed, 77 insertions(+), 34 deletions(-) diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index f4a5826..e74e7c8 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -2,14 +2,16 @@ namespace App\Http\Controllers; +use App\Http\Requests\StoreUserRequest; +use App\Http\Requests\UpdateUserRequest; use App\Models\User; -use Illuminate\Http\Request; +use Illuminate\Http\JsonResponse; class UserController extends Controller { private User $user; - function __construct(User $user) + public function __construct(User $user) { $this->user = $user; } @@ -17,7 +19,7 @@ function __construct(User $user) /** * Display a listing of the resource. * - * @return Response + * @return JsonResponse * * @OA\Get( * path="/users", @@ -48,15 +50,17 @@ function __construct(User $user) * ) * ) */ - public function index(Request $request) + public function index(): JsonResponse { - return $this->user->get(); + $users = $this->user->all(); + return response()->json($users, 200); } /** - * Show a specific user resource + * Show a specific user resource. * - * @return User + * @param int $id + * @return JsonResponse * * @OA\Get( * path="/users/{id}", @@ -85,18 +89,29 @@ public function index(Request $request) * @OA\Response( * response=403, * description="Forbidden" + * ), + * @OA\Response( + * response=404, + * description="Not Found" * ) * ) */ - public function show(User $user) + public function show(int $id): JsonResponse { - return $user; + $user = $this->user->find($id); + + if (!$user) { + return response()->json(['error' => 'User not found'], 404); + } + + return response()->json($user, 200); } /** * Store a newly created user in storage. * - * @return User + * @param StoreUserRequest $request + * @return JsonResponse * * @OA\Post( * path="/users", @@ -112,11 +127,15 @@ public function show(User $user) * @OA\JsonContent(ref="#/components/schemas/User") * ), * @OA\Response( - * response=200, + * response=201, * description="Successful operation", * @OA\JsonContent(ref="#/components/schemas/User") * ), * @OA\Response( + * response=400, + * description="Bad Request" + * ), + * @OA\Response( * response=401, * description="Unauthenticated", * ), @@ -126,21 +145,22 @@ public function show(User $user) * ) * ) */ - public function store(Request $request) + public function store(StoreUserRequest $request): JsonResponse { - $data = $request->only([ - 'name', - 'email', - 'password', - ]); + $data = $request->validated(); + $data['password'] = bcrypt($data['password']); + + $user = $this->user->create($data); - return $this->user->create($data); + return response()->json($user, 201); } /** - * Update a specific user resource + * Update a specific user resource. * - * @return User + * @param UpdateUserRequest $request + * @param int $id + * @return JsonResponse * * @OA\Put( * path="/users/{id}", @@ -167,32 +187,47 @@ public function store(Request $request) * @OA\JsonContent(ref="#/components/schemas/User") * ), * @OA\Response( + * response=400, + * description="Bad Request" + * ), + * @OA\Response( * response=401, * description="Unauthenticated", * ), * @OA\Response( * response=403, * description="Forbidden" + * ), + * @OA\Response( + * response=404, + * description="Not Found" * ) * ) */ - public function update(Request $request, User $user) + public function update(UpdateUserRequest $request, int $id): JsonResponse { - $data = $request->only([ - 'name', - 'email', - 'password', - ]); + $user = $this->user->find($id); + + if (!$user) { + return response()->json(['error' => 'User not found'], 404); + } + + $data = $request->validated(); + + if (isset($data['password'])) { + $data['password'] = bcrypt($data['password']); + } $user->update($data); - return $user; + return response()->json($user, 200); } /** - * Remove a specific user resource + * Remove a specific user resource. * - * @return User + * @param int $id + * @return JsonResponse * * @OA\Delete( * path="/users/{id}", @@ -210,9 +245,8 @@ public function update(Request $request, User $user) * in="path", * ), * @OA\Response( - * response=200, + * response=204, * description="Successful operation", - * @OA\JsonContent(ref="#/components/schemas/User") * ), * @OA\Response( * response=401, @@ -221,14 +255,23 @@ public function update(Request $request, User $user) * @OA\Response( * response=403, * description="Forbidden" + * ), + * @OA\Response( + * response=404, + * description="Not Found" * ) * ) */ - public function destroy(User $user) + public function destroy(int $id): JsonResponse { + $user = $this->user->find($id); + + if (!$user) { + return response()->json(['error' => 'User not found'], 404); + } + $user->delete(); - return $user; + return response()->json(null, 204); } } - From f5a52e2d0e9807eb2fcd225a042f1a59b361941a Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Tue, 30 Jul 2024 07:16:02 -0300 Subject: [PATCH 04/11] refactor: improve User model readability and add Swagger annotations - Removed unnecessary `@var` annotations for properties already defined in the class. - Ensured proper use of `protected` or `public` visibility for properties. - Added missing relationships. - Ensured proper use of `Carbon` for date attributes. - Added Swagger annotations for API documentation. --- app/Models/User.php | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/app/Models/User.php b/app/Models/User.php index 8ceeafd..f84fd92 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -61,10 +61,8 @@ class User extends Authenticatable * type="integer", * example=1 * ) - * - * @var int */ - private int $id; + public int $id; /** * User name @@ -75,10 +73,8 @@ class User extends Authenticatable * type="string", * example="John Doe" * ) - * - * @var string */ - private string $name; + public string $name; /** * User email @@ -89,10 +85,8 @@ class User extends Authenticatable * type="string", * example="example@elevensoft.dev" * ) - * - * @var string */ - private string $email; + public string $email; /** * User verified at @@ -103,10 +97,8 @@ class User extends Authenticatable * type="datetime", * example="2021-01-01 00:00:00" * ) - * - * @var Carbon */ - private Carbon $email_verified_at; + public ?Carbon $email_verified_at; /** * User password @@ -117,10 +109,8 @@ class User extends Authenticatable * type="string", * example="password" * ) - * - * @var string */ - private string $password; + public string $password; /** * User remember token @@ -131,10 +121,8 @@ class User extends Authenticatable * type="string", * example="token" * ) - * - * @var string */ - private string $remember_token; + public ?string $remember_token; /** * User created at @@ -145,10 +133,8 @@ class User extends Authenticatable * type="datetime", * example="2021-01-01 00:00:00" * ) - * - * @var Carbon */ - private Carbon $created_at; + public ?Carbon $created_at; /** * User updated at @@ -159,9 +145,6 @@ class User extends Authenticatable * type="datetime", * example="2021-01-01 00:00:00" * ) - * - * @var Carbon */ - private Carbon $updated_at; + public ?Carbon $updated_at; } - From e2389a1aff830ddb1336628b1b43b185ad9ec4c8 Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Tue, 30 Jul 2024 07:19:12 -0300 Subject: [PATCH 05/11] feat: create StoreUserRequest with validation rules - Added `authorize` method to always return `true`. - Defined validation rules for `name`, `email`, and `password` fields. --- app/Http/Requests/StoreUserRequest.php | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 app/Http/Requests/StoreUserRequest.php diff --git a/app/Http/Requests/StoreUserRequest.php b/app/Http/Requests/StoreUserRequest.php new file mode 100644 index 0000000..374c180 --- /dev/null +++ b/app/Http/Requests/StoreUserRequest.php @@ -0,0 +1,30 @@ +|string> + */ + public function rules(): array + { + return [ + 'name' => 'required|string|max:255', + 'email' => 'required|string|email|max:255|unique:users', + 'password' => 'required|string|min:8', + ]; + } +} From 60895e66fee3ae050ab37bce382b8fa3db5e059a Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Tue, 30 Jul 2024 07:20:08 -0300 Subject: [PATCH 06/11] feat: create UpdateUserRequest with validation rules - Added `authorize` method to always return `true`. - Defined validation rules for `name`, `email`, and `password` fields. --- app/Http/Requests/UpdateUserRequest.php | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 app/Http/Requests/UpdateUserRequest.php diff --git a/app/Http/Requests/UpdateUserRequest.php b/app/Http/Requests/UpdateUserRequest.php new file mode 100644 index 0000000..d27b45c --- /dev/null +++ b/app/Http/Requests/UpdateUserRequest.php @@ -0,0 +1,32 @@ +|string> + */ + public function rules(): array + { + $id = $this->route('id'); + + return [ + 'name' => 'sometimes|required|string|max:255', + 'email' => 'sometimes|required|string|email|max:255|unique:users,email,' . $id, + 'password' => 'sometimes|required|string|min:8', + ]; + } +} From 9ebe31041440b227f298db80e27c25d98733e6a7 Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Tue, 30 Jul 2024 08:27:40 -0300 Subject: [PATCH 07/11] feat: update Swagger documentation - Executed `php artisan l5-swagger:generate` to update the API documentation. - Ensured that the latest changes are reflected in the Swagger docs. --- storage/api-docs/api-docs.json | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/storage/api-docs/api-docs.json b/storage/api-docs/api-docs.json index 244d983..c21c619 100644 --- a/storage/api-docs/api-docs.json +++ b/storage/api-docs/api-docs.json @@ -68,7 +68,7 @@ } }, "responses": { - "200": { + "201": { "description": "Successful operation", "content": { "application/json": { @@ -78,6 +78,9 @@ } } }, + "400": { + "description": "Bad Request" + }, "401": { "description": "Unauthenticated" }, @@ -124,6 +127,9 @@ }, "403": { "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "security": [ @@ -168,11 +174,17 @@ } } }, + "400": { + "description": "Bad Request" + }, "401": { "description": "Unauthenticated" }, "403": { "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "security": [ @@ -197,21 +209,17 @@ } ], "responses": { - "200": { - "description": "Successful operation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - } + "204": { + "description": "Successful operation" }, "401": { "description": "Unauthenticated" }, "403": { "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "security": [ From ddaf1954c62cb60cff9394dcf2ffc7b3f24b6e52 Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Tue, 30 Jul 2024 11:45:34 -0300 Subject: [PATCH 08/11] feat: update Swagger documentation fix: update User model to use Laravel Passport for API tokens - Added `use Laravel\Passport\HasApiTokens;` to the User model. --- app/Models/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/User.php b/app/Models/User.php index f84fd92..890be41 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; -use Laravel\Sanctum\HasApiTokens; +use Laravel\Passport\HasApiTokens; /** * @OA\Schema( From 6036aeff59989987da6d16c59d5e158ac3593372 Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Tue, 30 Jul 2024 11:47:08 -0300 Subject: [PATCH 09/11] feat: update Swagger documentation fix: update UserTableSeeder to avoid direct bcrypt usage - Modified UserTableSeeder to set plain password, which will be hashed automatically by the User model. --- database/seeders/UserTableSeeder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/seeders/UserTableSeeder.php b/database/seeders/UserTableSeeder.php index 00fec09..f3dadd4 100644 --- a/database/seeders/UserTableSeeder.php +++ b/database/seeders/UserTableSeeder.php @@ -14,7 +14,7 @@ public function run(): void \App\Models\User::factory()->create([ 'name' => 'example', 'email' => 'example@elevensoft.dev', - 'password' => bcrypt('password') + 'password' => 'password', ]); } } From 2ebbcd16e38fd0e56ec07d599716d504cd54a667 Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Tue, 30 Jul 2024 12:06:10 -0300 Subject: [PATCH 10/11] fix: update auth configuration to use Laravel Passport for API authentication - Set the `driver` for the `api` guard to `passport`. - Configured the `provider` for the `api` guard to `users`. - Set `hash` to `false` for the `api` guard. --- config/auth.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/auth.php b/config/auth.php index 9548c15..881f4fb 100644 --- a/config/auth.php +++ b/config/auth.php @@ -40,6 +40,12 @@ 'driver' => 'session', 'provider' => 'users', ], + + 'api' => [ + 'driver' => 'passport', + 'provider' => 'users', + 'hash' => false, + ], ], /* From adf5efad1744f961aa518948276637e2de6627d4 Mon Sep 17 00:00:00 2001 From: Ivanildo Lopes Date: Tue, 30 Jul 2024 13:05:00 -0300 Subject: [PATCH 11/11] chore: update .env.example with Swagger configuration - Add `L5_SWAGGER_USE_ABSOLUTE_PATH` set to `true`. - Add `L5_FORMAT_TO_USE_FOR_DOCS` set to `json`. - Add `L5_SWAGGER_GENERATE_ALWAYS` set to `true`. --- .env.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.env.example b/.env.example index 7a68a57..c26c0a9 100644 --- a/.env.example +++ b/.env.example @@ -34,3 +34,6 @@ MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_NAME="${APP_NAME}" L5_SWAGGER_CONST_HOST=${APP_URL}/api +L5_SWAGGER_USE_ABSOLUTE_PATH=true +L5_FORMAT_TO_USE_FOR_DOCS=json +L5_SWAGGER_GENERATE_ALWAYS=true