Frequently Asked Questions

How do I capture error/success responses in JavaScript?

Learn how to handle form submission responses programmatically

Formserve returns JSON responses for all form submissions, making it easy to capture and handle success/error states in your JavaScript code.

API Response Format

Success Response (HTTP 200):

{
  "status": "success",
  "message": "Form submitted successfully",
  "redirect_url": "https://example.com/thank-you"
}

Error Response (HTTP 422):

{
  "status": "error",
  "message": "Failed to save submission",
  "errors": ["Field name is required", "Email is invalid"]
}

Method 1: Using Modern Fetch API (Recommended)

document.getElementById('myForm').addEventListener('submit', async function(e) {
  e.preventDefault();

  const form = e.target;
  const formData = new FormData(form);
  const submitButton = form.querySelector('button[type="submit"]');

  // Show loading state
  submitButton.disabled = true;
  submitButton.textContent = 'Submitting...';

  try {
    const response = await fetch(form.action, {
      method: 'POST',
      body: formData
    });

    const data = await response.json();

    if (response.ok && data.status === 'success') {
      // Handle success
      console.log('Success:', data);

      // Show success message
      document.getElementById('success-message').textContent = data.message;
      document.getElementById('success-message').classList.remove('hidden');

      // Optionally redirect
      if (data.redirect_url) {
        window.location.href = data.redirect_url;
      } else {
        form.reset(); // Clear the form
      }

    } else {
      // Handle error
      console.error('Error:', data);

      // Show error message
      const errorDiv = document.getElementById('error-message');
      errorDiv.textContent = data.message;

      // Show specific field errors if available
      if (data.errors && data.errors.length > 0) {
        errorDiv.innerHTML = `
          <p>${data.message}</p>
          <ul>
            ${data.errors.map(err => `<li>${err}</li>`).join('')}
          </ul>
        `;
      }
      errorDiv.classList.remove('hidden');
    }

  } catch (error) {
    // Handle network errors
    console.error('Network error:', error);
    document.getElementById('error-message').textContent =
      'An error occurred. Please try again.';
    document.getElementById('error-message').classList.remove('hidden');

  } finally {
    // Reset button state
    submitButton.disabled = false;
    submitButton.textContent = 'Submit';
  }
});

Method 2: Using XMLHttpRequest

document.getElementById('myForm').addEventListener('submit', function(e) {
  e.preventDefault();

  const form = e.target;
  const formData = new FormData(form);
  const xhr = new XMLHttpRequest();

  xhr.open('POST', form.action);

  xhr.onload = function() {
    const data = JSON.parse(xhr.responseText);

    if (xhr.status === 200 && data.status === 'success') {
      // Success
      console.log('Success:', data);
      alert(data.message);

      if (data.redirect_url) {
        window.location.href = data.redirect_url;
      }
    } else {
      // Error
      console.error('Error:', data);
      alert(data.message);

      if (data.errors) {
        console.error('Validation errors:', data.errors);
      }
    }
  };

  xhr.onerror = function() {
    alert('Network error occurred');
  };

  xhr.send(formData);
});

Method 3: With React

import { useState } from 'react';

function ContactForm() {
  const [status, setStatus] = useState('idle'); // idle, loading, success, error
  const [message, setMessage] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    setStatus('loading');

    const formData = new FormData(e.target);

    try {
      const response = await fetch('https://formserve.io/f/YOUR_ENDPOINT_KEY', {
        method: 'POST',
        body: formData
      });

      const data = await response.json();

      if (response.ok && data.status === 'success') {
        setStatus('success');
        setMessage(data.message);
        e.target.reset();

        if (data.redirect_url) {
          setTimeout(() => window.location.href = data.redirect_url, 2000);
        }
      } else {
        setStatus('error');
        setMessage(data.errors?.join(', ') || data.message);
      }

    } catch (error) {
      setStatus('error');
      setMessage('An error occurred. Please try again.');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}

      {status === 'success' && (
        <div className="success">{message}</div>
      )}

      {status === 'error' && (
        <div className="error">{message}</div>
      )}

      <button type="submit" disabled={status === 'loading'}>
        {status === 'loading' ? 'Submitting...' : 'Submit'}
      </button>
    </form>
  );
}

Complete HTML + JavaScript Example

<!DOCTYPE html>
<html>
<head>
  <style>
    .hidden { display: none; }
    .success { color: green; padding: 10px; background: #d4edda; }
    .error { color: red; padding: 10px; background: #f8d7da; }
  </style>
</head>
<body>
  <form id="contactForm" action="https://formserve.io/f/YOUR_ENDPOINT_KEY" method="POST">
    <div>
      <label for="name">Name:</label>
      <input type="text" id="name" name="name" required>
    </div>

    <div>
      <label for="email">Email:</label>
      <input type="email" id="email" name="email" required>
    </div>

    <div>
      <label for="message">Message:</label>
      <textarea id="message" name="message" required></textarea>
    </div>

    <button type="submit" id="submitBtn">Send Message</button>
  </form>

  <div id="successMessage" class="success hidden"></div>
  <div id="errorMessage" class="error hidden"></div>

  <script>
    const form = document.getElementById('contactForm');
    const submitBtn = document.getElementById('submitBtn');
    const successMsg = document.getElementById('successMessage');
    const errorMsg = document.getElementById('errorMessage');

    form.addEventListener('submit', async function(e) {
      e.preventDefault();

      // Hide previous messages
      successMsg.classList.add('hidden');
      errorMsg.classList.add('hidden');

      // Show loading state
      submitBtn.disabled = true;
      submitBtn.textContent = 'Sending...';

      try {
        const response = await fetch(form.action, {
          method: 'POST',
          body: new FormData(form)
        });

        const data = await response.json();

        if (response.ok && data.status === 'success') {
          // Success
          successMsg.textContent = data.message || 'Thank you! Your message has been sent.';
          successMsg.classList.remove('hidden');
          form.reset();

          // Optional redirect
          if (data.redirect_url) {
            setTimeout(() => {
              window.location.href = data.redirect_url;
            }, 2000);
          }

        } else {
          // Error
          let errorText = data.message || 'Something went wrong';
          if (data.errors && data.errors.length > 0) {
            errorText += ': ' + data.errors.join(', ');
          }
          errorMsg.textContent = errorText;
          errorMsg.classList.remove('hidden');
        }

      } catch (error) {
        errorMsg.textContent = 'Network error. Please check your connection and try again.';
        errorMsg.classList.remove('hidden');
      } finally {
        submitBtn.disabled = false;
        submitBtn.textContent = 'Send Message';
      }
    });
  </script>
</body>
</html>

Key Points:

  • Always prevent default form submission with e.preventDefault() to handle the response in JavaScript
  • Check both HTTP status (response.ok or xhr.status === 200) and the status field in the JSON response
  • The redirect_url field is optional - only present if you configured a redirect URL in your endpoint settings
  • Error responses may include an errors array with specific validation messages
  • Handle network errors separately from API errors in the catch block

HTTP Status Codes

  • 200 OK - Submission successful
  • 422 Unprocessable Entity - Validation error or submission failed
  • 404 Not Found - Invalid endpoint key
  • 429 Too Many Requests - Rate limit exceeded (with high spam protection)

More Questions Coming Soon

We're continuously adding more frequently asked questions. If you have a question that's not covered here, please contact support.