Next.js & Serverless Functions: A Simple Form Submission App

Written by

in

In the dynamic world of web development, creating interactive forms that seamlessly collect user data is a fundamental requirement for many applications. Imagine building a contact form, a feedback form, or even a simple survey form. The challenge often lies not just in designing the form itself, but also in handling the data submission process, especially when you want to avoid relying on a traditional server. This is where Next.js and serverless functions come to the rescue, offering a powerful combination for building efficient, scalable, and maintainable web applications.

Why Serverless Functions and Next.js?

Traditional form submissions often involve a backend server to process the data. This means managing server infrastructure, dealing with potential scaling issues, and the overhead of server maintenance. Serverless functions, on the other hand, allow you to execute code without managing servers. You only pay for the actual computation time, making it a cost-effective solution, especially for applications with fluctuating traffic. Next.js, with its built-in API routes, makes implementing these serverless functions incredibly straightforward.

This tutorial will guide you through building a simple form submission app using Next.js and serverless functions. We’ll cover everything from setting up the project to deploying your app, providing you with a solid foundation for understanding and implementing serverless functions in your own projects.

Prerequisites

Before we begin, ensure you have the following:

  • Node.js and npm (or yarn) installed on your machine.
  • A basic understanding of HTML, CSS, and JavaScript.
  • A code editor (VS Code, Sublime Text, etc.).

Step-by-Step Guide: Building Your Form Submission App

1. Setting Up Your Next.js Project

First, let’s create a new Next.js project. Open your terminal and run the following command:

npx create-next-app form-submission-app

This command will create a new directory named `form-submission-app` with the basic structure of a Next.js project. Navigate into the project directory:

cd form-submission-app

2. Creating the Form

Let’s create the form. We’ll modify the `pages/index.js` file to include a simple form with fields for name, email, and a message. Open `pages/index.js` and replace its contents with the following code:

import { useState } from 'react';

export default function Home() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [message, setMessage] = useState('');
  const [submitted, setSubmitted] = useState(false);
  const [error, setError] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    setError(''); // Clear any previous errors

    if (!name || !email || !message) {
      setError('Please fill out all fields.');
      return;
    }

    try {
      const response = await fetch('/api/submit', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ name, email, message }),
      });

      if (response.ok) {
        setSubmitted(true);
        setName('');
        setEmail('');
        setMessage('');
      } else {
        const errorData = await response.json();
        setError(errorData.message || 'An error occurred.');
      }
    } catch (err) {
      setError('An error occurred. Please try again later.');
      console.error('Submission error:', err);
    }
  };

  return (
    <div>
      <h1>Contact Us</h1>
      {submitted ? (
        <p>Thank you for your submission!</p>
      ) : (
        
          {error && <p style="{{">{error}</p>}
          <div>
            <label>Name:</label>
             setName(e.target.value)}
              required
            />
          </div>
          <div>
            <label>Email:</label>
             setEmail(e.target.value)}
              required
            />
          </div>
          <div>
            <label>Message:</label>
            <textarea id="message"> setMessage(e.target.value)}
              required
            />
          </div>
          <button type="submit">Submit</button>
        
      )}
    </div>
  );
}

This code defines a simple form with input fields for name, email, and message. It also includes state variables to manage the form data, submission status, and error messages. The `handleSubmit` function is responsible for sending the form data to our serverless function.

3. Creating the Serverless Function (API Route)

Next, we’ll create the serverless function that will handle the form submission. In Next.js, you create API routes by placing files inside the `pages/api` directory. Create a new file named `pages/api/submit.js` and add the following code:

export default async function handler(req, res) {
  if (req.method === 'POST') {
    try {
      const { name, email, message } = req.body;

      // Basic validation (optional, but recommended)
      if (!name || !email || !message) {
        return res.status(400).json({ message: 'All fields are required' });
      }

      // Log the data (replace with your desired action, e.g., send email, save to database)
      console.log('Form data:', { name, email, message });

      // Simulate a successful submission
      await new Promise(resolve => setTimeout(resolve, 1000)); // Simulate some processing time

      res.status(200).json({ message: 'Form submitted successfully!' });
    } catch (error) {
      console.error('Error processing form submission:', error);
      res.status(500).json({ message: 'Internal server error' });
    }
  } else {
    res.status(405).json({ message: 'Method Not Allowed' });
  }
}

This serverless function will handle POST requests to the `/api/submit` endpoint. It extracts the form data from the request body, performs basic validation, and logs the data to the console. In a real-world scenario, you would replace the `console.log` statement with your desired action, such as sending an email, saving the data to a database (e.g., MongoDB, PostgreSQL), or integrating with a third-party service.

4. Running Your Application

Now, run your Next.js application in development mode. In your terminal, inside the project directory, execute:

npm run dev  # or yarn dev

This will start the development server, usually on `http://localhost:3000`. Open your browser and navigate to this address. You should see the form you created.

Fill out the form and submit it. Check your browser’s developer console and your terminal where you are running the `npm run dev` command. You should see the form data logged in the console.

