Gabriel Moreira
Gabriel Moreira

Reputation: 21

Uploading Files on production server returns either CORS error or POST 400 Bad Request using Apollo-Graphql

I'm having trouble on uploading files to my production server, in a local environment, everything works fine just as expected, but when I try to do a a Mutation containing file uploads (and only on those mutations) it throws me a CORS error. I'm using Spaces to upload the files and save them into my Database.

app.ts (Back-end):

const configureExpress = async () => {
  const app: express.Application = express();

  app.use(cors());
  app.use(express.json());
  app.use(express.urlencoded({ extended: false }));
  app.use('/services', servicesRoute);

  const { typeDefs, resolvers } = await buildSchema;
  const schema = makeExecutableSchema({ typeDefs, resolvers });

  const server = new ApolloServer({
    schema,
    playground: true,
    introspection: true,
    uploads: {
      maxFileSize: 1000000000, 
      maxFiles: 100,
    },
    context: async ({ req }) => ({
      auth: await Auth.getUser(req),
    }),
    formatError: (err) => ({
      message: err.message,
      code: err.extensions && err.extensions.code,
      locations: err.locations,
      path: err.path,
      extensions: err.extensions && err.extensions.exception,
    }),
  });

  server.applyMiddleware({ app });

  return app;
};

export default () => database.connect().then(configureExpress);

client-auth.ts (On the Front-end):

const errorLink = onError(({ graphQLErrors }: any) => {
  if (graphQLErrors) {
    console.log(graphQLErrors);
    graphQLErrors.map(({ message }: any) => console.log(message));

    graphQLErrors.map(({ code }: any) => {
      if (code === 'UNAUTHENTICATED') {
        persistStore(store)
          .purge()
          .then(() => {
            window.location.reload();
          });
      }
      return true;
    });
  }
});

const authLink = setContext((_, { headers }) => {
  const token = store.getState().auth.user!.token;
  return {
    headers: {
      ...headers,
      authorization: `Bearer ${token}`,
    },
  };
});

const uploadLink = createUploadLink({
  uri: 'https://api.example.com.br/graphql'
  // uri: 'http://localhost:4000/graphql',
});

const client = new ApolloClient({
  link: ApolloLink.from([errorLink, authLink, uploadLink]),
  cache: new InMemoryCache(),
  defaultOptions: {
    query: {
      fetchPolicy: 'network-only',
    },
  },
});

resolver.ts

 return propertyModel.create({
      ...data
    } as DocumentType<any>).then(async property => {

    const user = await userModel.findById(input.userId);
    if (!user) throw new UserNotFound();
    await ownerModel.findByIdAndUpdate(user.owner, {
       $push: {
           properties: property.id,
        }
    });

    if (input.images) {
      input.images.forEach(async image => {
        const uploadedImage = await FileS3.upload(image, {
        path: 'images',
        id: propertyId.toHexString(),
        });
        await property.updateOne({$push: {images: uploadedImage}});
      });
    }
    
    if (input.scripture) {
      const uploadedScripture = await FileS3.upload(input.scripture, {
        path: 'documents',
        id: propertyId.toHexString(),
      });
      await property.updateOne({scripture: uploadedScripture});
    }
    if (input.registration) {
      const uploadedRegistration = await FileS3.upload(input.registration, {
        path: 'documents',
        id: propertyId.toHexString(),
      })
      await property.updateOne({
          registration: uploadedRegistration,
      });
    };

    if (input.car) {
      const uploadedCar = await FileS3.upload(input.car, {
        path: 'documents',
        id: propertyId.toHexString(),
      });
      await property.updateOne({
          car: uploadedCar,
      });
    };

    if (input.ccir) {
      const uploadedCcir = await FileS3.upload(input.ccir, {
        path: 'documents',
        id: propertyId.toHexString(),
      });
      await property.updateOne({
        ccir: uploadedCcir,

      });
    };

    if (input.itr) {
      const uploadedItr = await FileS3.upload(input.itr, {
        path: 'documents',
        id: propertyId.toHexString(),
      });
      await property.updateOne({
        itr: uploadedItr, 
      });
    };
      
    if (input.subscription) {
      const uploadedSubscription = await FileS3.upload(input.subscription, {
          path: 'documents',
          id: propertyId.toHexString(),
        });
       await property.updateOne({
          subscription: uploadedSubscription
       });


    return property;
    });
  };


I'm really lost regarding this error, is this an actual server error? (Production server is on DigitalOcean in Ubuntu) or something wrong regarding the code?

Upvotes: 1

Views: 1000

Answers (2)

Gabriel Moreira
Gabriel Moreira

Reputation: 21

If any one happens to have this same problem, here's how I solved. After digging through the code I realized that in the server I was receiving a Maximum call stack size exceeded, upon looking further to this problem I realized that It was an error regarding the Graphql-Upload dependency, I fixed it by removing it as a dependency and added the following on my package.json:

  "resolutions": {
    "fs-capacitor":"^6.2.0",
    "graphql-upload": "^11.0.0"
  }

after this I just executed this script: npx npm-force-resolutions. And It worked all fine.

Upvotes: 1

Metabolic
Metabolic

Reputation: 2914

For CORS, if you are using the latest version of ApolloServer then turn on the CORS:

const server = new ApolloServer({
  cors: {
      credentials: true,
      origin: true
    },,
  ...
});

//also apply it here
server.applyMiddleware({ app, 
  cors: {
      credentials: true,
      origin: true
    }
});

400 status code is returned for bad request which happens when a client sends a malformed request to server, You need to verify that your client is sending the correct data and headers on via correct HTTP verb (post/get etc)

Upvotes: 1

Related Questions