- Introduction to Web Development
- Backend Development Essentials
- APIs and HTTP Methods
- Setting Up Node.js and Express.js
- Creating and Testing a Basic REST API
- HTTP Status Codes and Error Handling
- Working with Data Formats (JSON)
-
Web Statistics: There are over 2 billion websites in existence, but only around 400 million of them are actively maintained. This shows the huge demand for web development and ongoing maintenance of online systems.
-
Why Learn Web Development?: In today’s digital world, web development skills are essential. By learning both frontend and backend technologies .
-
Frontend: referring to everything users interact with directly in their browser. It includes elements like layouts, fonts, colors, buttons (client side).
-
Backend: The part of the application that handles data storage, application logic, and communication between the frontend and database (server side).
-
Frontend Technologies:
- HTML: Structures the content on the web page.
- CSS: Styles the web page content (colors, layout, fonts).
- JavaScript: Adds interactivity and dynamic functionality to web pages.
-
Backend Technologies:
- PHP
- javascript
- Python
- go
- Rust
JavaScript was originally created to run in the browser, allowing web developers to create interactive, dynamic user interfaces.
- Definition: An API is a set of rules and protocols that allows different software applications to communicate with each other.
- RESTful API: This is a architecture for designing networked applications. It uses standard HTTP methods to perform CRUD operations on resources.
- GET: Retrieves data.
- POST: Submits data for creation.
- PUT: Updates data.
- DELETE: Removes data.
-
Request:
GET http://company.com/api/v2/users HTTP1.1
This fetches a list of users. another example
-
Response:
HTTP/1.1 200 OK Content-Type: application/json [ { "name": "Ahmed", "age": 10, "city": "Tiziouzou" }, { "name": "Achraf", "age": 20, "city": "Khenchela" }, { "name": "Bodja", "age": 30, "city": "setif" } ]
The server responds with a
200 OK
status and the data in JSON format.
To interact with APIs, developers commonly use tools that help in making requests, viewing responses, and debugging:
- Postman: A popular tool for testing APIs, allowing users to send HTTP requests and view responses in a user-friendly interface.
- cURL: A command-line tool for making HTTP requests, often used in terminal-based workflows.
- Thunder Client: A lightweight API testing extension for Visual Studio Code, providing an easy-to-use interface for making requests, viewing responses, and organizing API collections without leaving the code editor.
Task 1:
Use the provided URL to make a GET
request. This request should retrieve data from the specified endpoint. Try using tools like Postman or writing code to complete this task.
endpoints
-
Server: A server listens for incoming requests from clients or frontend.
-
Database: A database is used to store and manage data. Popular databases include MySQL, MongoDB, and PostgreSQL. These databases interact with the backend server to retrieve, modify, and store data.
- Node.js: Node.js is a JavaScript runtime that enables JavaScript to run on the server-side (outside the browser). Originally, JavaScript could only run in a browser, but Node.js makes it possible to use it on your machine.
For a brief overview of JavaScript, click here: Link text Here
Task 2:
- Declare two variables,
a
andb
, with values 10 and 20, respectively. - Declare a constant variable
name
. - Use
console.log()
to:- Output the values of
a
andb
. - Print "Hello World!".
- Print the sum:
result of a + b = 30
.
- Output the values of
Task 2 Solution
// Declare variables
let a = 10;
let b = 20;
const name = "Your Name";
// Output the values of `a` and `b`
console.log("Value of a:", a);
console.log("Value of b:", b);
// Print "Hello World!"
console.log("Hello World!");
// Print the sum of `a` and `b`
console.log(`Result of a + b = ${a + b}`);
- Express.js: Express is framework that simplifies backend development. It provides tools to handle HTTP requests, routing, and middleware functions, making it easier to build scalable and maintainable web applications.
-
Purpose of
package.json
: Thepackage.json
file holds metadata about your project, including its dependencies (libraries and frameworks), scripts, and project settings.- To create
package.json
, use:This initializes a new Node.js project.npm init
- To install Express, use:
npm install express
- To create
-
Initialize the Project:
- In your project directory, run:
This will create a
npm init -y
package.json
file.
- In your project directory, run:
-
Install Express:
- Install Express with:
npm install express
- Install Express with:
-
Create a Basic Server:
-
In the root directory, create a file named
server.js
(orapp.js
). -
Add the following code to set up the basic server:
const express = require('express'); const app = express(); const PORT = 3000; // Basic route for the root URL (localhost:3000) app.get('/', (req, res) => { res.send('Hello World!'); }); // Start the server and listen on the specified port app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); });
-
why we use spcfic port
-
and why we use listen
-
-
Run the Server:
- In your terminal, start the server by running:
node server.js
- You should see the message:
Server is running on http://localhost:3000
.
- In your terminal, start the server by running:
-
Test the Server:
- Open a browser or use a tool like cURL, Postman, or Thunder Client to make requests to:
http://localhost:3000/
to see "Hello World!"
- Open a browser or use a tool like cURL, Postman, or Thunder Client to make requests to:
This basic server is set up to handle GET requests and respond with simple text.
Task 3:
- Create a simple Express app.
- Define two GET routes:
/
: Respond with "Hello World!"/api
: Respond with "Hello from another world!"
- Make the app listen on port
3000
and log a success message when the server starts.
Task 3 Solution:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.get('/api', (req, res) => {
res.send('Hello from another world!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
- Purpose: HTTP status codes are three-digit numbers sent by the server to indicate the result of the request. They help clients understand if their request was successful, failed, or if further action is required.
- 1xx: Informational responses (e.g.,
100 Continue
) - 2xx: Success (e.g.,
200 OK
,201 Created
) - 3xx: Redirection (e.g.,
301 Moved Permanently
) - 4xx: Client errors (e.g.,
400 Bad Request
,404 Not Found
) - 5xx: Server errors (e.g.,
500 Internal Server Error
)
Key Status Codes:
200 OK
: The request was successful.201 Created
: A new resource was created successfully.400 Bad Request
: The request was malformed or invalid.404 Not Found
: The requested resource could not be found.500 Internal Server Error
: There was a server error while processing the request.
Task 4:
- Configure routes to return different HTTP status codes:
GET /
: return200 OK
with "Hello World"POST /
: return201 Created
GET /bad
: return400 Bad Request
GET /not-found
: return404 Not Found
GET /error
: return500 Internal Server Error
Task 4 Solution:
// read
app.get("/", (req, res) => {
res.status(200).send("Hello World");
})
// create
app.post("/", (req, res) => {
res.status(201).send("Hello World");
})
// Bad Request
app.get("/bad", (req, res) => {
res.status(400).send("Bad Request");
})
// Not Found
app.get("/not-found", (req, res) => {
res.status(404).send("Not Found");
})
// Internal Server Error
app.get("/error", (req, res) => {
res.status(500).send("Internal Server Error");
})
-
Purpose: Data formats like JSON and XML are used to structure data in a way that can be easily transmitted over the internet and processed by both clients and servers.
-
Popular Formats:
- JSON: JavaScript Object Notation. A lightweight, human-readable format for transmitting data.
- XML: eXtensible Markup Language. A markup language that defines rules for encoding documents in a format that is both human-readable and machine-readable.
-
Example JSON:
{ "name": "John Doe", "age": 30, "city": "New York" }
-
Example XML:
<person> <name>John Doe</name> <age>30</age> <city>New York</city> </person>
Task 5:
- Add the /cars Route define a new GET route for /cars that responds with JSON data.
Task 5 solution:
let cars = [
{ id: 1, make: "Toyota", model: "Corolla", year: 2020 },
{ id: 2, make: "Honda", model: "Civic", year: 2021 },
];
// READ: Get all cars
app.get("/cars", (req, res) => {
res.status(200).json(cars);
});
- Recap of Key Concepts from Session 01
- Key Terms and Definitions (URL Structure)
- Middleware 'task'
- Params vs. Query Strings 'task'
- CRUD opration 'task'
fromat of the request:
POST https://example.com/api/v1/users
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
content-type: application/json
accept: application/json
{
"name": "Juan",
"password": "123456"
}
fromat of the response:
HTTP 201 Created
content-type: application/json
Content-Length: 100
{
"msg": "User createdsuccessfully"
}
Task 1:
Create an API endpoint that logs (print) request details including IP address, User-Agent, HTTP method, URL path, and Accept and return as response 'welcome'
Task 1 solution:
app.get("/", (req, res) => {
const ip = req.ip;
const userAgent = req.get("User-Agent");
const method = req.method;
const path = req.originalUrl;
const Accept = req.get("Accept");
console.log(`************************************`);
console.log(`IP: ${ip}`);
console.log(`User-Agent: ${userAgent}`);
console.log(`Method: ${method}`);
console.log(`Path: ${path}`);
console.log(`Accept-Content: ${Accept}`);
console.log(`************************************`);
res.status(200).send("Welcome");
});
https://example.com/api/users
A URL (Uniform Resource Locator) consists of the following components:
-
Protocol: Defines the communication method (e.g.,
http
,https
).- Example:
https://
- Example:
-
Domain Name: Identifies the website (e.g.,
example.com
).- Example:
example.com
- Example:
-
Path: Refers to the resource's location on the server.
- Example:
/api/users
- Example:
Endpoints are specific paths on the server that are associated with particular HTTP methods (GET, POST, PUT, DELETE, etc.) to perform different actions on the resources.
Another definition: An API endpoint is a URL that serves as the point of interaction between an API client and an API server. API clients make requests to these endpoints to access the functionality and data provided by the API.
GET /api/users
- Retrieves a list of all users from the server.
- Example URL:
https://example.com/api/users
GET /api/users/{id}
- Retrieves details of a specific user based on their ID.
- Example URL:
https://example.com/api/users/1
We need to know the User-Agent, IP address, HTTP method, URL, and Accept-Type in all endpoints of the application.
app.get('/users', (req, res) => {
res.send('Users list');
});
app.get('/posts', (req, res) => {
res.send('Posts list');
});
app.get('/products', (req, res) => {
res.send('Posts list');
});
app.get('/users', (req, res) => {
console.log(`User-Agent: ${req.get('User-Agent')}`);
console.log(`IP Address: ${req.ip}`);
console.log(`Method: ${req.method}`);
console.log(`URL: ${req.originalUrl}`);
console.log(`Accept-Type: ${req.get("Accept")}`);
res.send('Users list');
});
app.get('/posts', (req, res) => {
console.log(`User-Agent: ${req.get('User-Agent')}`);
console.log(`IP Address: ${req.ip}`);
console.log(`Method: ${req.method}`);
console.log(`URL: ${req.originalUrl}`);
console.log(`Accept-Type: ${req.get("Accept")}`);
res.send('Posts list');
});
This solution is incorrect because it repeats the logging code in every route handler.
Middleware is software or functions that act as intermediaries between different components of an application.
In the context of Express, middleware functions handle HTTP requests before they reach route handlers, which allows you to perform common tasks (like logging) for all routes.
Middleware in Express typically has the following structure:
const middlewareName = (req, res, next) => {
// Your middleware logic here
next(); // Pass control to the next middleware or route handler
};
// for pass the middlware in all routes
app.use(middlewareName())
Instead of repeating the logging code in every route, we can write a middleware function that logs the required details for all incoming requests, no matter the endpoint.
const express = require('express');
const app = express();
const logRequestDetails = (req, res, next) => {
console.log(`User-Agent: ${req.get('User-Agent')}`);
console.log(`IP Address: ${req.ip}`);
console.log(`Method: ${req.method}`);
console.log(`URL: ${req.originalUrl}`);
console.log(`Accept-Type: ${req.get("Accept")}`);
next();
};
app.use(logRequestDetails); // Apply this middleware to all routes
// Define routes
app.get('/users', (req, res) => {
res.send('Users list');
});
app.get('/posts', (req, res) => {
res.send('Posts list');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
- Write a middleware to log the current date and time for every incoming request. 'to get current time 'new Date().toLocaleString()' '
const logDateTime = (req, res, next) => {
const currentDate = new Date().toLocaleString();
console.log(`Request received at: ${currentDate}`);
next();
};
app.use(logDateTime);
app.get('/', (req, res) => {
res.send('Hello, Middleware with Date and Time!');
});
The following implementation creates a separate route for each user, which is inefficient and hard to maintain.
let users = [
{ id: 1, name: "user-1233" },
{ id: 2, name: "user-1652" },
{ id: 3, name: "user-1533" },
{ id: 4, name: "user-1453" },
];
app.get('/', (req, res) => {
res.status(200).send('Test your API!');
});
app.get("/api/users", (req, res) => {
res.status(200).json(users);
});
app.get("/api/users/1", (req, res) => {
res.status(200).json(users[0]);
});
app.get("/api/users/2", (req, res) => {
res.status(200).json(users[1]);
});
app.get("/api/users/3", (req, res) => {
res.status(200).json(users[2]);
});
app.get("/api/users/4", (req, res) => {
res.status(200).json(users[3]);
});
What are Path Parameters?
- Included directly in the URL path to make routes dynamic.
- Useful for accessing specific resources.
- Example:
/api/users/:id
- URL:
/api/users/123
- Accessed in code as
req.params.id
.
- URL:
By using URL parameters, we can create a single dynamic route to handle user retrieval.
app.get('/', (req, res) => {
res.status(200).send('Test your API!');
});
app.get("/api/users", (req, res) => {
res.status(200).json(users);
});
let users = [
{ id: 1, name: "user-1233" },
{ id: 2, name: "user-1652" },
{ id: 3, name: "user-1533" },
{ id: 4, name: "user-1453" },
];
app.get("/api/users/:id", (req, res) => {
const id = req.params.id;
const user = users[id]
if (!user) {
return res.status(404).send("User not found");
}
res.status(200).json(user);
});
Query parameters are used to pass additional information to the server and are added to the URL after a ?
.
- Example:
/api/users?name=John&age=30
- Accessed in code as
req.query
.
Common use cases:
-
Searching
-
Sorting
app.get('/users', (req, res) => { const { name } = req.query; // Extract the 'name' query parameter const filteredUsers = users.filter((user) => user.name === name); res.status(200).json(filteredUsers); })
Create an API endpoint to accept both path parameters and query and send them as a response as json format.
Here is the implementation where we combine both path parameters and query strings and send them as a response.
app.get('/api/:id', (req, res) => {
const id = req.params.id; // Path parameter
const queryParams = req.query; // Query parameters
res.status(200).json({
pathParam: req.params, // Path parameter
queryParams: queryParams, // Query parameters
});
});
CRUD stands for:
- Create: Adding new data (
POST
). - Read: Retrieving data (
GET
). - Update: Modifying existing data (
PUT
orPATCH
). - Delete: Removing data (
DELETE
).
const express = require('express');
const app = express();
app.use(express.json()); // Middleware to parse JSON data
let users = [];
// Create
app.post('/users', (req, res) => {
const user = req.body;
users.push(user);
res.status(201).send(user);
});
// Read
app.get('/users', (req, res) => {
res.status(200).send(users);
});
// Update
app.put('/users/:id', (req, res) => {
const { id } = req.params;
const updatedUser = req.body;
users = users.map(user => (user.id === parseInt(id) ? updatedUser : user));
res.send(updatedUser);
});
// Delete
app.delete('/users/:id', (req, res) => {
const { id } = req.params;
users = users.filter(user => user.id !== parseInt(id));
res.send(`User with ID ${id} deleted.`);
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Task:
- Build a CRUD API for managing a list of tasks. Each task should have an
id
,title
, andisCompleted
status.