1

I was hoping to get a clearer understand where I may be going wrong. Sorry if I ask a lot of questions since I feel a bit lost and been stuck for about a week on this one.

Currently, I've changed the package I was using for linking with apollo-client. The previous package was apollo-link-http and now I'm using apollo-absinthe-upload-link since I read it allows for image upload.

It's done as follows

const httpLink = createLink({
    uri: 'http://localhost:4000/api',
    credentials: 'same-origin',
    fetch,
    fetchOptions
});

There wasn't any change to sending information to the backend but I do continue to be lost in regards to uploading an image. The purpose of this image is to upload to the cloud then save the url information with the product details.

I'm using a hook as const [ images, setImages ] = useState([]); and an input of <input type="file" placeholder="Upload Image" onChange={handleUploadImage} />

The purpose of the onChange function is to set the image information to the images property. When we send the mutation to the backend, the way it's done is as follows

const buildForm = () => {
    let storeID = 2;
    const fileData = fileList.fileList.map((file) => {
        return file.originFileObj;
    });
    const data = new FormData();
    data.append('fileData', images);
    debugger;
    return {
        productName,
        productDescription,
        productPrice,
        productType,
        isReturnable,
        storeID,
        fileData: data
    };
};

when it goes, within my console I'm getting an error of Uncaught (in promise) Error: GraphQL error: Argument "fileData" has invalid value $fileData. and I'm seeing on the backend the key fileData having an empty object as its value. I was hoping to get some advice on what might be wrong or what I should consider. If someone mentioned CURL please explain since I have no idea what that means in regards to GraphQL and sending a mutation. Thank you for the help on this matter.

P.S - The mutation call that is being used is

export const CREATE_PRODUCT_MUTATION = gql`
    mutation CreateProduct(
        $storeID: Int!
        $productName: String!
        $productDescription: String!
        $productPrice: Decimal!
        $productType: Int!
        $isReturnable: Boolean!
        $fileData: Upload!
    ) {
        createProduct(
            product: {
                productName: $productName
                productDescription: $productDescription
                productPrice: $productPrice
                productType: $productType
                isReturnable: $isReturnable
            }
            storeId: $storeID
            fileData: $fileData
        ) {
            id
            productName
            productDescription
            productPrice
        }
    }
`;

UPDATE - Network return request

{"errors":[{"locations":[{"column":0,"line":2}],"message":"Argument \"fileData\" has invalid value $fileData."}]}

Backend Schema

@desc "List a new product"
field :create_product, :product do
  arg(:product, :new_product)
  arg(:store_id, :integer)
  arg(:file_data, non_null(:upload))
Yama
  • 401
  • 1
  • 8
  • 22
  • That sounds like a type mismatch between the argument and the variable. I'm guessing the variable should be `[Upload!]!` not `Upload!` if you are sending multiple files. I'm not familiar with the Elixir implementation, but that doesn't seem like the complete error message. I would expect some kind of messaging along the lines of "expected x but received y" -- maybe you can check the actual response from the server in dev tools for the complete message. – Daniel Rearden Dec 16 '19 at 06:27
  • *someone mentioned CURL please explain since I have no idea what that means*--Normally, to send a request to a server you fill out a form on a web page and hit submit, then all the name/value pairs for the form are sent to the server. Well, what if you want to test how the server responds without having to create a web page with a form on it? There happens to be a program called CURL that allows you to send name/value pairs to the server. CURL will package the name/value pairs just like a form does on a web page, and the server will have no idea that the request is not from a form. – 7stud Dec 16 '19 at 14:12
  • ...CURL is known as an *http client*, i.e. a piece of software that can send name/value pairs in the proper format to a server. An example of an elixir http client is [httpoison](https://github.com/edgurgel/httpoison). – 7stud Dec 16 '19 at 14:19
  • @DanielRearden The return error I'm getting when checking network is `{"errors":[{"locations":[{"column":0,"line":2}],"message":"Argument \"fileData\" has invalid value $files."}]}` which is the same I'm seeing within console. I'm still not sure exactly what I might be missing to make it work. The Elixir implementation I believe is the same where we declare the field name and what arguments we will expect. I've added it to the bottom of the question. Thank you again for replying/helping. – Yama Dec 17 '19 at 01:09
  • @7stud Thank you so much for that explanation. I got told in other places about it and saw an example online but it didn't help me to better understand what it was and how it might be implemented. But from my understanding from your explanation, it's basically similar to using Postman but internally through the terminal and watch the type of response we might get. Interesting. – Yama Dec 17 '19 at 01:10
  • @StevenOssorio the error mentions a variable named `$files` but I do not see any variable with that name declared in the query you copy and pasted. – Daniel Rearden Dec 17 '19 at 01:25
  • @DanielRearden I'm sorry for the confusion. I mad a small change which resulted in that incorrect error from network. I added in the bottom of the post the network response that was fileData and what my schema looks like on the backend as well. Sorry again for that confusion. – Yama Dec 17 '19 at 01:46
  • *[curl is] basically similar to using Postman but internally through the terminal*. Yep. The guys who created the unix operating system also added thousands of programs that can used at the command line, e.g. `ls`. See [here](http://mally.stanford.edu/~sr/computing/basic-unix.html) for more. You can also download thousands of command line programs if your computer didn't come with them pre-installed, e.g. [wget](https://www.gnu.org/software/wget/). To use a unix command, like curl, the first step is to try `$ man curl` to launch the *manual page* for the command. – 7stud Dec 17 '19 at 17:19
  • ...However, often times the man pages are very confusing because they are so detailed and there are so many command line flags you can use with the command, so to get help you can search google for a basic tutorial on how to use the command, e.g. [curl tutorial](https://www.freecodecamp.org/news/how-to-start-using-curl-and-why-a-hands-on-introduction-ea1c913caaaa/) – 7stud Dec 17 '19 at 19:01

1 Answers1

1

apollo-absinthe-upload-link expects a variable of type File or Blob (see here), but you are passing fileData as type FormData.

Since your input type is file, you could do:

const handleUploadImage = (event) => setImages(event.target.files);

const buildForm = () => ({
  productName,
  productDescription,
  productPrice,
  productType,
  isReturnable,
  storeID: 2,
  fileData: images[0],
});

References:

file-selector

react-dropzone

rscheff
  • 21
  • 1
  • 2