I am trying to create a custom resolver to upload an user's avatar image for an Express + Apollo Server + Mongoose project which is using composeWithMongoose.
User resolvers are being created with SchemaComposer
, which generates them from the Mongoose schema like:
User Model
import mongoose, { Schema } from 'mongoose';
import timestamps from 'mongoose-timestamp';
import bcrypt from 'mongoose-bcrypt';
import { composeWithMongoose } from 'graphql-compose-mongoose';
export const UserSchema = new Schema(
{
name: {
type: String,
trim: true,
required: true,
},
email: {
type: String,
lowercase: true,
trim: true,
unique: true,
},
phone: {
type: Number,
trim: true,
unique: true,
},
password: {
type: String,
bcrypt: true,
},
type: {
type: String,
},
image: {
type: String,
trim: true,
lowercase: true,
},
},
{
collection: 'users',
}
);
UserSchema.plugin(timestamps);
UserSchema.plugin(bcrypt);
UserSchema.index({ createdAt: 1, updatedAt: 1 });
export const User = mongoose.model('User', UserSchema);
export const UserTC = composeWithMongoose(User);
User Schema
import { User, UserTC } from '../models/user';
const UserQuery = {
userById: UserTC.getResolver('findById'),
userByIds: UserTC.getResolver('findByIds'),
userOne: UserTC.getResolver('findOne'),
userMany: UserTC.getResolver('findMany'),
userCount: UserTC.getResolver('count'),
userConnection: UserTC.getResolver('connection'),
userPagination: UserTC.getResolver('pagination'),
};
const UserMutation = {
userCreateOne: UserTC.getResolver('createOne'),
userCreateMany: UserTC.getResolver('createMany'),
userUpdateById: UserTC.getResolver('updateById'),
userUpdateOne: UserTC.getResolver('updateOne'),
userUpdateMany: UserTC.getResolver('updateMany'),
userRemoveById: UserTC.getResolver('removeById'),
userRemoveOne: UserTC.getResolver('removeOne'),
userRemoveMany: UserTC.getResolver('removeMany'),
};
export { UserQuery, UserMutation };
According to graphql-compose-mongoose documentation and what I understood I have to add the resolver to the ObjectTypeComposer
(UserTC
) using the method addResolver()
like:
User Schema
import { User, UserTC } from '../models/user';
import { GraphQLUpload } from 'graphql-upload';
UserTC.addResolver({
name: 'uploadImage',
type: 'String',
args: { userId: 'MongoID!', image: 'Upload!' },
resolve: async ({ source, args, context, info }) => {
const user = await User.findById({ _id: args.userId }).exec();
console.log(user);
}
});
const UserQuery = {
...
};
const UserMutation = {
...
uploadImage: UserTC.getResolver('uploadImage'),
};
export { UserQuery, UserMutation };
This was working until I changed the image
argument type from String
to Upload
. Where, according to Apollo documentation is enabled by default.
I get this error in console: Error: Type with name "Upload" does not exists
.
But I am not sure how to add to my own type definitions using composeWithMongoose()
in this case.
What would you do? Maybe using an entire different approach is completely valid. Any comments or suggestions will be appreciated.
Edit 1: In response to @Daniel Rearden
I am still getting Upload
type does not exists:
throw new Error(`Type with name ${(0, _misc.inspect)(typeName)} does not exists`); ^
Error: Type with name "Upload" does not exists
- I have installed:
express-graphql
andapollo-upload-server
. - I added the middlewares to the server configuration:
import dotenv from 'dotenv';
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import mongoose from 'mongoose';
import bodyParser from 'body-parser';
import { apolloUploadExpress } from 'apollo-upload-server';
import './utils/db';
import schema from './schema';
dotenv.config();
const app = express();
app.use(
bodyParser.json(),
apolloUploadExpress()
);
const server = new ApolloServer({
schema,
cors: true,
playground: process.env.NODE_ENV === 'development' ? true : false,
introspection: true,
tracing: true,
path: '/',
});
...
- I have provided the following code inside the Schema index:
import { SchemaComposer } from 'graphql-compose';
import { GraphQLUpload } from 'apollo-upload-server';
import db from '../utils/db'; //eslint-disable-line no-unused-vars
const schemaComposer = new SchemaComposer();
schemaComposer.add(GraphQLUpload);
...
And I am still getting the error: Error: Type with name "Upload" does not exists
.
Edit 2: Also, in response to @Daniel Rearden
Well, I just added the custom resolver to the UserMutation
schema and it worked:
const UserMutation = {
userCreateOne: UserTC.getResolver('createOne'),
userCreateMany: UserTC.getResolver('createMany'),
userUpdateById: UserTC.getResolver('updateById'),
userUpdateOne: UserTC.getResolver('updateOne'),
userUpdateMany: UserTC.getResolver('updateMany'),
userRemoveById: UserTC.getResolver('removeById'),
userRemoveOne: UserTC.getResolver('removeOne'),
userRemoveMany: UserTC.getResolver('removeMany'),
uploadImage: {
type: 'String',
args: {
userId: 'String!',
image: 'Upload'
},
resolve: async (_, { userId, image }) => {
const user = await User.findById({ _id: userId}).exec();
console.log(user);
},
}
};