Error A 'contents' key is required al enviar archivos desde una api con Http Client

Publicado por Luis Aguilar
hace 3 semanas

Estoy tratando de enviar un archivo de video desde mi app en laravel mediante POST usando hacia una API,y me genera un error A 'contents' key is required e intentado todas las soluciones posibles y no encuentro la solucion.

Este es la funcion de mi controlador que recibe los datos de mi formulario POST.

public function store(Request $request)
{
    $validated = $request->validate([
        'nameVideo' => 'required|max:255',
        'videoFile' => 'required|file|mimes:mp4,mov,avi|max:3072000',
        'datePublication' => 'required|date',
        'producer' => 'required|string|in:' . implode(',', $this->producers),
        'selectArtist' => ['required', 'array', function ($attribute, $value, $fail) {
            foreach ($value as $artist) {
                if (!in_array($artist, $this->artists)) {
                    $fail("El valor $artist no es válido para el campo $attribute.");
                }
            }
        }],
        'selectCategories' => ['required', 'array', function ($attribute, $value, $fail) {
            foreach ($value as $category) {
                if (!in_array($category, $this->categories)) {
                    $fail("El valor $category no es válido para el campo $attribute.");
                }
            }
        }],
        'newCategories' => 'nullable|string',
        'descriptionVideo' => 'nullable',
    ]);

//Las validaciones se hacen correctamente

    $video = $request->file('videoFile');

    $data = [
        'nombreVideo' => $validated['nameVideo'],
        'fechaPublicacion' => $validated['datePublication'],
        'productora' => $validated['producer'],
        'listadoArtistas' => $validated['selectArtist'], // Array de artistas seleccionados
        'listadoCategorias' => $validated['selectCategories'], // Array de categorías seleccionadas
        'descripcion' => $validated['descriptionVideo'],
    ];

    // Enviar la solicitud HTTP con los datos del formulario y el video
    $response = Http::timeout(900)->asMultipart()->withHeaders([
            'Authorization' => 'Bearer ' . Session::get('api_token'),
            'Accept' => 'application/json',
        ])
        ->attach('video', file_get_contents($video->getRealPath()), $video->getClientOriginalName())
        ->post($this->endpoint_url, $data);

    return $this->handlerResponse($response, 'Error al enviar el video');
}

La api tiene que recibir un multipart/fom-data del tipo

 String nombreVideo,
    MultipartFile video,
    Date fechaPublicacion,
    String productora,
    List<String> listadoArtistas,
    List<String> listadoCategorias,
    String descripcion

y recibo el error A 'contents' key is required

Laravel 11 HttpClient post multipart attach
Respuesta de Cristian Olaz
hace 3 semanas

Hola Luis,

Por empezar, imagino que ya lo hiciste pero tendrías que asegurarte que file_get_contents te está devolviendo correctamente el contenido del archivo:

dd(file_get_contents($video->getRealPath());

En segundo lugar, aparentemente en algunas versiones si enviás un archivo adjunto entonces no podés enviar los datos en la manera que lo estás haciendo. Y en su lugar tendrías que definirlos de esta manera:

$data = [
    [
        'name' => 'nombreVideo'
        'contents' => $validated['nameVideo'],
    ],
    [
        'name' => 'fechaPublicacion'
        'contents' => $validated['datePublication'],
    ],
    [
        'name' => 'productora'
        'contents' => $validated['producer'],
    ],
    [
        'name' => 'listadoArtistas'
        'contents' => $validated['selectArtist'], // Array de artistas seleccionados
    ],
    [
        'name' => 'listadoCategorias'
        'contents' => $validated['selectCategories'], // Array de categorías seleccionadas
    ],
    [
        'name' => 'descripcion'
        'contents' => $validated['descriptionVideo'],
    ],
    [
        'name' => 'video',
        'contents' => file_get_contents($video->getRealPath()),
        'filename' => $video->getClientOriginalName()
    ]
];

Y luego enviarlo como lo estabas haciendo pero sin el attach:

    $response = Http::timeout(900)->asMultipart()->withHeaders([
            'Authorization' => 'Bearer ' . Session::get('api_token'),
            'Accept' => 'application/json',
        ])
        ->post($this->endpoint_url, $data);

Espero que te sirva. Saludos,