saloonphp / saloon

šŸ¤  Build beautiful API integrations and SDKs with Saloon
https://docs.saloon.dev
MIT License
2.09k stars 107 forks source link

HasMultipartBody and multiple files with the same key #338

Closed ManukMinasyan closed 12 months ago

ManukMinasyan commented 12 months ago

This pure Laravel code is working properly:

use Illuminate\Support\Facades\Http;

$files = [
            [
                'name' => 'files',
                'contents' => fopen($voice->getMedia('samples')->first()->getPath(), 'r'),
                'filename' => 'sample1.mp3',
                'headers' => [
                    'Content-Type' => 'audio/mpeg'
                ]
            ],
            [
                'name' => 'files',
                'contents' => fopen($voice->getMedia('samples')->last()->getPath(), 'r'),
                'filename' => 'sample2.mp3',
                'headers' => [
                    'Content-Type' => 'audio/mpeg'
                ]
            ]
        ];

        $headers = [
            "Accept" => "application/json",
            "xi-api-key" => config('services.eleven_labs.api_key'),
        ];

        $response = Http::withHeaders($headers)
            ->attach($files)
            ->post('https://api.elevenlabs.io/v1/voices/add', [
                'name' => $voice->name,
                'description' => $voice->description,
            ]);

But this Saloon code don't work, I get uploaded only last file, not all files with key "files"

class AddVoiceRequest extends Request implements HasBody
{
    use HasMultipartBody;

    /**
     * Define the HTTP method
     *
     * @var Method
     */
    protected Method $method = Method::POST;

    public function __construct(
        protected string  $name,
        protected MediaCollection $samples,
        protected ?string $description,
    )
    {
    }

    protected function defaultBody(): array
    {
        $files = $this->samples->map(function (Media $file) {
            return new MultipartValue('files', fopen($file->getPath(), 'r'));
        })->toArray();

        return [
            new MultipartValue('name', $this->name),
            new MultipartValue('description', $this->description ?? ''),
            ...$files
        ];
    }

    /**
     * Define the endpoint for the request
     *
     * @return string
     */
    public function resolveEndpoint(): string
    {
        return '/v1/voices/add';
    }
}
Sammyjo20 commented 12 months ago

Hey @ManukMinasyan thanks for reporting this. I've had a few people report the same thing, so I'm considering changing the way the code works.

Sammyjo20 commented 12 months ago

Hey @ManukMinasyan I've just released v3.1 which should hopefully fix this issue šŸ¤ž would you mind trying it out and letting me know? I've found with some APIs, you might have to use square-brackets on each of the file names (e.g files[]) to get it working too, but try your implementation first.

ManukMinasyan commented 12 months ago

Hi @Sammyjo20, I wanted to let you know that everything is working as expected. Thank you for your hard work and dedication. Keep up the great work! šŸ˜Š