Search code examples
next.jsformikdynamic-routing

How to use Next.js router.push to dynamic api route with Formik, getting 404 (Not found) error


I'm using the auth0 nextjs-auth0 library to handle signup and authentication for a next.js app. I'm also using Formik to handle input data and validation. I'd like to have an email address be submitted via Formik to a Next.js api route.

When I use Nextjs's useRouter hook to navigate via router.push to the api route, it works as expected, so my data is passed to the api route and nextjs-auth0 redirects the user as expected. However, before redirecting the browser console flashes the following error:

enter image description here

Should I just ignore this error? Is it possible that router.push is for client-side redirects only I'm trying to navigate to an api route, which is not how it should be done? Note, my /signup api route uses the auth0-nextjs code and redirects the user to auth0's authentication page. Relevant code below.

Signup api route:

import auth0 from "../../../lib/auth0"

export default async function signup(req, res) {

    const {
        query: { pid },
    } = req


    try {
        await auth0.handleLogin(req, res, {
            authParams: {
                initialScreen: "signup",
                login_hint: pid
            },
        })
    } catch (error) {
        console.error(error)
        res.status(error.status || 500).end(error.message)
    }
}

Import of useRouter hook:

import { useRouter } from 'next/router'

Validation function for Formik:

    function validateEmail(value) {
        let error;
        let re = /\S+@\S+\.\S+/

        if (!value) {
            error = "Email is required"
        } else if (!re.test(value)) {
            error = "Please use a valid email"
        }

        return error
    }

Handler function for Formik submit:

    const handleFormikSubmit = async (values, actions) => {
        router.push('/api/signup/[...pid]', `/api/signup/${values.email}`)
        actions.setSubmitting(false)
    }

Formik component (note, using the <Button component is a Chakra-ui component):

                                <Formik
                                    initialValues={{ email: "" }}
                                    onSubmit={handleFormikSubmit}
                                >
                                    {(props) => (
                                        <form onSubmit={props.handleSubmit}>
                                            <Field type="email" name="email" validate={validateEmail}>
                                                {({ field, form }) => (
                                                    <FormControl
                                                        isInvalid={
                                                            form.errors.email &&
                                                            form.touched.email
                                                        }
                                                    >
                                                        <Input
                                                            {...field}
                                                            id="email"
                                                            placeholder="Your email address..."
                                                        />
                                                        <FormErrorMessage>
                                                            {form.errors.email}
                                                        </FormErrorMessage>
                                                    </FormControl>
                                                )}
                                            </Field>
                                            <Button
                                                variantColor="orangish"
                                                width="100%"
                                                mt={2}
                                                className="checkout-style-background"
                                                isLoading={props.isSubmitting}
                                                type="submit"
                                            >
                                                Sign up to get started for $1
                                            </Button>
                                        </form>
                                    )}
                                </Formik>

Solution

  • next/router is used for client-side transitions between local pages whenever it's possible. An API route is always executed on a server side, so you can't perform a client-side navigation to it.

    That being said, next/router is not useful if you want to redirect to an API route or another website.

    Instead, you can use window.location.replace() to redirect a user to the API route.