Closed aruku closed 1 year ago
@aruku Hi! We need more info to try to reproduce this one. Could you please refine:
Sorry about that... Laravel 10.11 and Laravel Swagger v2.1.
IndexTest.php
<?php
namespace Api\V0\Orders;
use App\Models\Order;
use Faker\Generator;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\App;
use Tests\TestCase;
class IndexTest extends TestCase
{
use RefreshDatabase;
public function test_list_all_orders(): void
{
$faker = App::make(Generator::class);
$orders = Order::factory()->count($faker->randomNumber(2))->create();
$response = $this
->jsonApi()
->expects('orders')
->get('/api/v0/orders');
$response->assertFetchedMany($orders);
}
}
OrderRequest.php
<?php
namespace App\JsonApi\V0\Orders;
use LaravelJsonApi\Laravel\Http\Requests\ResourceRequest;
use LaravelJsonApi\Validation\Rule;
class OrderRequest extends ResourceRequest
{
/**
* Get the validation rules for the resource.
*
* @return array
*/
public function rules(): array
{
return [
'cadastral_reference' => ['required', 'string'],
'city' => ['required', 'string'],
'street' => ['required', 'string'],
'number' => ['required', 'string'],
'building' => ['required', 'string'],
'staircase' => ['required', 'string'],
'floor' => ['required', 'string'],
'location' => ['required', 'string'],
'door' => ['required', 'string'],
'price' => ['required', Rule::integer()],
'terms_accepted' => ['required', Rule::boolean()],
'data_protection_policy_accepted' => ['required', Rule::boolean()],
'cee_policy_accepted' => ['required', Rule::boolean()],
'name' => ['required', 'string'],
'email' => ['required', 'string'],
'phone' => ['required', 'string'],
];
}
}
@aruku thanks! we'll check it
@aruku after investigation, I've found a reason. It seems your controller's method depends on the contract class which has not bind to implementation yet. Could you please check that your test will be finished sucessfully with disabled autodoc? For it, please call skipDocumentationCollecting
method in the setUp
method or as the first line of your test case. If you don't use the AutoDocTestCaseTrait
in your test case class - you can manually set the RonasIT\Support\AutoDoc\Http\Middleware\AutoDocMiddleware::$skipped
property as true
.
That way it works, yes. But I don't understand the problem you describe. Could you elaborate, please?
@aruku got it, let me describe how it works technically. To generate the API input params - script should parse validation rules from the form request, injected to controller's method.
Here is example from the Laravel doc https://laravel.com/docs/10.x/validation#creating-form-requests
But in some cases, instead of concrete form request class - can be inject the contract, which should be bind to the concrete form request class.
So script parse all arguments of the controller's method and try to resolve all contracts to determine is one of them is a form request class.
As I can see - the second argument of your class is a contract, so the application try to resolve it and fail. I suppose that it can be performed by two reasons:
__construct
method (trait, interface, enum)We'll fix it to prevent such cases in the future.
Please also note that you need to inject the FormRequest
class inside the controller's method to able package to collect the API description
In your current implementation after we fix the error - the API will be just skipped, because index
method hasn't got the FormRequest class as described argument and package couldn't parse the rules
method.
@Goodmain could you please fix described error and update the readme file as we discussed to add the controller's method example after the request class example and before the test method example.
Thank you. I think I understand the problem but not so much the solution: should I bind the contract class to the request one?
Like App::bind(Store::class, OrderRequest::class);
?
Where would I do it? In AppServideProvider?
@aruku not exactly, just add the third OrderRequest $request
arg to controller's index method. It should looks like this
public function index(Route $route, StoreContract $store, OrderRequest $request)
{
// code here
}
such code will automatically inject the concrete FormRequest class and validate the input data
I see. Unfortunately, I can't do that because I'm extending a class from https://github.com/laravel-json-api/laravel. Is there an alternative?
@aruku as alternative, we may implement an ability to set the related form request class via the annotation param, e.g.
/**
* @request OrderRequest
*/
public function index(Route $route, StoreContract $store)
{
// code here
}
but in this case you'll have to redefine parent controller's class to set the annotation
If you can redefine controller - you may try to do somethig like this
public function index(Route $route, StoreContract $store, OrderRequest $request)
{
parent::index($route, $store);
}
but I suppose that in this case validation process will be run twice, which is not good
What about configuration? Could we map the request classes to each action in some config.php file?
@aruku we'll discusse it with team.
I'm curious, the controller's example you've provided is just a trait which you have to use in your local class I supposed. How you make the validation with the OrderRequest
you've provided above?
@aruku We've fixed the main issue related to the contract. You may install the dev-master
version to for it. We've also update readme file.
I'm no longer working on the project that had this need, but thank you anyway. Appreciate it!
@aruku thanks! Hope you'll work with our solution further! I've tested the main issue, and it seems fixed, I'll mark it as ready for version.
I'm using https://github.com/laravel-json-api/laravel and this is what happens when I get the tests with laravel-swagger installed:
Any suggestions? Thank you.