I want to upload file to mongodb databse with Apollo mutation. Here's some of my config: server.js(here's on port 4000):
...
// Connect to Mongo
mongoose
.connect(process.env.mongoURI, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
useFindAndModify: false
}) // Adding new mongo url parser
.then(() => console.log('MongoDB Connected...'))
.catch(err => console.log(err));
const { ApolloServer } = require('apollo-server-express');
const typeDefs = require('./modules/graphqlschemas/index');
const resolvers = require('./modules/resolvers/index');
// #5 Initialize an Apollo server
const server = new ApolloServer({
typeDefs: typeDefs,
resolvers: resolvers,
context: ({ req }) => ({
getUser: () => req.user,
logout: () => {
req.session = null;
req.logout();
return true
}
})
});
...
Now my schemas and resolvers:
graphqlschemas/image.js
module.exports = `
type File {
_id: ID!
path: String!
filename: String!
mimetype: String!
encoding: String!
},
type Query {
uploads: [File]
},
type Mutation {
singleUpload(file: Upload!): File!
}
`;
resolvers/image.js( and here very important thing I've observed, file is always null there)
const Image = require('../../models/image');
module.exports = {
Query: {
uploads: (parent, args) => Image.find({}),
},
Mutation: {
singleUpload: async (parent, {file}) => {
console.log(file); // always null
}
}
}
, but let's go further to client( React app on port 3000):
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { ApolloProvider } from '@apollo/react-hooks';
import ApolloClient from "apollo-boost";
import { InMemoryCache } from 'apollo-cache-inmemory';
import { createUploadLink } from 'apollo-upload-client';
import { onError } from "apollo-link-error";
import { ApolloLink } from "apollo-link";
// const link = createUploadLink({ uri: '/graphql' });
const client = new ApolloClient({
link: ApolloLink.from([
// Report errors to console in a user friendly format
onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
)
);
if (networkError) console.log(`[Network error]: ${networkError}`);
}),
createUploadLink({
uri: '/graphql'
})
]),
cache: new InMemoryCache()
});
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root')
);
serviceWorker.unregister();
mutation query( I am using codgen to generate graphql hooks):
mutation SingleUpload($file: Upload!) {
singleUpload(file: $file) {
_id
filename
}
}
And file uploading with component(most important lines):
const [fileData, setFileData] = useState(null);
const [singleUpload] = useSingleUploadMutation();
const onChangeFile = e => {
setFileData(e.target.files[0]);
};
console.log(fileData);
const onChangeText = e => {
setNewsData({
...newsData,
[e.target.name]: e.target.value
});
}
const onSubmit = async e => {
e.preventDefault();
await singleUpload({ variables: { file: fileData } });
}
return (
<form id="addNews" onSubmit={onSubmit}>
<div className="form-group">
<input id="news" type="file" name="news" placeholder="Add photo" onChange={onChangeFile} />
</div>
<div className="form-group mt-4 mb-0">
<input type="submit" className="btn btn-primary btn-block" value="Add photo"/>
</div>
</form>
)
,but in resolver is equal null, so maybe that is the problem?
variables
.await singleUpload({ variables: { file: fileData } });
. I think an easy debugging check would be to slightly change your resolver to not destructure the argument and log that out.singleUpload: async (parent, logThisArg) => {
– ChrisG