【问题标题】:How can one upload an image to a KeystoneJS GraphQL endpoint?如何将图像上传到 KeystoneJS GraphQL 端点?
【发布时间】:2020-06-24 15:48:51
【问题描述】:

我在 KeystoneJS AdminUI 的自定义字段中使用 TinyMCE,这是一个 React 应用程序。我想将 React 前端的图像上传到 KeystoneJS GraphQL 后端。我可以使用添加到 Keystone 服务器的 REST 端点上传图像——向 TinyMCE 传递一个images_upload_handler 回调——但我想利用 Keystone 已经构建的 GraphQL 端点来获取图像列表/类型创建的。

我首先尝试使用this article中详述的方法,使用axios上传图片

const getGQL = (theFile) => {
    const query = gql`
  mutation upload($file: Upload!) {
    createImage(file: $file) {
      id
      file {
        path
        filename
      }
    }
  }
`;
// The operation contains the mutation itself as "query"
    // and the variables that are associated with the arguments
    // The file variable is null because we can only pass text
    // in operation variables
    const operation = {
        query,
        variables: {
            file: null
        }
    };
    // This map is used to associate the file saved in the body
    // of the request under "0" with the operation variable "variables.file"
    const map = {
        '0': ['variables.file']
    };

    // This is the body of the request
    // the FormData constructor builds a multipart/form-data request body
    // Here we add the operation, map, and file to upload
    const body = new FormData();
    body.append('operations', JSON.stringify(operation));
    body.append('map', JSON.stringify(map));
    body.append('0', theFile);

    // Create the options of our POST request
    const opts = {
        method: 'post',
        url: 'http://localhost:4545/admin/api',
        body
    };
// @ts-ignore
    return axios(opts);

};

但我不确定要传递什么 theFile -- TinyMCE 的 images_upload_handler,我需要从中调用图像上传,接受一个 blobInfo 对象,其中包含给我的功能

文件名不起作用,blob 也不起作用——两者都给我服务器错误 500——错误消息没有更具体。

我更喜欢使用 GraphQL 客户端来上传图片——another SO article 建议使用apollo-upload-client。但是,我在 KeystoneJS 环境中操作,Apollo-upload-client 说

Apollo 客户端只能有 1 个“终止”Apollo Link 发送 GraphQL 请求;如果已经设置了诸如 apollo-link-http 之类的, 删除它。

我相信 Keystone 已经设置了Apollo-link-http(它在搜索中多次出现),所以我认为我不能使用Apollo-upload-client

【问题讨论】:

    标签: node.js graphql apollo-client apollo-server keystonejs


    【解决方案1】:

    UploadLink 只是 HttpLink 的替代品。你没有理由不能使用它。有一个演示 KeystoneJS 应用程序 here,它显示了 Apollo 客户端配置,包括使用 createUploadLink

    带有Upload 标量的突变的实际用法显示为here

    查看source code,您应该能够使用自定义image handler 并在提供的blobInfo 对象上调用blob。像这样的:

    tinymce.init({
      images_upload_handler: async function (blobInfo, success, failure) {
        const image = blobInfo.blob()
        try {
          await apolloClient.mutate(
            gql` mutation($image: Upload!) { ... } `,
            {
              variables: { image }
            } 
          )
          success()
        } catch (e) {
          failure(e)
        }
      }
    })
    

    【讨论】:

    • 我是 GraphQL 的相对新手——当你说“直接替换”时,我具体用 UploadLink 做什么?他们的文档说要删除已设置的任何其他“终止链接”。我真的需要这样做吗?在 Keystone 的背景下,如何? - 此外,您链接的示例非常有帮助,但由于我在受限上下文中操作,我只提供文件名、blob 等内容(如上所述),我如何使用它来到达示例正在使用的 File 对象(从表单中获取)?
    • 通常,您使用 HttpLink like this。您无需创建 HttpLink,而是创建 UploadLink,如 here 所示。
    • 我会仔细研究所有内容。我的一个问题是,当我在 AdminUI 中工作时,是否会发生任何变化?也就是说,看演示——github.com/keystonejs/keystone/blob/…——它似乎是从头开始设置 Apollo 客户端,但在 AdminUI 中已经完成了所有工作。我应该再做一次,即设置我自己的“本地”Apollo 客户端吗?还是我误会了什么?
    • @DanielRearden 结果怎么样 - blob 不应该被替换为从突变返回的远程 url 生成的新的?
    • 我对 KeystoneJS 不是很熟悉,但它看起来像管理应用程序already uses createUploadLink
    【解决方案2】:

    我以前也有同样的问题,用 Apollo 上传链接解决了。现在,当应用程序进入生产阶段时,我意识到 Apollo 客户端占用了 1/3 的 gzip 压缩构建文件,我创建了最小的 graphql 客户端,仅用于自动上传图像的 keystone。该软件包在 npm 中可用:https://www.npmjs.com/package/@sylchi/keystone-graphql-client

    如果有用户将头像字段设置为文件,则将 github 徽标上传到用户配置文件的使用示例:

    import {  mutate } from  '@sylchi/keystone-graphql-client'
    
    const  getFile  = () =>  fetch('https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png',
    {
        mode:  "cors",
        cache:  "no-cache"
    })
    .then(response  =>  response.blob())
    .then(blob  => {
        return  new  File([blob], "file.png", { type:  "image/png" })
    });
    
    getFile().then(file  => {
    
    const  options  = {
        mutation: `
            mutation($id: ID!, $data: UserUpdateInput!){
                updateUser(id: $id, data: $data){
                    id
                }
            }
        `,
        variables: {
            id:  "5f5a7f712a64d9db72b30602", //replace with user id
            data: {
                avatar:  file
            }
        }
    }
    
    mutate(options).then(result  =>  console.log(result));
    
    });
    

    整个包只有 50loc 和 1 个依赖 :)

    【讨论】:

      猜你喜欢
      • 2018-02-21
      • 2018-01-19
      • 2022-06-20
      • 2017-06-22
      • 2020-09-01
      • 2019-11-23
      • 1970-01-01
      • 2019-11-29
      • 2021-05-04
      相关资源
      最近更新 更多