Movatterモバイル変換


[0]ホーム

URL:


Skip to content
Important
Security Advisory: React2Shell & two new vulnerabilities
Find out more

How to create forms with API Routes

Last updated July 30, 2025

Forms enable you to create and update data in web applications. Next.js provides a powerful way to handle data mutations usingAPI Routes. This guide will walk you through how to handle form submission on the server.

Server Forms

To handle form submissions on the server, create an API endpoint that securely mutates data.

pages/api/submit.ts
importtype { NextApiRequest, NextApiResponse }from'next'exportdefaultasyncfunctionhandler(  req:NextApiRequest,  res:NextApiResponse) {constdata=req.bodyconstid=awaitcreateItem(data)res.status(200).json({ id })}

Then, call the API Route from the client with an event handler:

pages/index.tsx
import { FormEvent }from'react'exportdefaultfunctionPage() {asyncfunctiononSubmit(event:FormEvent<HTMLFormElement>) {event.preventDefault()constformData=newFormData(event.currentTarget)constresponse=awaitfetch('/api/submit', {      method:'POST',      body: formData,    })// Handle response if necessaryconstdata=awaitresponse.json()// ...  }return (    <formonSubmit={onSubmit}>      <inputtype="text"name="name" />      <buttontype="submit">Submit</button>    </form>  )}

Good to know:

  • API Routesdo not specify CORS headers, meaning they are same-origin only by default.
  • Since API Routes run on the server, we're able to use sensitive values (like API keys) throughEnvironment Variables without exposing them to the client. This is critical for the security of your application.

Form validation

We recommend using HTML validation likerequired andtype="email" for basic client-side form validation.

For more advanced server-side validation, you can use a schema validation library likezod to validate the form fields before mutating the data:

pages/api/submit.ts
importtype { NextApiRequest, NextApiResponse }from'next'import { z }from'zod'constschema=z.object({// ...})exportdefaultasyncfunctionhandler(  req:NextApiRequest,  res:NextApiResponse) {constparsed=schema.parse(req.body)// ...}

Error handling

You can use React state to show an error message when a form submission fails:

pages/index.tsx
import React, { useState, FormEvent }from'react'exportdefaultfunctionPage() {const [isLoading,setIsLoading]=useState<boolean>(false)const [error,setError]=useState<string|null>(null)asyncfunctiononSubmit(event:FormEvent<HTMLFormElement>) {event.preventDefault()setIsLoading(true)setError(null)// Clear previous errors when a new request startstry {constformData=newFormData(event.currentTarget)constresponse=awaitfetch('/api/submit', {        method:'POST',        body: formData,      })if (!response.ok) {thrownewError('Failed to submit the data. Please try again.')      }// Handle response if necessaryconstdata=awaitresponse.json()// ...    }catch (error) {// Capture the error message to display to the usersetError(error.message)console.error(error)    }finally {setIsLoading(false)    }  }return (    <div>      {error&& <divstyle={{ color:'red' }}>{error}</div>}      <formonSubmit={onSubmit}>        <inputtype="text"name="name" />        <buttontype="submit"disabled={isLoading}>          {isLoading?'Loading...':'Submit'}        </button>      </form>    </div>  )}

Displaying loading state

You can use React state to show a loading state when a form is submitting on the server:

pages/index.tsx
import React, { useState, FormEvent }from'react'exportdefaultfunctionPage() {const [isLoading,setIsLoading]=useState<boolean>(false)asyncfunctiononSubmit(event:FormEvent<HTMLFormElement>) {event.preventDefault()setIsLoading(true)// Set loading to true when the request startstry {constformData=newFormData(event.currentTarget)constresponse=awaitfetch('/api/submit', {        method:'POST',        body: formData,      })// Handle response if necessaryconstdata=awaitresponse.json()// ...    }catch (error) {// Handle error if necessaryconsole.error(error)    }finally {setIsLoading(false)// Set loading to false when the request completes    }  }return (    <formonSubmit={onSubmit}>      <inputtype="text"name="name" />      <buttontype="submit"disabled={isLoading}>        {isLoading?'Loading...':'Submit'}      </button>    </form>  )}

Redirecting

If you would like to redirect the user to a different route after a mutation, you canredirect to any absolute or relative URL:

pages/api/submit.ts
importtype { NextApiRequest, NextApiResponse }from'next'exportdefaultasyncfunctionhandler(  req:NextApiRequest,  res:NextApiResponse) {constid=awaitaddPost()res.redirect(307,`/post/${id}`)}

Was this helpful?

supported.

[8]ページ先頭

©2009-2025 Movatter.jp