Contents

0. Project Structure 1. Database 2. Backend (Node/Express) 3. React Frontend 4. Testing 5. Complete Data Flow

Back

Fullstack React Example - Burger Shop

React frontend + Node/Express API + PostgreSQL (or other DB)

0️⃣ Project Structure → Files & Folders

burger-shop/                    // root (monorepo / two folders)
│
├── server/                     // Node/Express backend
│   ├── src/
│   │   ├── models/            // Sequelize / Knex models
│   │   ├── routes/            // API routes (burgers, cart)
│   │   └── index.js            // express app
│   └── package.json
│
├── client/                     // React app (create-react-app / Vite)
│   ├── src/
│   │   ├── App.jsx
│   │   ├── components/BurgerList.jsx
│   │   └── context/         // CartContext
│   └── package.json
│
├── migrations/                // DB migrations
└── README.md
      

We keep server and client separated for clarity — same flow as other stacks: DB ↔ API ↔ Frontend.

1️⃣ Database → Model (Sequelize example)

Sequelize model for burgers (server/src/models/burger.js):

// server/src/models/burger.js
module.exports = (sequelize, DataTypes) => {
  const Burger = sequelize.define('Burger', {
    name: { type: DataTypes.STRING, allowNull: false },
    price: { type: DataTypes.DECIMAL(6,2), allowNull: false }
  });
  return Burger;
};
      

Use migrations to create the table and seed initial data.

2️⃣ Backend → Node / Express API

Minimal Express routes (server/src/routes/burgers.js):

// server/src/routes/burgers.js
const express = require('express');
const router = express.Router();
const { Burger } = require('../models');

/* GET /api/burgers */
router.get('/', async (req, res) => {
  const burgers = await Burger.findAll();
  res.json(burgers);
});

/* POST /api/cart */
router.post('/cart', async (req, res) => {
  // handle add to cart (session, DB cart table, or persisted cart)
  res.json({ success: true });
});

module.exports = router;
      

Server entry (server/src/index.js):

// server/src/index.js
const express = require('express');
const burgersRoutes = require('./routes/burgers');

const app = express();
app.use(express.json());
app.use('/api/burgers', burgersRoutes);
app.use('/api/cart', burgersRoutes); // minimal example

app.listen(4000, () => console.log('Server running on 4000'));
      

3️⃣ React Frontend → Components & Fetch

App.jsx (client/src/App.jsx):

// client/src/App.jsx
import React from 'react';
import BurgerList from './components/BurgerList';

export default function App() {
  return (
    <div>
      <h1>React Burger Shop</h1>
      <BurgerList />
    </div>
  );
}
      

BurgerList.jsx (client/src/components/BurgerList.jsx):

// client/src/components/BurgerList.jsx
import React, { useEffect, useState } from 'react';

export default function BurgerList() {
  const [burgers, setBurgers] = useState([]);
  useEffect(() => {
    fetch('/api/burgers')
      .then(r => r.json())
      .then(setBurgers);
  }, []);

  return (
    <ul id="catalog">
      {burgers.map(b => (
        <li key={b.id}>
          <strong>{b.name}</strong> — ${b.price}
          <button onClick={() => addToCart(b.id)}>Add</button>
        </li>
      ))}
    </ul>
  );
}

// addToCart calls API
async function addToCart(id) {
  await fetch('/api/cart', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ burgerId: id, qty: 1 })});
}
      

Run React dev server (CRA / Vite) and proxy `/api` to the backend in dev for CORS convenience.

4️⃣ Testing → Jest / RTL + Supertest

Examples:

// server/tests/burgers.test.js (supertest)
const request = require('supertest');
const app = require('../src/index');

describe('GET /api/burgers', () => {
  it('responds with json', async () => {
    const res = await request(app).get('/api/burgers');
    expect(res.status).toBe(200);
    expect(Array.isArray(res.body)).toBe(true);
  });
});

// client/src/components/BurgerList.test.jsx (React Testing Library)
import render, screen from '@testing-library/react';
import BurgerList from './BurgerList';

test('renders list', () => {
  render(<BurgerList />);
  expect(screen.getByText(/React Burger Shop/i)).toBeInTheDocument();
});
      

Use Jest for unit + RTL for components; Supertest for API endpoints.

5️⃣ Complete Data Flow

Layer Example Purpose
Database Postgres (Sequelize) Store burgers, cart rows
Backend Express routes JSON API for CRUD
React Frontend App.jsx, BurgerList.jsx Render initial UI, call API
Testing Jest / RTL / Supertest Unit & integration tests
Dev flow npm run dev / proxy Local dev with hot reload