This architecture separates concerns between the client and server, allowing for scalability, maintainability, and flexibility in web application development. It enables the creation of robust and interactive applications capable of handling diverse user requirements and environments.
-
Client-side:
- 🖥️ Represents the
user interface
and user interaction components. - 🌐
Sends requests to the server
to retrieve data or perform actions. - 📡 Utilizes various technologies and languages such as HTML, CSS, and JavaScript to render and interact with content in the user's browser.
- 🛠️ Executes business logic and handles user input validation before sending requests to the server.
- 🧠 May incorporate client-side frameworks or libraries like
React
, Angular, or Vue.js to manage UI components and state.
- 🖥️ Represents the
-
Server-side:
- 🖥️
Manages and processes requests from clients
. - 💼 Handles business logic, and interactions with databases or external services.
- 🌐 Uses server-side programming languages and frameworks such as
Node.js, Python, Java, or PHP
. - 📥
Receives requests from clients
, routes them to the appropriate handlers, andgenerates responses
. - 🔒 Implements security measures such as authentication, authorization, and data validation to protect sensitive information and ensure the integrity of the system.
- 📡 Can communicate with databases
(e.g., SQL databases like MySQL, PostgreSQL, or NoSQL databases like MongoDB)
to store and retrieve data required by the application.
- 🖥️
🔌 Communication:
- HTTP (Hypertext Transfer Protocol):
-
📡 Defines the rules for transferring data between the client and server over the internet.
-
📤
Clients send HTTP requests
tothe server
, which processes them andsends back HTTP responses
. -
🔄 Supports various request methods
(GET, POST, PUT, DELETE, etc.)
for different types of interactions. -
🔒 Can be secured using HTTPS (HTTP Secure) to encrypt data transmission and enhance security.
When a client sends an HTTP request to a server, it includes a
request method (GET, POST, etc.), headers, and optional data
. The server processes the request and generates anHTTP response
, including astatus code, headers, and optional data
. The response is sent back to the client, indicating success or failure of the request.-
GET Request:
- Used to request data from a server, data is sent in the URL, typically used for retrieving data.
-
POST Request:
- Used to submit data to a server, data is sent in the request body, typically used for submitting data.
-
-
// Example of a GET request using Fetch API
fetch('https://api.example.com/products?category=electronics')
.then(response => {
return response.json();
})
.then(data => {
// Process the retrieved data
console.log('Products:', data);
})
// Example of a POST request using Fetch API
const formData = new FormData();
formData.append('username', 'exampleuser');
formData.append('password', 'secretpassword');
fetch('https://api.example.com/login', {
method: 'POST',
body: formData
})
.then(response => {
return response.json();
})
.then(data => {
// Handle successful login response
console.log('Login successful:', data);
})
📚 Documentation:
- 📖 Comprehensive documentation of APIs, endpoints, data models, and system architecture is essential for development, maintenance, and collaboration.
- 🧩 Helps developers understand how to interact with the server, integrate with client applications, and troubleshoot issues effectively.
Having both client-side and server-side code is essential for building a functional web application that can perform CRUD operations and provide a seamless user experience.
-
🖥️ Client-Side Code (
NoteForm.jsx
):- This code runs in the user's web browser.
- It's responsible for
rendering the user interface
(UI) elements, such as forms and input fields, allowing users to interact with the application. - In the context of note-taking application, the client-side code displays forms for creating and editing notes, allows users to input note data, and
sends requests to the server to perform CRUD operations
on notes.
-
🌐 Server-Side Code (
server.js
):- This code runs on a
server
and handlesHTTP requests
from the client-side
code. - It's responsible for implementing the
backend logic
of the application, includinghandling incoming requests, interacting with a database, and sending responses back to the client
. - In the context of note-taking application, the
server-side code provides API endpoints
the client-side code can interact with to perform CRUD operations on notes
.
For example, it includesroutes
forcreating, reading, updating, and deleting
notes in a database.
- This code runs on a
Together, the client-side and server-side code work together to create a complete web application👇🏻:
- The
client-side
code provides theuser interface
and handlesuser interactions
. 💻👩💻 - The
server-side
code provides the backend logic anddata storage
capabilities. 🖥️🔧 - When a user interacts with the client-side UI (e.g., submits a form to create or update a note), the client-side code
sends an HTTP request
to the server. 📡📤 - The
server-side
codereceives the request
,performs the necessary operations
(such as updating a note in the database), andsends a response back to the client-side
code.🛠️🔍 - The client-side code
then updates the UI based on the response
received from the server. 🔄🖼️
In a typical React application, HTTP requests for CRUD operations are commonly managed within a centralized service layer or within the component that handles the data management.
const router = express.Router();
// GET all notes
// Handle GET request from client -
// defines a route for handling GET requests to the root URL ("/").
// When a client sends a GET request to the server, the server retrieves a collection named "notes" from a database
// converts the results to an array, and then sends the array of notes back to the client as the response with a status code of 200 (OK).
router.get("/", async (req, res) => {
let collection = await db.collection("notes"); // Access "notes" collection from database
let results = await collection.find({}).toArray(); // Retrieve all notes from the collection and convert them to an array
res.send(results).status(200); // Send the array of notes as a response with status 200 (OK)
});
// GET a single note by id
router.get("/:id", async (req, res) => {
...
}
// Create a new note
router.post("/", async (req, res) => {
...
}
// Update a note by id - related to the `useEffect` hook in the client-side `NoteForm.jsx` component
router.patch("/:id", async (req, res) => {
...
}
// Delete a note by id
router.delete("/:id", async (req, res) => {
...
}
export default function NoteForm() {
const [form, setForm] = useState({ title: "", content: "" });
const [notes, setNotes] = useState([]);
const params = useParams(); // Access parameters from the URL
const navigate = useNavigate(); // Access navigation function for programmatic navigation
// Request to fetch a single note from the server by its ID
useEffect(() => {
// Fetch note by id
async function fetchNote() {
const id = params.id?.toString() || undefined; // Fetch note by ID from the server
if(!id) return; // If no ID is present, do nothing
// sends a GET request to the server -
// using the fetch API to make an HTTP request to a server running locally on http://localhost:5050.
// The URL it's fetching corresponds to a specific note identified by params.id, which is converted to a string.
// This code sends a GET request to the server to retrieve information about the specific note.
const response = await fetch(
`http://localhost:5050/note/${params.id.toString()}`
);
if (!response.ok) {
const message = `An error has occurred: ${response.statusText}`;
console.error(message);
return;
}
const note = await response.json(); // Parse response as JSON
if (!note) { // If note is not found, log warning and navigate to home page
console.warn(`Note with id ${params.id} not found`);
navigate("/");
return;
}
setForm(note);
}
fetchNote();
}, [params.id, navigate]); // Fetch note when the component mounts and when the id changes in the URL
-
🌐 Server-Side Operation (server.js):
server.js
typically represents the server-side code of a web application.- It hosts the RESTful API endpoints (like
/note
) and handles requests from clients. - In the provided context,
server.js
contains API routes for CRUD operations on notes stored in a database. - These routes are accessed by the client-side code (e.g.,
NoteForm.jsx
) via HTTP requests (GET, POST, PATCH, DELETE). - The route
router.patch("/:id", async (req, res) => { ... })
inserver.js
handles PATCH requests
toupdate
a note by its ID. - It
receives
the updated note data (title and content) from theclient-side request body
(req.body
). - Inside this route handler, the server
updates
the corresponding notein the database
based on the provided note ID (req.params.id
) and the update data (req.body.title
andreq.body.content
).
-
🖥️ Client-Side Operation (NoteForm.jsx):
NoteForm.jsx
represents a React component used in the client-side code of a web application.- It interacts with users, rendering forms for creating and editing notes.
- It
sends HTTP requests to the server
(via the API endpoints defined in server.js
) to perform CRUD operations on notes. - For example, when a
user submits a form
to create or update a note,NoteForm.jsx
sends a POST or PATCH request to the server's
'/note' endpoint`. - The
useEffect
hook inNoteForm.jsx
is responsible forfetching a single note
from theserver
by its ID when the component mounts or when the note ID changes in the URL. - This hook
sends a PATCH request
to theserver
to update a specific note. It sends the updated note data (title and content) as part of the request body.
In summary, server.js
and NoteForm.jsx
work together within a client-server architecture to enable the creation, retrieval, updating, and deletion of notes in a web application.
Therefore, when the NoteForm.jsx
component in the client-side makes a PATCH request to update a note, it's handled by the corresponding route in the server.js
file, which updates the note's data in the database accordingly.