What is the right way of uploading images in PUT request

Viewed 58

I am trying to update a user profile by making a PUT request to an endpoint that accepts both text and file. Using axios, when I set the "Content-type": "multipart/form-data" text fields are not updated and image in also not uploaded but setting this "Content-type": "application/json", updates all text fields but throws validation error for image.

My script code looks like this

<script setup>
import { ref } from "vue";
import { useRouter } from "vue-router";
import http from "../http-common";

const router = useRouter();
const file = ref(null);
const form = ref({
  first_name: profile.userProfile.first_name,
  last_name: profile.userProfile.last_name,
});

function handleImage() {
  form.value.photo = file.value.files[0];
}

const updateProfile = async () => {
  try {
    const res = await http.put("user/profile", form.value, {
      headers: {
        Accept: "application/json",
        "Content-type": "multipart/form-data",
      },
    });

    if (form.value.photo) {
      console.log("image upload pending");
    }

    if (res.data.success) {
      alert(res.data.message);
    }

    router.push("/profile");
  } catch (error) {
    console.log(error);
  }
};
</script>

This is the form

<form
  class="space-y-8 divide-y divide-hrgray"
  enctype="form.data"
  @submit.prevent="submit"
>

        <div
            class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-center sm:border-t sm:border-hrgray sm:pt-5"
        >
            <label
            for="photo"
            class="block text-sm font-medium text-gray-700"
            >
            Photo
            </label>
            <div class="mt-1 sm:mt-0 sm:col-span-2">
                <div class="flex items-center">
                    <input
                    ref="file"
                    v-on:change="handleImage"
                    type="file"
                    />
                </div>
            </div>
        </div>
    </div>

    <div class="pt-8 space-y-6 sm:pt-10 sm:space-y-5">
        
        <div
            class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-hrgray sm:pt-5"
        >
            <label
            for="first-name"
            class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"
            >
            First name
            </label>
            <div class="mt-1 sm:mt-0 sm:col-span-2">
            <input
                type="text"
                v-model="form.first_name"
                name="first-name"
                id="first-name"
                autocomplete="given-name"
                class="max-w-lg block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md"
            />
            </div>
        </div>

        <div
            class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-hrgray sm:pt-5"
        >
            <label
            for="last-name"
            class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2"
            >
            Last name
            </label>
            <div class="mt-1 sm:mt-0 sm:col-span-2">
            <input
                type="text"
                v-model="form.last_name"
                name="last-name"
                id="last-name"
                autocomplete="family-name"
                class="max-w-lg block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md"
            />
            </div>
        </div>
    </div>

    <div class="pt-5 pb-10">
        <div class="flex justify-end">
            <button
            type="submit"
            @click="updateProfile()"
            class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-book hover:bg-blue focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
            >
            Save
            </button>
        </div>
    </div>
</form>

What is the right way to pass the image and text in the API PUT request?

1 Answers

Use a form data object and append your picture which is chosen from the input.

const payload = new FormData();

payload.append('name', firstName.value);
payload.append('file', file.value); // v-model file to the input[type=file] element

const res = await http.put("user/profile", payload, {
  headers: {
    Accept: "application/json",
    "Content-type": "multipart/form-data",
  },
});
Related