Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upload a PDF file #83

Closed
Tes3awy opened this issue Aug 30, 2019 · 13 comments · Fixed by #143
Closed

Upload a PDF file #83

Tes3awy opened this issue Aug 30, 2019 · 13 comments · Fixed by #143
Labels
enhancement New feature or request released

Comments

@Tes3awy
Copy link

Tes3awy commented Aug 30, 2019

Hello there,

I am trying to use this awesome plugin to upload a PDF file. I have created a model for this:

import Model from './Model';

export default class JobApplication extends Model {
  resource() {
    return 'v2/job_applications';
  }
}

Then, I call the model within the .vue file like that:

...
 import JobApplication from "./../models/JobApplication";
...
async onSubmit() {
  let job = new JobApplication({
    first_name,
    last_name,
    email,
    mobile_phone,
    resume: this.$refs.resume.files[0]
  });
  await job
    .save()
    .then(response => {
      console.log(response);
    })
    .catch(error => {
      console.error(error.response);
    });
}
...

The problem is that the POST request fails every time I try to submit the form because of the resume field. What am I doing wrong in here? Do I have to do any extra steps? Thank you

@lukecurtis93
Copy link

Haven't personally tried this but have you attempted to set the headers to be 'Content-Type': 'multipart/form-data' on the constructor for the models default http method?

@Tes3awy
Copy link
Author

Tes3awy commented Sep 21, 2019

Hello @lukecurtis93

Actually I haven't because I don't know-how. Can you help me with this, please?

This is the Model.js file

import { Model as BaseModel } from 'vue-api-query';

export default class Model extends BaseModel {
  // define a base url for a REST API
  baseURL() {
    return '/api';
  }

  // implement a default request method
  request(config) {
    return this.$http.request(config);
  }
  parameterNames() {
    return Object.assign(super.parameterNames(), {
      page: 'page[number]',
      limit: 'page[size]'
    });
  }
}

And the JobApplicaton.js model

import Model from './Model';

export default class JobApplication extends Model {
  resource() {
    return 'v2/job_applications';
  }
}

@Peter-Krebs
Copy link
Collaborator

+1 if someone can provide a vue-api-query answer for file uploads.

I got around that using FormData objects directly.
The vue-api-query models were still useful for giving the endpoint URL. For example if you have a forum post with a dedicated upload endpoint:

  let post = new Post(this.post);
  let uploadUrl = post.endpoint() + "/" + new PostDocument().resource();

@abishekrsrikaanth
Copy link

Did not know there was a method endpoint() to get that. What does the resource() method do?

@Peter-Krebs
Copy link
Collaborator

Peter-Krebs commented Oct 14, 2019

Yes, I saw endpoint() in the base model and borrowed the call from there.

resource() is the resource name that you set for each model.
See Define your domain models from the readme.

@Peter-Krebs
Copy link
Collaborator

@Tes3awy Have the tips provided helped you to find a solution?

Is there still a need for a pure vue-api-query approach to this? I would like one, but if there is currently no need and no PR exists we should close this for now.

@Tes3awy
Copy link
Author

Tes3awy commented Nov 8, 2019

@Peter-Krebs I didn't get to find a solution that uses vue-api-query for my issue. I don't know why you closed the issue. My problem is not solved yet. Can you please suggest a solution that uses vue-api-query? Thank you

@Peter-Krebs
Copy link
Collaborator

I don't have a solution for you except the approach mentioned above, sorry. There was no activity for over 3 weeks so I assumed the demand was dead.
It's reopened so others can chip in ideas.

@Peter-Krebs Peter-Krebs reopened this Nov 8, 2019
@robsontenorio
Copy link
Owner

robsontenorio commented Nov 8, 2019 via email

@Peter-Krebs Peter-Krebs added the enhancement New feature or request label Nov 20, 2019
@alvaro-canepa
Copy link

Hi, I have a small solution to this issue using object-to-formdata library.
The request method check for File type on all config.data items (not recursive), if detects for a File item, just convert data using objectToFormData() function.

// src/models/Model.js
import { Model as BaseModel } from "vue-api-query";
import objectToFormData from "object-to-formdata";
import { _ } from "vue-underscore";

export default class Model extends BaseModel {
  baseURL() {
    return "";
  }

  async request(config) {
    if (config.method == "PUT") {
      config.method = "POST";
      config.data._method = "PUT";
    }

    const hasUpload = !_.chain(_.values(config.data))
      .filter((value) => {
        return value instanceof File;
      })
      .isEmpty()
      .value();

    if (hasUpload) {
      config.data = objectToFormData(config.data, { indices: true });
    }

    return await this.$http.request(config);
  }
}

JoaoPedroAS51 added a commit that referenced this issue Nov 10, 2020
Add support to upload files by checking if data has instance of `File`. If so, it set the `Content-Type` to `multipart/form-data` and convert the data object to `FormData` using `object-to-formdata`.

Based on comment by @alvaro-canepa at #83
@github-actions
Copy link

🎉 This issue has been resolved in version 1.8.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@JoaoPedroAS51
Copy link
Collaborator

@alvaro-canepa Now you can simplify your model :)

// src/models/Model.js
import { Model as BaseModel } from "vue-api-query";
import objectToFormData from "object-to-formdata";
import { _ } from "vue-underscore";

export default class Model extends BaseModel {
  baseURL() {
    return "";
  }

  async request(config) {
    if (config.method == "PUT") {
      config.method = "POST";
      config.data._method = "PUT";
    }

    return await this.$http.request(config);
  }

  formData() {
    return { indices: true };
  }
}

@ajcastro
Copy link

This what works for me better :

/* eslint-disable no-underscore-dangle */
/* eslint-disable no-param-reassign */
/* eslint-disable class-methods-use-this */
import { Model as BaseModel } from 'vue-api-query'
import env from '@env'

export default class Model extends BaseModel {
  // Define a base url for a REST API
  baseURL() {
    return `${env.baseURL}/api/admin`
  }

  // Implement a default request method
  request(config) {
    const isFormData = config.data instanceof FormData

    if (isFormData && config.method === 'PUT') {
      config.method = 'POST'
      config.data.append('_method', 'PUT')
    }

    return this.$http.request(config)
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request released
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants