Skip to content
Adding a Backend: API Routes and Database
← Back to Course Lesson 7 / 10

Adding a Backend: API Routes and Database

Everything so far runs in the user's browser. When someone submits their email, it goes nowhere — we just show a fake success message. In this lesson, we add a backend so data actually gets saved.

The Big Picture

Concept

Every web application has the same basic flow:

User's Browser (Frontend)API Route (Backend)DatabaseResponse back to Browser

The frontend collects user input. The backend processes it. The database stores it. The response confirms it. That's how every app in the world works — from Google to a simple signup form.

Next.js API Routes

Here's the beautiful thing about Next.js: it handles backend logic too. You don't need a separate server. API Routes are special files inside your app/api/ folder that handle server-side logic.

An API Route is simply a URL on your server that accepts data and returns a response. For example: POST /api/signup — receives an email, stores it, returns "success."

Try It

In Claude Code, type:

"Create an API route at app/api/signup/route.ts that: - Accepts POST requests with a JSON body containing an email field - Validates the email format on the server side - Checks for duplicate emails - Stores the email with a timestamp in a local JSON file at data/signups.json - Returns a JSON response with success: true or an error message - Create the data directory if it doesn't exist"

Claude will create the API route file. This is your first backend code!

Starting Simple: JSON File Storage

For learning purposes, we're storing data in a local JSON file. This is the simplest possible "database" — a file that contains a list of emails. It works perfectly for development.

After Claude creates the API route, your data/signups.json file will look something like this:

[
  { "email": "user@example.com", "timestamp": "2026-04-11T10:30:00Z" }
]

Honest Note

A JSON file is not a real database. It works fine for learning and small-scale testing, but it has real limitations: no concurrent access handling, no querying, no backup, and it lives on a single machine. In Lesson 10, we'll switch to DynamoDB — a real cloud database. But for now, this is the perfect learning tool.

Connecting Frontend to Backend

Now let's update the signup form to actually POST data to our new API route:

Try It

In Claude Code:

"Update the signup form component to POST to /api/signup instead of simulating a delay. Send the email as JSON in the request body. Handle the response: - If the API returns success: true, show the success message - If the API returns an error (like duplicate email), show the error message from the API - Handle network errors with a generic 'Something went wrong. Please try again.' message"

Testing It

  1. Make sure your dev server is running (npm run dev)
  2. Go to http://localhost:3000
  3. Enter an email and submit the form
  4. Check data/signups.json — your email should be there!
  5. Try submitting the same email again — you should see a "duplicate" error

Try It

Submit a few different emails through the form. Then open data/signups.json in VS Code to verify they're all there. You just built a full-stack feature!

Data Validation on the Server

Client-side validation (in the browser) is nice for user experience, but it's not enough. Anyone can bypass it by sending requests directly to your API.

Concept

Never trust data from the client. Always validate on the server too. Client-side validation is for user experience (showing helpful errors). Server-side validation is for security (rejecting bad data regardless of how it was sent).

Our API route already validates emails on the server — Claude included this. But let's make it more robust:

Add rate limiting to the signup API — maximum 5 signups per IP address 
per hour. If exceeded, return a 429 status with a friendly message.

Testing Your API

Besides using the form in the browser, you can test your API directly:

Using the browser's Network tab:

  1. Open Developer Tools (F12)
  2. Go to the Network tab
  3. Submit the form
  4. Click on the signup request to see the request and response details

Using curl in your terminal (optional):

curl -X POST http://localhost:3000/api/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "test@example.com"}'

Security Note

Honest Note

This is a learning project, and that's okay. But a production application needs more:

- Authentication — verifying who is making requests - Rate limiting — preventing abuse (we added basic limiting above) - Input sanitization — preventing injection attacks - HTTPS — encrypting data in transit - Environment variables — keeping secrets out of code

Claude can help you add all of these, but it's important to know they exist. Security isn't optional in real applications.

Git Checkpoint

git add .
git commit -m "backend API route with email storage and server-side validation"

Make sure to add data/signups.json to your .gitignore file — you don't want to commit user data:

echo "data/signups.json" >> .gitignore
git add .gitignore
git commit -m "ignore signup data file"

Key Takeaway

You just built a full-stack feature. Data flows from the user's browser, through your API route, into a database (JSON file for now). This is the same pattern used by every application in the world — you just did it with AI assistance.

Checkpoint

Your signup form now actually stores data. Emails are validated on both client and server, duplicates are rejected, and everything is saved to a file. Git committed. Next: building an admin dashboard to see your data.