knuckleswtf / scribe

Generate API documentation for humans from your Laravel codebase.✍
https://scribe.knuckles.wtf/laravel/
MIT License
1.58k stars 280 forks source link

When using FormRequest with 'file' validation, request data is empty even data is provided in docs example body #764

Open lHondol opened 7 months ago

lHondol commented 7 months ago

Scribe version

4.23

PHP version

8.2.4

Framework

Laravel

Framework version

10

Scribe config

theme => "elements"
title => "Notex"                  
base_url => "http://localhost:8000"           
try_it_out.base_url => "http://localhost:8000"
auth.enabled => true
auth.default => true
auth.name => "Authorization"

What happened?

In my FormRequest, i have these rules:

public function rules(): array
{
    return [
        'information' => ['required'],
        'file' => ['required', 'file'],
    ];
}

In the generated documentation, within the "try_out" body, I can now choose the file I need to upload. However, when I hit submit, the response states, 'The information field is required,' even though I have already provided the value.

also the request payload:

------WebKitFormBoundaryPuRQG2gkhYZdgo8K
Content-Disposition: form-data; name="information"

tempore

------WebKitFormBoundaryPuRQG2gkhYZdgo8K
Content-Disposition: form-data; name="file"; filename="myfile.pdf"
Content-Type: application/pdf

------WebKitFormBoundaryPuRQG2gkhYZdgo8K--

request headers : Content-Type: 'multipart/form-data' Accept: 'application/json'

Docs

mcpicoli commented 6 months ago

Having similar trouble here using try-it-out. Route uses HTTP PUT method and has a "file" parameter named "photo". php artisan scribe:generate generates "correct" documentation, I can pick a file and fill other parameters. If no file is selected, everything works fine, only when providing it, it is missing as described by the OP.

257 should have fixed this problem, but the HTTP method is never changed to POST, the hidden parameter "_method" is never added and the Content-Type header is never changed to multipart/form-data. The file is never seen by the server (as expected since PUT does not support multipart/form-data in PHP) and because of that the validation logic fails, stating the file is invalid since it is encoded as an empty JSON body.

{"photo":{}}

The request header, as per the browser developer tools is not changed from "Content-Type: application/json"

If I change the header manually to "multipart/form-data", the validation logic passes (the file is not mandatory), but the try-it-out does not send anything multipart encoded (file is missing), nothing is done at all regarding the file. The correct (manually changed) Content-Type is sent, but (if I am not understanding something wrong), it should be deleted (line 192)

Edit: version here is 4.25.0

shalvah commented 6 months ago

Thanks for your preliminary investigation. I'll look at this some more when I have the time, but in the meantime, feel free to submit a PR if you have an idea what needs to be fixed.

wlhrtr commented 3 weeks ago

When uploading a file the Content-Type header must not be set otherwise the browser cannot set the right boundaries for the multipart formdata payload.

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects

Bildschirmfoto 2024-06-06 um 12 07 56

You can add following code to index.blade.php of vendor published elements template in line :126 to get it to work

// ...
let preflightPromise = Promise.resolve();
if (window.useCsrf && window.csrfUrl) {
    preflightPromise = makeAPICall('GET', window.csrfUrl).then(() => {
        headers['X-XSRF-TOKEN'] = getCookie('XSRF-TOKEN');
    });
}

// START this needs to be added
if (form.dataset.hasfiles === "1") {
    delete headers['Content-Type'];
}
// END this needs to be added

return preflightPromise.then(() => makeAPICall(method, path, body, query, headers, endpointId))
// ...
shalvah commented 2 weeks ago

Can you make a PR with that fix?