Skip to content

F0DH1L/backend_workshop

Repository files navigation

Welcome to the Backend Development Workshop

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!

1. Introduction to Backend Development

  • 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.


2. How the web works ?

  • 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

diagram


3. What is an API?

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 data
    • POST: Add new data
    • PUT/PATCH: Update existing data
    • DELETE: Remove data

4. Hands-On Practice

Installation Check: Ensure node js and Postman are installed

Step 1: Project Setup

mkdir demo_app && cd demo_app
npm init -y
npm install express

Step 2: Hello World Endpoint

const 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}`);
});

Run with

node server.js

and Test http://localhost:3000 in Postman or a browser.

Create a simple GET endpoint

GET All Tasks

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' });
    }
});

Step 3: Add a Database (SQLite)

Use sqlite3 to create a books table.

CRUD Operations: Write routes to add/fetch books.

npm install sqlite3
const 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'
    )
  `);
});

Step 4: POST and GET Endpoints

1/GET All Tasks

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);
  });
});

2/POST a new task

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'
      });
    }
  );
});

3/GET a Single Task by ID

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);
  });
});

4/PUT Update Task Status

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 });
    }
  );
});

5/DELETE a task

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!' });
    }
  );
}); 

5. Using an ORM :

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.

1/ Project Setup with Prisma

npm install @prisma/client
npm install prisma --save-dev

# Initialize Prisma with SQLite (or change provider in schema)
npx prisma init --datasource-provider sqlite

2/ Define Prisma Schema

generator 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.db

3/ Create Database & Generate Client

npx prisma migrate dev --name init
npx prisma generate  # Generates Prisma Client

4/ update the express server

const 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}`);
});

6. Next Steps

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.


7. Contact

EMAIL: f.benhiba@esi-sba.dz Personal Website: https://fodhil-benhiba.vercel.app

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published