0

I keep getting req.file is undefined from the api when trying to upload an image from the frontend. I use Laravel's guzzle-http to post the data. When I use postman's form-data ,however, the image gets uploaded successfully so I think it might have to do with something on the frontend.

If you can point me to the right direction that could help a lot.

Heres what I have so far

Node js Controller

exports.post_image = (req, res, next) => {
    console.log(req.file);// outputs undefined
    //validate file is present
    if (!req.file) return res.status(400).json({message: 'Please upload a image!'});}

Node js Route

router.post('/', upload.single('image'), ImageController.post_image);

Laravel Controller

public function store(Request $request)
    {
        $validatedData = Validator::make($request->all(), [
            'image' => 'required|image:jpeg,png,jpg|max:2048',
        ])->validate();
        
        if ($request->hasFile('image')) {
            $image = $validatedData['image'];
        }

        //dd($image);// returns the file and its properties

        
        $url = 'http://localhost:3000/upload';

        $response = Http::post($url, [
            'image' => $image
        ]);

        dd(json_decode($response));// response is 'Please upload a image!'

        $response_decode = json_decode($response);
        $message = $response_decode->message;

        session()->flash('success', $message);

        return redirect()->action('ImageController@index');
    }

Html Page

<form action="{{ route('image.store') }}" method="POST" enctype="multipart/form-data">
  @csrf
  @method('PUT')
    
  <div class="form-group">
     <label for="image">Image</label>
     <input type="file" id="image" name="image" accept="image/png,image/jpeg" class="form-control">
  </div>
  <div class="form-group">
     <button class="btn btn-success">Upload</button>
  </div>
</form>
Steven Selolo
  • 126
  • 1
  • 7

1 Answers1

1

If you would like to send files as multi-part requests, you should call the attach method before making your request.

You need to change certain lines, First change,

 if ($request->hasFile('image')) {
      $image = $request->file('image');
 }

then, secondly,

 $url = 'http://localhost:3000/upload';
 $photo = fopen($image, 'r');

 $image_name = 'image' . $image->getClientOriginalExtension();
 $response = Http::attach(
     'image', $photo, $image_name
 )->post($url);

 dd($response->json(), $response->status());

You can read more from here


method 2 :

You can directly use Guzzle HTTP Client instead of using HTTPClient(expressive, minimal API around the Guzzle HTTP client).

try{
    $url = 'http://localhost:3000/upload';
    if (!empty($image)){
        $guzzleResponse = $client->post($url, [
                        'multipart' => [
                            [
                                'name' => 'image',
                                'contents' => fopen($image, 'r')
                            ] //,
                            /** for other parameters
                            [
                                 'name' => 'description'
                                 'contents' => 'image about cat'
                            ]  //put ',' and similarly add other parameters
                             */
                         ] // ,
                         // 'headers' => $headers  you can add headers here(commented as you have not added any headers in your code snippet)
                    ]);
        if ($guzzleResponse->getStatusCode() == 200) {
            $response = json_decode($guzzleResponse->getBody(), true);  
        }
      }
    }catch (RequestException $e) {
        // you can catch here 400 response errors and 500 response errors
        // see this https://stackoverflow.com/questions/25040436/guzzle-handle-400-bad-request/25040600
    } catch(Exception $e){
        //other errors 
    }
}
bhucho
  • 3,903
  • 3
  • 16
  • 34
  • Please inform me if this works or not, I have another way of doing it as well. – bhucho Oct 16 '20 at 18:29
  • I tried your suggestion above and had a look at the documentation but it still doesn't work.Please provide the other way if possible. – Steven Selolo Oct 17 '20 at 21:25
  • I have added the direct use of Guzzle, I use guzzle directly so I know it works, but why HTTP Client didn't work I have to try that, you can see this [pull](https://github.com/laravel/framework/pull/32428) though it was merged so there shouldn't be any prob I will try & inform – bhucho Oct 18 '20 at 16:44
  • Ok let me check it out – Steven Selolo Oct 18 '20 at 17:40
  • the image uploads successfully with the 2nd code you provided, but when I try to add other form fields to it I get an error stating: Invalid resource type: array. Do you know how to solve this? – Steven Selolo Oct 21 '20 at 12:14
  • how are you adding other form_fields? if you want to send it besides image, you will have to create separate arrays for each field with name & contents as two indexes of that array – bhucho Oct 21 '20 at 13:01
  • Lets say I want to upload the image with the description of it. So what you are saying is that I have to create another array separate from the image one and pass that to multipart? By the way the form includes an image and a description. – Steven Selolo Oct 21 '20 at 13:15
  • edited the answer see the comment part within /** */ – bhucho Oct 21 '20 at 14:08
  • Nice it works, thanks a lot for your patience and replies. – Steven Selolo Oct 21 '20 at 14:13