如何将图像上传到 KeystoneJS GraphQL 端点?

Posted

技术标签:

【中文标题】如何将图像上传到 KeystoneJS GraphQL 端点?【英文标题】:How can one upload an image to a KeystoneJS GraphQL endpoint? 【发布时间】: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

【问题讨论】:

【参考方案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 个依赖 :)

【讨论】:

以上是关于如何将图像上传到 KeystoneJS GraphQL 端点?的主要内容,如果未能解决你的问题,请参考以下文章

如何将图片从 TinyMCE 上传到 Apollo GraphQL 服务器?

Microsoft Graph API - 如何将附件上传到列表项

如何使用 iPhone 中的 Graph API 在 Facebook 上上传照片?

护照后如何使用承诺登录。通过社会服务进行身份验证。 KeystoneJS + 护照

将照片上传到 facebook 群组 Graph API

如何发送 Microsoft Graph 上传会话的最终字节?