Building Full-Stack Web Applications with Express.js and React

·4 min readexpressJs

Learn how to combine Express.js and React to create powerful web applications

This blog post explores the integration of Express.js, a robust Node.js framework, with React, a popular frontend library, to build full-stack web applications efficiently.

Blog thumbnail
Introduction

Building modern web applications often requires a combination of frontend and backend technologies. Express.js, a minimalist and flexible Node.js framework, serves as an excellent choice for creating powerful backend APIs and handling server-side logic. When combined with React, a popular frontend library known for its component-based architecture and declarative approach, developers can build full-stack web applications that offer a seamless user experience.

Setting Up the Project

Before we dive into the integration of Express.js and React, let's set up a new project and install the necessary dependencies. We'll use create-react-app to generate the frontend and express-generator to scaffold the backend.

# Create a new directory for your project
mkdir full-stack-app
cd full-stack-app
 
# Generate the frontend using create-react-app
npx create-react-app client
 
# Scaffold the backend using express-generator
npx express-generator server
cd server
npm install

Now that we have our project structure in place, with the frontend generated in the client directory and the backend scaffolded in the server directory, let's proceed with integrating Express.js and React.

Integrating Express.js with React

To integrate Express.js with React, we'll serve the React application as static files from the Express server. This approach allows us to handle both frontend and backend logic within the same project structure.

Let's configure Express.js to serve the React application:

// server/app.js
 
const express = require('express');
const path = require('path');
const app = express();
 
// Serve static files from the React app
app.use(express.static(path.join(__dirname, '../client/build')));
 
// Define API routes
app.get('/api', (req, res) => {
    res.send({ message: 'Welcome to the Express.js backend!' });
});
 
// Serve the React app on all other routes
app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname, '../client/build/index.html'));
});
 
const port = process.env.PORT || 5000;
app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

In this configuration, we serve the static files from the React build directory using Express's express.static middleware. We define an API route at /api to handle backend logic, and all other routes are redirected to the React application's index.html.

Proxying API Requests from React to Express

During development, it's common to run the React frontend and Express backend servers separately. To avoid CORS issues and simplify the development workflow, we can proxy API requests from the React application to the Express server.

Modify the client/package.json file to include a proxy configuration:

// client/package.json
 
{
  "name": "client",
  "version": "0.1.0",
  "proxy": "http://localhost:5000",
  ...
}

With this proxy configuration, any API requests from the React application will be forwarded to the Express server running on port 5000 during development.

Creating API Endpoints with Express

With the integration of Express.js and React in place, we can now create API endpoints to handle data retrieval, manipulation, and other server-side tasks. These endpoints can be defined in separate route files within the Express application.

Here's an example of defining a simple API endpoint in Express:

// server/routes/api.js
 
const express = require('express');
const router = express.Router();
 
router.get('/data', (req, res) => {
    res.json({ message: 'This is sample data from the Express backend.' });
});
 
module.exports = router;

We can then mount this router in the main Express application:

// server/app.js
 
const express = require('express');
const path = require('path');
const apiRouter = require('./routes/api');
 
const app = express();
 
// Serve static files from the React app
app.use(express.static(path.join(__dirname, '../client/build')));
 
// Mount API routes
app.use('/api', apiRouter);
 
// Serve the React app on all other routes
app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname, '../client/build/index.html'));
});
 
const port = process.env.PORT || 5000;
app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

With this setup, requests to /api/data will be handled by the apiRouter, allowing us to encapsulate and organize our backend logic effectively.

Conclusion

Integrating Express.js with React opens up a world of possibilities for building powerful full-stack web applications. By combining the robust backend capabilities of Express.js with the dynamic frontend features of React, developers can create seamless and scalable web experiences that cater to a wide range of use cases.

In this tutorial, we've covered the basics of integrating Express.js with React, including serving the React application from the Express server, proxying API requests during development, and defining API endpoints to handle backend logic. Armed with this knowledge, you're well-equipped to embark on your journey of building full-stack web applications with Express.js and React.

Stay tuned for more tutorials on full-stack development and happy coding!

Author

Masum Billah

Full-Stack Engineer