【问题标题】:Allowing a multipart (image) upload through GraphQL for Elixir backend允许通过 GraphQL 为 Elixir 后端上传多部分(图像)
【发布时间】:2020-04-08 12:57:42
【问题描述】:

我希望能更清楚地了解我可能出错的地方。对不起,如果我问了很多问题,因为我感到有点失落并且在这个问题上被困了大约一周。

目前,我已经更改了用于链接 apollo-client 的包。以前的包是apollo-link-http,现在我使用apollo-absinthe-upload-link,因为我读到它允许上传图片。

如下进行

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

向后端发送信息没有任何变化,但在上传图片方面我仍然迷失方向。此图像的目的是上传到云端,然后将 url 信息与产品详细信息一起保存。

我使用一个钩子作为const [ images, setImages ] = useState([]); 和一个<input type="file" placeholder="Upload Image" onChange={handleUploadImage} /> 的输入

onChange 函数的目的是将图像信息设置到 images 属性。当我们将突变发送到后端时,它的完成方式如下

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
    };
};

当它运行时,在我的控制台中我收到一个错误 Uncaught (in promise) Error: GraphQL error: Argument "fileData" has invalid value $fileData. 并且我在后端看到键 fileData 有一个空对象作为它的值。我希望就可能出现的问题或我应该考虑的问题获得一些建议。如果有人提到 CURL,请解释一下,因为我不知道这对于 GraphQL 和发送突变意味着什么。感谢您对此事的帮助。

P.S - 正在使用的突变调用是

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
        }
    }
`;

更新 - 网络返回请求

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

后端架构

@desc "List a new product"
field :create_product, :product do
  arg(:product, :new_product)
  arg(:store_id, :integer)
  arg(:file_data, non_null(:upload))

【问题讨论】:

  • 这听起来像是参数和变量之间的类型不匹配。我猜如果您要发送多个文件,变量应该是[Upload!]! 而不是Upload!。我不熟悉 Elixir 的实现,但这似乎不是完整的错误消息。我希望有一些类似于“预期 x 但收到 y”的消息——也许您可以在开发工具中检查来自服务器的实际响应以获取完整消息。
  • 有人提到 CURL,请解释一下,因为我不知道那是什么意思--通常,要向服务器发送请求,您需要在网页上填写表格并点击提交,然后将表单的所有名称/值对发送到服务器。好吧,如果您想测试服务器如何响应而不必创建带有表单的网页怎么办?碰巧有一个名为 CURL 的程序,它允许您将名称/值对发送到服务器。 CURL 会像网页上的表单一样打包名称/值对,服务器不会知道请求不是来自表单。
  • ...CURL 被称为 http 客户端,即可以将正确格式的名称/值对发送到服务器的软件。 elixir http 客户端的一个示例是httpoison
  • @DanielRearden 检查网络时遇到的返回错误是{"errors":[{"locations":[{"column":0,"line":2}],"message":"Argument \"fileData\" has invalid value $files."}]},这与我在控制台中看到的相同。我仍然不确定我可能缺少什么才能使其正常工作。我相信 Elixir 的实现与我们声明字段名称和我们期望的参数是相同的。我已将其添加到问题的底部。再次感谢您的回复/帮助。
  • @7stud 非常感谢您的解释。我在其他地方被告知并在网上看到了一个示例,但这并没有帮助我更好地理解它是什么以及如何实现它。但是根据我对您的解释的理解,它与使用 Postman 基本相似,但在内部通过终端并观察我们可能得到的响应类型。有趣。

标签: reactjs graphql elixir phoenix-framework absinthe


【解决方案1】:

apollo-absinthe-upload-link 需要FileBlob (see here) 类型的变量,但您将fileData 作为FormData 类型传递。

由于您的input 类型是file,您可以这样做:

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

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

参考资料:

file-selector

react-dropzone

【讨论】:

    猜你喜欢
    • 2020-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多