React-query: useMutation with Next.js API route error handling

Created on 13 Nov 2020  路  7Comments  路  Source: tannerlinsley/react-query

Describe the bug
I am using React Query's useMutation to subscribe users to ConvertKit email list using Next.js API route /pages/api/subscribe.js.

Here is a simplified code of the form.

import React from "react";
import { useForm } from "react-hook-form";
import { useMutation } from "react-query";

const SignupForm = () => {
  // front end validation with react-hook-form
  // prevent submitting invalid or empty emails
  const { handleSubmit } = useForm();

  // react query mutation that will call our API route
  const [mutate, { isLoading, isSuccess, isError, error }] = useMutation(
    ({ email }) => {
      return fetch(`/api/subscribe?email=${email}`);
    }
  );

  // handle form submit
  const onSubmit = (data) => mutate(data);

  // if API returns error show it to the user
  if (isError) {
    return <p>{error}</p>;
  }

  // if success show confirmation message instead of the form
  if (isSuccess) {
    return <p>Success</p>;
  }

  return (
    <form className="w-full max-w-sm" onSubmit={handleSubmit(onSubmit)}>
      ...
    </form>
  );
};

export default SignupForm;

Here is the simplified endpoint API route:

import fetch from "isomorphic-unfetch";

export default async (req, res) => {
  // 1. Destructure the email address from the request query.
  const { email, tags } = req.query;

  if (!email) {
    // 2. Throw an error if an email wasn't provided.
    return res.status(400).json({ error: "Email is required" });
  }
  ...
};

Is there a way for the Next.js API route to set isError to true and also return the error itself?

Or do I need to check for the returned data, check for the status, and handle the error in my component state?

At the moment any response from the Next.js API route returns isSuccess and isError or error is never updated.

Any suggestions on how to make isError and error work with Next.js API route would be great. Thanks

Expected behavior
I would expect that isError is true if the API returns 400 status.

Screenshots
img_react-query-next

Most helpful comment

To get error in mutation state you need emit error in your mutation function. In your case thats how fetch work (promise always success if request sent "The Promise returned from fetch() won鈥檛 reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure or if anything prevented the request from completing." details)

so you code should looks like:

// subscribe  
const subscribe = async (email) => {
  const res = await fetch(`/api/subscribe?email=${email}`);
  if (!res.ok) throw 'error'
}

// your component
const [mutate, { isLoading, isSuccess, isError, error }] = useMutation(({ email }) => subscribe(email) );

All 7 comments

Looks like your mutation function doesn't throwing error... can you share more code?

I can share the whole subscribe.js file but I am trying to make the example minimal to start with.

What would I need to change in the above code to make the isError and error update?

Just to clarify. If I don't send email in the request I want the isError to be true but it is always false.

To get error in mutation state you need emit error in your mutation function. In your case thats how fetch work (promise always success if request sent "The Promise returned from fetch() won鈥檛 reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure or if anything prevented the request from completing." details)

so you code should looks like:

// subscribe  
const subscribe = async (email) => {
  const res = await fetch(`/api/subscribe?email=${email}`);
  if (!res.ok) throw 'error'
}

// your component
const [mutate, { isLoading, isSuccess, isError, error }] = useMutation(({ email }) => subscribe(email) );

Oh ok, this works fine, throwing the error in the subscribe function works fine.

if (!res.ok) throw 'error'

So there is no way to get the different error messages returned by the endpoint?

image

Oh ok, this works fine, throwing the error in the subscribe function works fine.

if (!res.ok) throw 'error'

So there is no way to get the different error messages returned by the endpoint?

image

Did you solve the this problem?

I ended up throwing the error in the subscribe function and display this error to the user.

if (!res.ok) throw 'custom error message'
Was this page helpful?
0 / 5 - 0 ratings

Related issues

bgazzera picture bgazzera  路  4Comments

benediktviebahn picture benediktviebahn  路  4Comments

ivowork picture ivowork  路  5Comments

tiagofernandez picture tiagofernandez  路  3Comments

the133448 picture the133448  路  4Comments