Welcome, this workshop was organized by Alphabit Club. In this workshop, we'll explore the fundamentals of building server-side applications, understand the key components of backend architecture, and get hands-on practice. If you're just starting out, this workshop is designed to give you practical insights and tools to kickstart your journey. Let's dive in!
- What is Backend Development?
It is the part of the application where the server and database reside and the logics is build to perform operations. It includes the main features and functionalities of the application on the server.
- Client-Server Model
- How browsers (clients) communicate with servers via HTTP/HTTPS
- Components of a Backend System
Explain request-response cycle (use a diagram here):- Web Server: Handles requests and responses
- Application Server: Runs business logic
- Database: Stores and retrieves data
- APIs: Act as the intermediary between the client and server
An API is a type of software interface, offering a service to other pieces of software.
- Examples: REST, GraphQL, gRPC, SOAP
- What is REST API
- RESTful principles: endpoints, HTTP methods (GET/POST/PUT/DELETE)
GET: Retrieve dataPOST: Add new dataPUT/PATCH: Update existing dataDELETE: Remove data
Installation Check: Ensure node js and Postman are installed
mkdir demo_app && cd demo_app
npm init -y
npm install expressconst express = require('express');
const app = express();
const port = 3000;
// Middleware to parse JSON requests
app.use(express.json());
// Root endpoint
app.get('/', (req, res) => {
res.send('Hello World!');
});
// Start the server
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});node server.jsand Test http://localhost:3000 in Postman or a browser.
Create a simple GET endpoint
const tasks = [
{
'id': 1,
'title': 'do homework',
},
{
'id': 2,
'title': 'go to the gym',
},
{
'id': 3,
'title': 'clean the room',
},
{
'id': 4,
'title': 'wash dishes',
},
]
app.get('/tasks', (req, res) => {
if (tasks){
res.json(tasks);
}
else{
res.status(404).json({ error: 'no tasks found' });
}
});Use sqlite3 to create a books table.
CRUD Operations: Write routes to add/fetch books.
npm install sqlite3const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('tasks.db');
// Create tasks table
db.serialize(() => {
db.run(`
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
description TEXT,
status TEXT DEFAULT 'pending'
)
`);
});app.get('/tasks', (req, res) => {
db.all('SELECT * FROM tasks', (err, tasks) => {
if (err) {
res.status(500).json({ error: err.message });
return;
}
res.json(tasks);
});
});app.post('/tasks', (req, res) => {
const { title, description } = req.body;
if (!title) {
return res.status(400).json({ error: 'Title is required!' });
}
db.run(
'INSERT INTO tasks (title, description) VALUES (?, ?)',
[title, description],
function (err) {
if (err) {
res.status(500).json({ error: err.message });
return;
}
res.status(201).json({
id: this.lastID,
title,
description,
status: 'pending'
});
}
);
});app.get('/tasks/:id', (req, res) => {
const { id } = req.params;
db.get('SELECT * FROM tasks WHERE id = ?', [id], (err, task) => {
if (err) {
res.status(500).json({ error: err.message });
return;
}
if (!task) {
return res.status(404).json({ error: 'Task not found!' });
}
res.json(task);
});
});app.put('/tasks/:id', (req, res) => {
const { id } = req.params;
const { status } = req.body;
// Validate allowed statuses
const allowedStatuses = ['pending', 'in-progress', 'completed'];
if (!allowedStatuses.includes(status)) {
return res.status(400).json({ error: 'Invalid status!' });
}
db.run(
'UPDATE tasks SET status = ? WHERE id = ?',
[status, id],
(err) => {
if (err) {
res.status(500).json({ error: err.message });
return;
}
res.json({ id, status });
}
);
});app.delete('/tasks/:id', (req, res) => {
const { id } = req.params;
db.run(
'DELETE FROM tasks WHERE id = ?',
[id],
function (err) {
if (err) {
res.status(500).json({ error: err.message });
return;
}
// Check if any task was deleted
if (this.changes === 0) {
return res.status(404).json({ error: 'Task not found!' });
}
res.json({ message: 'Task deleted successfully!' });
}
);
}); An ORM is a programming tool that lets you interact with your database using objects and methods instead of writing raw SQL queries. Additionally, ORMs often include safeguards against common errors and security issues like SQL injection, making it a practical alternative to writing raw SQL manually.
npm install @prisma/client
npm install prisma --save-dev
# Initialize Prisma with SQLite (or change provider in schema)
npx prisma init --datasource-provider sqlitegenerator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL") // Default: file:./dev.db
}
model Task {
id Int @id @default(autoincrement())
title String
description String?
status String @default("pending")
createdAt DateTime @default(now())
}add .env file
DATABASE_URL=file:./tasks.dbnpx prisma migrate dev --name init
npx prisma generate # Generates Prisma Clientconst express = require('express');
const {PrismaClient} = require('@prisma/client')
const prisma = new PrismaClient()
const app = express();
const port = 3000;
app.use(express.json());
// Get all tasks (with optional status filter)
app.get('/tasks', async (req, res) => {
try {
const { status } = req.query;
const whereClause = status ? { status } : {};
const tasks = await prisma.task.findMany({ where: whereClause });
res.json(tasks);
} catch (err) {
console.log(err.message)
res.status(500).json({ error: err.message });
}
});
// Create a task
app.post('/tasks', async (req, res) => {
try {
const { title, description } = req.body;
const task = await prisma.task.create({
data:{
title,
description
}
}
);
res.status(201).json(task);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// Get a single task by ID
app.get('/tasks/:id', async (req, res) => {
try {
const task = await prisma.task.findUnique(
{
where: {
id: Number(req.params.id)
}
}
);
if (!task) {
return res.status(404).json({ error: 'Task not found!' });
}
res.json(task);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Update task status
app.put('/tasks/:id', async (req, res) => {
try {
const taskFound = await prisma.task.findUnique(
{
where: {
id: Number(req.params.id)
}
}
);
if (!taskFound) {
return res.status(404).json({ error: 'Task not found!' });
}
const task = await prisma.task.update({
where:{
id: Number(req.params.id)
},
data:{
status: req.body.status
}
}
);
res.json(task);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// Delete a task
app.delete('/tasks/:id', async (req, res) => {
try {
const deleted = await prisma.task.delete({
where: { id: Number(req.params.id) },
});
if (!deleted) {
return res.status(404).json({ error: 'Task not found!' });
}
res.json({ message: 'Task deleted!' });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});Learning a backend language and framework in depth.
Database design and management.
API design principles.
Security best practices (authentication, authorization).
Deployment and scaling.
Practice with small projects (building a simple blog, a task manager).
Resources: Documentation, tutorials, online courses, communities.
EMAIL: f.benhiba@esi-sba.dz Personal Website: https://fodhil-benhiba.vercel.app
