This is not about "client to server" upload.
I am looking for a way to upload a file from nodejs server to rails backend graphql server (server to server).
The rails backend is working fine, and it can take file uploads without a problem if it was from a client.
The problem I am having is to create/build a "File" object in nodejs, so that I can use an Apollo mutation like this to upload the file.
// 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?
},
}
})
If it was the client side, it's very simple.
<input type="file" onchange={(event) => {
const file = event.target.files[0] // this can be the "file" object
}}/>
Is it possible to create an equivalent file object as the client side File object in nodejs?
import fs from "fs"
// giving this "file" object to the mutation doen't upload the file
const file = fs.createReadStream("./local/file/path.jpg")
Things I tried
- created a new rails graphql backend with apollo_upload_server
- created a new nextjs
- posting a file working on the server-end (Altair GraphQL Client)
- I see the file as
<ActionDispatch::Http::UploadedFile:0x00007f9e1ac0e8a0 @tempfile=#<Tempfile:/tmp/RackMultipart20211020-14-156qwls.jpg ...
- I see the file as
- created a Blob object, but I get this error
Variable $input of type TestMutationInput! was provided invalid value for file ({} is not a valid upload)
on the front-end
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()
}
I nailed it.
https://github.com/jaydenseric/apollo-upload-client/issues/272