【发布时间】:2021-12-06 04:27:37
【问题描述】:
这与“客户端到服务器”上传无关。
我正在寻找一种将文件从 nodejs 服务器上传到 rails 后端 graphql 服务器(服务器到服务器)的方法。
rails 后端工作正常,如果来自客户端,它可以毫无问题地上传文件。
我遇到的问题是在 nodejs 中创建/构建一个"File" object,这样我就可以使用这样的 Apollo 突变来上传文件。
// nodejs server side, NOT react client side
const { data } = await client.mutate<
FileUploadMutation,
FileUploadMutationVariables
>({
mutation: FileUploadDocument,
variables: {
input: {
file: file // how do I create this file object from a local file?
},
}
})
如果是客户端,那就很简单了。
<input type="file" onchange={(event) => {
const file = event.target.files[0] // this can be the "file" object
}}/>
是否可以在nodejs中创建一个与the client side File object等效的文件对象?
import fs from "fs"
// giving this "file" object to the mutation doen't upload the file
const file = fs.createReadStream("./local/file/path.jpg")
我尝试过的事情
- 使用apollo_upload_server 创建了一个新的rails graphql 后端
- 创建了一个新的 nextjs
-
posting a file working 在服务器端 (Altair GraphQL Client)
- 我看到的文件是
<ActionDispatch::Http::UploadedFile:0x00007f9e1ac0e8a0 @tempfile=#<Tempfile:/tmp/RackMultipart20211020-14-156qwls.jpg ...
- 我看到的文件是
- 创建了一个 Blob 对象,但我在前端收到此错误
Variable $input of type TestMutationInput! was provided invalid value for file ({} is not a valid upload)
package.json
{
"scripts": {
"dev": "next",
"generate": "graphql-codegen -w --config codegen.yml"
},
"dependencies": {
"@apollo/client": "^3.4.16",
"apollo-upload-client": "^16.0.0",
"graphql": "^15.6.1",
"next": "^11.1.2",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@graphql-codegen/cli": "^2.2.1",
"@graphql-codegen/typescript": "^2.2.4",
"@graphql-codegen/typescript-operations": "^2.1.8",
"@graphql-codegen/typescript-react-apollo": "^3.1.6",
"@types/apollo-upload-client": "^14.1.0",
"@types/react": "^17.0.30",
"typescript": "^4.4.4"
}
}
(nextjs)/api/test.ts (nodejs)
import { ApolloClient, InMemoryCache } from "@apollo/client"
import { createUploadLink } from "apollo-upload-client"
import { Blob } from "buffer"
import type { NextApiRequest, NextApiResponse } from "next"
// import { Blob } from "node:buffer"
import * as Generated from "src/generated/graphql"
const client = new ApolloClient({
cache: new InMemoryCache(),
link: createUploadLink({
uri: "http://backend:3000/graphql",
}),
})
// checking if the apollo connection is good at all ------------
client
.query<Generated.TestFieldQuery, Generated.TestFieldQueryVariables>({
query: Generated.TestFieldDocument,
variables: {},
})
.then(({ data }) => {
// this actually returns data
console.log("data:", data)
})
// checking if the apollo connection is good at all ------------
export default async (req: NextApiRequest, res: NextApiResponse) => {
// const buffer = fs.readFileSync(fs.realpathSync("./test.jpg"))
// const file = new Blob([buffer], { type: "image/jpg" })
const file = new Blob(["abc123"], { type: "text/plain" })
console.log("file:", file)
// this mutation gives me this error
// graphQLErrors: [
// {
// message: 'Variable $input of type TestMutationInput! was provided invalid value for file ({} is not a valid upload)',
// locations: [Array],
// extensions: [Object]
// }
// ],
await client.mutate<
Generated.TestMutationMutation,
Generated.TestMutationMutationVariables
>({
mutation: Generated.TestMutationDocument,
variables: {
input: {
file,
},
},
fetchPolicy: "no-cache",
})
res.status(200).end()
}
【问题讨论】:
-
GraphQL 不支持文件上传,甚至 Apollo 也没有提供开箱即用的 this。 Rails 后端期望文件采用什么格式?如果你在浏览器中,你会如何处理
file? -
"这与“客户端到服务器”上传无关。" - 当然,就像所有 HTTP 一样,只是您有一个 node.js 客户端而不是浏览器客户。这就是您仍在使用 Apollo client 库的原因。
-
事实上,我在客户端使用的是 jaydenseric/apollo-upload-client v12.1.0。所以就像我说的,rails 后端可以正常接收文件上传。
-
"client" 我的意思更像是“浏览器”。没有冒犯,但是,是的,我使用的是 Apollo 客户端,所以如果你从字面上理解它是“客户端到服务器”。但我更喜欢关注如何在nodejs中创建一个像客户端(浏览器)一样的“文件对象”。
-
啊,所以 rails 服务器希望根据 Apollo 规范进行分段上传?你可以手工制作。另外,你见过github.com/jaydenseric/apollo-upload-client/issues/134、github.com/jaydenseric/apollo-upload-client/issues/32和github.com/jaydenseric/apollo-upload-client/issues/129吗?
标签: node.js graphql next.js apollo-client apollo-upload-client