skip to Main Content

all,

I’m still getting comfortable with both Typescript and with Apollo Server, and I’m looking for a method I’m not finding. I’m dealing with an addUser mutation, with unique username and email address required. When the validation passes, everything works fine. But when the validation fails, I’m having difficulty extracting the error message from the ApolloError. The error shows what failed:

duplicate key error collection: be_for_reel_db.users index: userName_1 dup key: { userName: "foo" }

But I’ve been unable to extract that text so that my client code can parse it and inform the user why the new account wasn’t created. I am coding in React 18, using Apollo Server Express 3.6.2 and graphQL 16.3.0.

So the client side handler uses a try-catch block:

try {
      const { data } = await addUser({
        variables: {
          userName: signupForm.signupUsername,
          email: signupForm.signupEmail,
          password: signupForm.signupPassword,
        },
      });

    } catch (err) {
      setErrorMessage(true);
      console.log(err);
    }

When I console.log the error, it correctly shows up as an ApolloError. On the front end side I can’t simply access err.message (there is a typescript compile error: "err" is of type unknown)

Here is what I’ve tried:

–I’ve tried importing the ApolloError function from the Apollo client. It hasn’t given me any love: compile errors when I try to apply it as a type to err.

–I’ve tried customizing the error message on the server side:

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: authMiddleware,
  formatError: (formattedError, error) => {
    return { message: "This is my custom error" };
  },
});

When I do that, I get the same thing: my new message is listed with the ApolloError that arrives on the client side, still inaccessible.

–I’ve tried inserting some logic into the resolver:

Mutation: {
    addUser: async (parent, args) => {
      const { userName, email, password } = args;
      const today = Date();
      const newUser = {
        userName,
        email,
        password,
        created: today,
        polls: [],
        votes: [],
        comments: [],
      };

      const user = await User.create(newUser);

      if (!user) return { message: "Operation failed" };

      const token = signToken(user);
      return { token, user };
    },

    (other mutations here)
}

The logic seems to not even hit the if statement: once the mutation fails (i.e. not a unique username or email or whatever) Apollo throws its error and the rest of addUser doesn’t execute.

Can anyone give me any kind of guidance on this?

===============

OK, I tried out Michael Floyd’s suggestions below, still with no luck.

If I remove the try-catch from the client side, I get the same Apollo error to the console, only now it’s not caught so the error appears in the browser and not just the console.

I then tried to handle it server-side:

try {
        const user = await User.create(newUser);
        return user;
      } catch (err) {
        const pieces = err.message.split(": ");
        let message = pieces.pop();
        message = `${pieces.pop()}: ${message}`;
        return message;
      }

That bit on parsing the message creates a JSON string something like { username: foo }, or "this failed because ‘foo’ is already taken". But when I return the message to the client…I just get an Apollo error with { username: foo} as the title, still unreachable at the client.

2

Answers


  1. Chosen as BEST ANSWER

    OK, I think I've got it. Thanks, Michael Floyd, for spurring a further spate of attempts!

    The problem was a typescript oversight. In the try/catch, I in fact could reach err.message, but only if I identified err as type any. I had been trying to type it as ApolloError (which I had imported) with no luck: typescript would not allow it. It was not sufficient to leave it un-typed, I had to specifically identify err as any.


  2. Apollo client doesn’t throw an error when the server returns an error so you can’t catch it.

    Instead look at the error object returned from your mutation:

    const { data, error } = await addUser(…);
    

    A try/catch on the server might come in handy if you want to control the message returned.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search