5. Deploying Your Application

Next.js makes deployment incredibly easy. You can deploy your application to various platforms, including Vercel, Netlify, and others. For simplicity, we’ll use Vercel, as it’s the recommended platform for Next.js applications.

If you don’t have a Vercel account, sign up at https://vercel.com/.

Install the Vercel CLI globally:

npm install -g vercel  # or yarn global add vercel

Then, authenticate with Vercel in your terminal:

vercel login

Finally, deploy your project:

vercel

Vercel will guide you through the deployment process. It will detect that it’s a Next.js project and configure everything automatically. After the deployment is complete, Vercel will provide you with a live URL where your application is deployed.

Common Mistakes and How to Fix Them

1. CORS Errors

CORS (Cross-Origin Resource Sharing) errors can occur if your frontend and backend (serverless function) are hosted on different domains. This is usually not an issue when deploying to Vercel or Netlify, as they handle this automatically. However, if you encounter CORS issues, ensure your serverless function is configured to allow requests from your frontend’s origin. In this simple example, we are using the same origin, so it’s not a common issue, but it’s good to be aware of it.

Fix: If you encounter CORS errors, you’ll need to configure your serverless function to allow requests from your frontend’s origin. This typically involves setting the `Access-Control-Allow-Origin` header in your serverless function’s response. For example:

res.setHeader('Access-Control-Allow-Origin', '*'); // Or specify your frontend's origin

2. Incorrect API Route Path

Make sure the API route path in your `fetch` request matches the path of your serverless function file. For instance, if your file is `pages/api/submit.js`, the path in your `fetch` request should be `/api/submit`.

Fix: Double-check the path in your `fetch` request and ensure it corresponds to the correct file path.

3. Missing Dependencies

If you’re using external libraries or modules in your serverless function, ensure they are correctly installed in your project’s `package.json` file. Next.js will automatically handle the bundling of these dependencies during deployment.

Fix: Install any missing dependencies using `npm install <package-name>` or `yarn add <package-name>`.

4. Unhandled Errors in Serverless Functions

Serverless functions can fail if they encounter unhandled errors. Always include proper error handling (e.g., `try…catch` blocks) to catch potential issues and return appropriate error responses to the client.

Fix: Implement `try…catch` blocks around your serverless function’s logic to catch errors. Return informative error messages to the client using `res.status(500).json({ message: ‘Error message’ });`.

5. Incorrect HTTP Method

Ensure that your serverless function is configured to handle the correct HTTP method (e.g., `POST`, `GET`, `PUT`, `DELETE`). In our example, the form submission requires a `POST` request.

Fix: Verify that your serverless function checks the `req.method` and handles the appropriate method. For instance, `if (req.method === ‘POST’) { … }`.

Key Takeaways

  • Next.js and Serverless Functions: A powerful combination for building scalable and efficient web applications.
  • API Routes: Next.js makes creating serverless functions (API routes) simple.
  • Form Handling: Easily process form submissions without a traditional server.
  • Deployment: Deploy your Next.js app with ease using platforms like Vercel.
  • Error Handling: Implement robust error handling in your serverless functions.

FAQ

1. Can I use this approach to send emails?

Yes, you can. Within your serverless function, instead of `console.log`, you would use an email sending service (e.g., SendGrid, Mailgun) or a library (e.g., Nodemailer) to send an email. You’ll need to configure the email service with your credentials and then call its API from your serverless function.

2. How do I save the form data to a database?

You can use a database such as MongoDB, PostgreSQL, or others. In your serverless function, you would connect to the database, and insert the data into the appropriate collection or table. You’ll need to install the necessary database client library (e.g., `mongoose` for MongoDB, `pg` for PostgreSQL) and configure the connection details.

3. Is this approach secure?

Security is crucial. Always validate user input on both the client and server sides to prevent vulnerabilities like cross-site scripting (XSS) and SQL injection. Protect your API routes with authentication if necessary. When sending emails, use a reputable email service provider to handle the sending process securely.

4. How do I handle file uploads?

File uploads require a slightly more complex approach. You’ll need to use a library like `formidable` or `multer` to parse the form data, handle the file upload, and store the file (e.g., in cloud storage like AWS S3 or Google Cloud Storage). Remember to handle the file upload in your serverless function.

5. Can I use environment variables?

Yes, you can and should use environment variables to store sensitive information like API keys and database connection strings. In Next.js, you can access environment variables using `process.env`. When deploying to platforms like Vercel, you can configure environment variables in the deployment settings.

Building a form submission app with Next.js and serverless functions opens up a world of possibilities for creating dynamic and interactive web applications. By understanding the core concepts and following the step-by-step instructions, you can easily implement form submissions without the complexities of managing a traditional server. Remember to always prioritize security, handle errors gracefully, and consider the scalability of your application as it grows. This simple project serves as a fantastic starting point for exploring the power of serverless functions and Next.js, empowering you to build more efficient and maintainable web solutions. As your projects become more complex, the principles of serverless architecture will help you keep your applications scalable, cost-effective, and easy to manage.