使用 nexus-prisma graphql 处理文件上传

Posted

技术标签:

【中文标题】使用 nexus-prisma graphql 处理文件上传【英文标题】:Handling file upload with nexus-prisma graphql 【发布时间】:2020-09-06 16:04:14 【问题描述】:

我正在尝试将文件从我的前端应用上传到我的服务器 但我不断收到这个奇怪的错误,不知道为什么会这样。

错误是前端:

Variable "$file" got invalid value ; Expected type Upload. Upload value invalid.

后端出错:

GraphQLError: Upload value invalid.
at GraphQLScalarType.parseValue (/app/backend/node_modules/graphql-upload/lib/GraphQLUpload.js:66:11)

这就是我添加上传标量的方式


// scalars/upload.ts
import  scalarType  from "nexus/dist";
import  GraphQLUpload  from "graphql-upload";

export const Upload = scalarType(
  name: "Upload",
  asNexusMethod: "upload", // We set this to be used as a method later as `t.upload()` if needed
  description: GraphQLUpload.description,
  serialize: GraphQLUpload.serialize,
  parseValue: GraphQLUpload.parseValue,
  parseLiteral: GraphQLUpload.parseLiteral,
);

export default Upload;

// scalar/index.ts
export  default as Upload  from "./Upload";

// index.ts
import * as allTypes from "./resolvers";
import * as scalars from "./scalars";
const schema = makePrismaSchema(
  types: [scalars, allTypes],
  prisma: 
    datamodelInfo,
    client: prisma,
  ,
...

// my mutation 
t.string("uploadFile", 
  args: 
    file: arg( type: "Upload", nullable: false ),
  ,
  resolve: async (_: any,  file ,   : any) => 
    console.log(file);
    return "ok";
  ,
);

这就是我在我的 React/NextJS 应用程序中制作 uplaod 客户端的方式

// the link
const link = () => 
  return createUploadLink(
    uri: process.env.backend,
    credentials: "include",
    fetch,
  );
;

// the mutation ( I use graphql codegen )

mutation TestUpload($file: Upload!) 
  uploadFile(file: $file)


const [upload] = useTestUploadMutation();

<input
  type="file"
  onChange=(e) => 
    const  files, validity  = e.target;
    if (validity.valid && files && files[0]) 
      upload(
        variables: 
          file: files[0],
        ,
      );
    
  
/>

即使尝试使用我的前端应用程序以外的其他东西运行突变,我也会遇到同样的错误,所以我猜问题出在我的后端设置上,即使我搜索了很多方法来做到这一点,但似乎没有一个工作。

【问题讨论】:

【参考方案1】:

我刚刚遇到了完全相同的问题。这解决了它。所以基本上手动定义上传而不是使用 GraphQLUpload

import  objectType, scalarType  from "@nexus/schema";
import  GraphQLError  from "graphql";
import * as FileType from "file-type";

export const Upload = scalarType(
  name: "Upload",
  asNexusMethod: "upload", // We set this to be used as a method later as `t.upload()` if needed
  description: "desc",
  serialize: () => 
    throw new GraphQLError("Upload serialization unsupported.");
  ,
  parseValue: async (value) => 
    const upload = await value;
    const stream = upload.createReadStream();
    const fileType = await FileType.fromStream(stream);

    if (fileType?.mime !== upload.mimetype)
      throw new GraphQLError("Mime type does not match file content.");

    return upload;
  ,
  parseLiteral: (ast) => 
    throw new GraphQLError("Upload literal unsupported.", ast);
  ,
);

export const File = objectType(
  name: "File",
  definition(t) 
    t.id("id");
    t.string("path");
    t.string("filename");
    t.string("mimetype");
    t.string("encoding");
  ,
);

【讨论】:

以上是关于使用 nexus-prisma graphql 处理文件上传的主要内容,如果未能解决你的问题,请参考以下文章

Nexus-prisma:排序嵌套连接

如何使用 prisma 2 或 3 和 nexus 模式生成同时生成生成的 crud 和“ondelete 级联”

如何为 REST 和 GraphQL 使用相同的 RoleGuard?

GraphQL 或 REST [关闭]

从 React 向 GraphQL 服务器进行查询时出现意外错误 [重复]

SyntaxError:在 Graphiql 中测试时,JSON 中位置 0 处出现意外标记 <