0

I keep getting an unhandled promise rejection error from my server as soon as I add any code to a specific resolver of mine used to query and mutate data in MongoDB. The code for the resolver is as shown:

import { Coordinates, Fridge, Fridges } from '../models/Fridge';
import { Arg, Ctx, Field, InputType, Mutation, Resolver } from 'type-graphql';
import { MyContext } from '../types';
import { Users } from '../models/User';

@InputType()
class FridgeInput {
  @Field()
  name: string

  @Field()
  address: string

  @Field()
  description: string

  @Field(() => Coordinates)
  coordinates?: Coordinates
}

@Resolver()
export class FridgeResolver {
  @Mutation(() => Fridge)
  async createFridge (
    @Arg("inputs") inputs: FridgeInput,
    @Ctx() { req } : MyContext
  ): Promise<Fridge | undefined> {
      const author = Users.findOne({_id: req.session.userId});
      const {name, address, description, coordinates} = inputs;
  
      const fridge = new Fridges({
        name,
        address,
        description,
        author,
        coordinates: coordinates ? coordinates : undefined
      })
  
      try {
        await fridge.save()
      } catch (error) {
        console.log(error)
        return undefined
      } 
    
      return fridge
  }
}

I am trying to reference other classes in the Fridges class and wasn't sure if I was doing that right but I couldn't imagine how that would be the root of the problem. The code for this is here:

import { Field, ID, ObjectType } from "type-graphql";
import { prop, getModelForClass, Ref } from "@typegoose/typegoose";
import { User } from './User';

export class Coordinates {
  lat: number
  lng: number
}

@ObjectType()
export class Fridge {
  @Field(() => ID, {nullable: true})
  _id: string

  @Field() 
  @prop({required: true})
  name: string;

  @Field() 
  @prop({required: true})
  address: string;

  @Field() 
  @prop({required: true})
  description: string;

  @Field(() => User, {nullable: true}) 
  @prop({required: true, ref: User})
  public author: Ref<User>

  @Field(() => Coordinates, {nullable: true}) 
  @prop({required: true})
  cordinates?: Coordinates;
};

export const Fridges = getModelForClass(Fridge);

Lastly here is the code for my server:

***** As soon as I remove the FridgeResolver the error goes away. Also if I remove all the code within the FridgeResolver but leave it in the ApolloServer it also goes away. ********

import { ApolloServer } from "apollo-server-express";
import "colors";
import connectRedis from "connect-redis";
import cors from 'cors';
import express from "express";
import session from "express-session";
import Redis from "ioredis";
import mongoose from "mongoose";
import "reflect-metadata";
import { buildSchema } from "type-graphql";
import { COOKIE_NAME, __prod__ } from "./constants";
import { FridgeResolver } from './resolvers/fridge';
import { HelloResolver } from "./resolvers/hello";
import { UserResolver } from "./resolvers/user";

// create express instance:
const app = express();
// connect to our mongo database
const connectDB = async() => {
  try {
    const conn = await mongoose.connect('mongodb://localhost:27017/cff', {
      useNewUrlParser: true,
      useCreateIndex: true,
      useUnifiedTopology: true,
      useFindAndModify: false,
      autoIndex: true
    });
    console.log(`Mongo Connected to: ${conn.connection.host}`.cyan.bold)
  } catch (error) {
    console.log(`Error: ${error}`.red.bold);
    process.exit();
  }
};

connectDB();
const main = async () => {
  // Redis 
  const RedisStore = connectRedis(session);
  const redis = new Redis();
  // cors 
  app.use(cors({
    origin: 'http://localhost:3000',
    credentials: true,
  }));
  // Session middleware needs to come before apollo so we can use it inside apollo middleware
  app.use(
    session({
      name: COOKIE_NAME,
      store: new RedisStore({
        client: redis, 
        disableTouch: true,
      }),
      cookie: {
        maxAge: 1000 * 60 * 60 * 24 * 365 * 10, // 10 years
        httpOnly: true,
        sameSite: 'lax',
        secure: __prod__, // cookie only works in https 
      },
      secret: '123',
      resave: false,
      saveUninitialized: false,
    })
  );

  // Apollo server
  const apolloServer = new ApolloServer({
    schema: await buildSchema({
      resolvers: [HelloResolver, UserResolver, FridgeResolver],
      validate: false,
    }),
    context: ({ req, res }) => ({ req, res, redis })
  })
  apolloServer.applyMiddleware({ app, cors: false });
  const PORT = 4000;
  app.listen(PORT, ()=> {
    console.log(`Server is listening on port ${PORT}`.blue.bold)
  });
};

main().catch((err) => {
  console.log(err.red.bold)
});

2 Answers2

0
    @Resolver()
export class FridgeResolver {
  @Mutation(() => Fridge)
  async createFridge (
    @Arg("inputs") inputs: FridgeInput,
    @Ctx() { req } : MyContext
  ): Promise<Fridge | undefined> {
      const author = await Users.findOne({_id: req.session.userId}); //You are using async function so you might have to use await here.
      const {name, address, description, coordinates} = inputs;
  
      const fridge = new Fridges({
        name,
        address,
        description,
        author,
        coordinates: coordinates ? coordinates : undefined
      })
  
      try {
        await fridge.save()
      } catch (error) {
        console.log(error)
        return undefined
      } 
    
      return fridge
  }
}
Syed Mohib Uddin
  • 718
  • 7
  • 16
  • Hey Syed, awaiting the user was definitely something I needed to change as well. It wasn't able to completely solve the problem but found that the Coordinates class in the Fridge class declared as an object type was the root of the problem. I changed the field to be two separate individual lat and lng fields and it solved the issue. If anyone has an explanation for this that would be awesome because I wasn't able to find anything on my own. Thanks for your help Syed! – Angus Chang Apr 01 '21 at 16:53
  • No worries bro,if you are using async function you should use await as pointer will not wait to complete the task and can move to next line then will get back to which can cause unhanlded promise rejection. – Syed Mohib Uddin Apr 01 '21 at 17:33
0

I was able to get rid of the error by changing the fields in my Fridge class to:

import { Field, Float, ID, ObjectType } from "type-graphql";
import { prop, getModelForClass, Ref } from "@typegoose/typegoose";
import { User } from './User';

@ObjectType()
export class Fridge {
  @Field(() => ID, {nullable: true})
  _id: string

  @Field(() => String) 
  @prop({required: true})
  name: string;

  @Field(() => String) 
  @prop({required: true})
  address: string;

  @Field(() => String) 
  @prop({required: true})
  description: string;

  @Field(() => User) 
  @prop({ ref: () => User})
  public author: Ref<User>

  @Field(() => Float, {nullable: true}) 
  @prop()
  lat?: number

  @Field(() => Float, {nullable: true}) 
  @prop()
  lng?: number
};

export const Fridges = getModelForClass(Fridge);

I don't fully understand how this would cause an unhanlded promise rejection. If anyone has any info it would be much appreciated because I was not able to find anything on my own.