1

I'm having trouble uploading files from react to a laravel api. I have a backend for uploading a post that has title,body and image. if their is an image it should save the url of the image and if not save a default value. i tested with postman and it worked correctly but when i'm trying to upload from my react front end, it saves noimage for every trial.

Laravel api

public function save(Request $request)
    {
        $validator = Validator::make($request->all(),[
            'title'=>'required',
            'body'=>'required',
            'user_id'=>'required'
        ]);
        $post = new Post();
            $post->title = $request->title;
            $post->body= $request->body;
            $post->user_id= auth()->user()->id;
            if($request->hasFile('image')){
                $fileNameWithExt = $request->file('image')->getClientOriginalName();
                $fileName = pathinfo($fileNameWithExt,PATHINFO_FILENAME);
                $fileExt = $request->file('image')->getClientOriginalExtension();
                $fileNameToStore = $fileName.'_'. time() .'.'.$fileExt;
                $path = $request->file('image')->storeAs('public/images',$fileNameToStore);
            }else{
                $fileNameToStore = "NoImage.jpg";
            }
            $post->image =$fileNameToStore;
            $post->save();

        return new PostResource($post);
    }

React code

    const [imgName,setImgName] = useState('Choose Image');
        const [postImg,setPostImg] = useState()
        const [postData,setPostData] = useState({
            title:'',
            body:''
        });
    
        const {title,body} = postData;
    
        const changeHandler = e =>{  
           setPostData({...postData,[e.target.name]:e.target.value});
        }
    
        const fileHandler = e=>{
            setImgName(e.target.files[0].name);
            setPostImg(e.target.files[0]);
            
        }
    
        const submitHandler = e =>{
            e.preventDefault();
            
            if(!title || !body){
                props.setMsg("You can't leave title or body field blank",'warning');
                setTimeout(()=>{
                    props.clearError()
                },3000)
            }else{
                const fd = new FormData();
                fd.append('image',postImg)
                const data = {
                    title:title,
                    body:body,
                    image:fd
                }
                
                props.onCreatePost(data);
                console.log(fd.get('image'));
                
            }
           
        }

I'm using redux to with react

`

export const createPost = (formData)=>{
    return (dispatch) =>{
        const token = localStorage.getItem('token')
        const config ={
            headers:{
                'Authorization':`Bearer ${token}`,
                
            }, 
        }
        console.log('Sent Data: ',formData);
           axios.post(`http://127.0.0.1:8000/api/posts`,formData,config)
            .then(res=>{
                dispatch(addPost(res.data))
            }).catch(err=>{
                dispatch(postfailed(err.response))
            })        
    }
}

`

Yhomi
  • 40
  • 6
  • Please post code which uploads the image to your backend. – SaachiTech Sep 22 '20 at 13:46
  • It's not clear when your code post the data to your backend. You have declared ```formdata``` but seems not used which ``props.onCreatePost(data);``` submit data object to a method whose definition is not available – SaachiTech Sep 22 '20 at 14:17
  • `export const createPost = (formData)=>{ return (dispatch) =>{ const token = localStorage.getItem('token') const config ={ headers:{ 'Authorization':`Bearer ${token}`, }, } console.log('Sent Data: ',formData); axios.post(`http://127.0.0.1:8000/api/posts`,formData,config) .then(res=>{ dispatch(addPost(res.data)) }).catch(err=>{ dispatch(postfailed(err.response)) }) } }` – Yhomi Sep 22 '20 at 14:17
  • Please add this to your question so it's more readable. – SaachiTech Sep 22 '20 at 14:18
  • 1
    I have done that, Thank you this is my first time of asking question here – Yhomi Sep 22 '20 at 14:25
  • try updating ```props.onCreatePost(data);``` to ```props.onCreatePost(fd);``` – SaachiTech Sep 22 '20 at 14:27
  • If i do that, the other fields {title,body} that i'm sending along won't be their – Yhomi Sep 22 '20 at 14:34
  • You need to add them in form data instead of making formdata part of the object. – SaachiTech Sep 22 '20 at 14:37
  • I don't get what you mean – Yhomi Sep 22 '20 at 14:42

2 Answers2

1

You need to send the request as multipart/form-data if you need to include files in your post request:

const config ={
    headers:{
        'Authorization':`Bearer ${token}`,
         'Content-Type': 'multipart/form-data'
     }, 
}

If you want to learn more about the subject I suggest you read this: application/x-www-form-urlencoded or multipart/form-data?


Also, you must attach every field as formData, you can't create a javascript object with a formdata inside

Instead of:

const fd = new FormData();
fd.append('image',postImg)
const data = {
   title:title,
   body:body,
   image:fd
}
                
props.onCreatePost(data);

Do:

const fd = new FormData();
fd.append('image',postImg)
fd.append('title', title)
fd.append('body', body)             
props.onCreatePost(fd);

gbalduzzi
  • 7,129
  • 18
  • 44
0

Please update your formdata to following

const fd = new FormData();
fd.append('image',postImg)
fd.append('title', title)
fd.append('body',body)
props.onCreatePost(fd);

Then use header as explained by @gbalduzzi

SaachiTech
  • 1,849
  • 1
  • 10
  • 21