<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ajor</title>
    <description>The latest articles on DEV Community by Ajor (@ajor-saha).</description>
    <link>https://dev.to/ajor-saha</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1146082%2Fbe280bd3-19f4-4c2e-9fd9-3d92b8f39ce9.jpeg</url>
      <title>DEV Community: Ajor</title>
      <link>https://dev.to/ajor-saha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ajor-saha"/>
    <language>en</language>
    <item>
      <title>Deploying Your AI/ML Models: A Practical Guide from Training to Production</title>
      <dc:creator>Ajor</dc:creator>
      <pubDate>Tue, 23 Dec 2025 17:47:41 +0000</pubDate>
      <link>https://dev.to/ajor-saha/deploying-your-aiml-models-a-practical-guide-from-training-to-production-2fg3</link>
      <guid>https://dev.to/ajor-saha/deploying-your-aiml-models-a-practical-guide-from-training-to-production-2fg3</guid>
      <description>&lt;p&gt;In the fast-evolving world of AI and machine learning, training models is just the beginning. To make your research impactful, you need to deploy them so others can interact with your work—whether it's for real-world applications, demos, or further experimentation. This tutorial focuses on a streamlined workflow for deploying ML/deep learning models to the cloud, wrapped in a user-friendly API. We'll keep things general so you can apply this to any AI/ML project, but I'll use my own computer vision research on fish species classification as a concrete example.&lt;/p&gt;

&lt;h3&gt;
  
  
  The process breaks down into these key steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Train your model on a platform like Kaggle.&lt;/li&gt;
&lt;li&gt;Download the trained model.&lt;/li&gt;
&lt;li&gt;Wrap the model in a FastAPI application for API access.&lt;/li&gt;
&lt;li&gt;Dockerize the app for easy portability.&lt;/li&gt;
&lt;li&gt;Deploy to the cloud.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end, you'll have a production-ready setup that lets users interact with your model via simple HTTP requests. Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Workflow?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Training on Kaggle: Free GPUs/TPUs, easy dataset management, and version control for notebooks.&lt;/li&gt;
&lt;li&gt;FastAPI: Modern, fast, and auto-generates interactive docs (Swagger UI) for your API.&lt;/li&gt;
&lt;li&gt;Docker: Ensures consistency across environments.&lt;/li&gt;
&lt;li&gt;Cloud Deployment: Scalable, accessible from anywhere.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This setup is ideal for researchers: Train once, deploy anywhere, and focus on innovation rather than infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagram: High-Level Workflow
&lt;/h2&gt;

&lt;p&gt;Here's a simple flowchart of the process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1rq3m3ci8lqm0b93kuv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1rq3m3ci8lqm0b93kuv.png" alt="Flow-Chart" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Training Your Model on Kaggle
&lt;/h2&gt;

&lt;p&gt;Kaggle is perfect for training, especially for compute-intensive tasks like computer vision. It handles datasets, notebooks, and hardware for free.&lt;br&gt;
General Steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload or Find a Dataset: Go to Kaggle Datasets and upload your data or use an existing one. Ensure it's structured (e.g., images in folders by class for classification).&lt;/li&gt;
&lt;li&gt;Create a Notebook: Start a new notebook in Kaggle Notebooks.&lt;/li&gt;
&lt;li&gt;Install Libraries: Use !pip install for any extras (e.g., timm for transformers).&lt;/li&gt;
&lt;li&gt;Load and Preprocess Data: Use libraries like PyTorch or TensorFlow.&lt;/li&gt;
&lt;li&gt;Train Models: Experiment with architectures. Save the best model using torch.save or similar.&lt;/li&gt;
&lt;li&gt;Version and Run: Commit your notebook to save versions. Run it with GPU/TPU acceleration.&lt;/li&gt;
&lt;li&gt;Output Artifacts: Save models, weights, and metadata (e.g., class labels as JSON).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Example: Fish Species Classification
&lt;/h2&gt;

&lt;p&gt;For my research, I used a dataset of fish images (e.g., from Kaggle's "Fish Species" datasets). I trained computer vision models like DeiT (Data-efficient Image Transformer), ViT (Vision Transformer), and VGG16.&lt;/p&gt;

&lt;p&gt;Dataset: ~12,000 images across 32 fish species&lt;br&gt;
&lt;strong&gt;Models Trained:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DeiT: Lightweight transformer, great for efficiency.&lt;/li&gt;
&lt;li&gt;ViT: Standard vision transformer for baseline.&lt;/li&gt;
&lt;li&gt;VGG16: CNN classic for comparison.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 2: Downloading the Trained Model
&lt;/h2&gt;

&lt;p&gt;Once training is done:&lt;/p&gt;

&lt;p&gt;In your Kaggle notebook, commit and run to generate outputs.&lt;br&gt;
Go to the notebook's "Output" tab and download the files (e.g., model weights and JSON).&lt;/p&gt;

&lt;p&gt;For sharing large files, upload to Google Drive (as in my example) or GitHub.&lt;/p&gt;

&lt;p&gt;In my case, I uploaded deit_tiny_fish_model.pth to Google Drive and used its ID for downloading in the API.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Wrapping the Model with FastAPI
&lt;/h2&gt;

&lt;p&gt;Now, turn your model into an API. FastAPI is async, type-safe, and includes auto-docs.&lt;br&gt;
General Steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set Up Project: Create a folder, install deps: pip install fastapi uvicorn torch timm pillow gdown.&lt;/li&gt;
&lt;li&gt;Load Model: Handle device (CPU/GPU), download if needed.&lt;/li&gt;
&lt;li&gt;Preprocess Inputs: Match training transforms.&lt;/li&gt;
&lt;li&gt;Create Endpoints: /predict for inference, health checks, etc.&lt;/li&gt;
&lt;li&gt;Add CORS: For web apps.&lt;/li&gt;
&lt;li&gt;Run Locally: uvicorn main:app --reload.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example Code: Generalizable API Wrapper&lt;br&gt;
Here's the full code from my fish classifier, adapted to be general (replace "fish" with your domain, adjust classes/models).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
import io
import json
import numpy as np
import torch
import torch.nn as nn
from PIL import Image
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from torchvision.transforms import Compose, Resize, CenterCrop, ToTensor, Normalize
import timm
import gdown

# Define device
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

# Model configuration (customize these)
NUM_CLASSES = 32  # Your number of classes
MODEL_PATH = os.path.join(os.path.dirname(__file__), "your_model.pth")  # e.g., deit_tiny_fish_model.pth
CLASSES_PATH = os.path.join(os.path.dirname(__file__), "classes.json")

# Download model if not exists (e.g., from Google Drive)
if not os.path.exists(MODEL_PATH):
    print("Downloading model...")
    gdown.download(id="YOUR_GOOGLE_DRIVE_ID", output=MODEL_PATH, quiet=False)

# Load class names
try:
    with open(CLASSES_PATH, "r") as f:
        class_names = json.load(f)
except Exception:
    class_names = ["class1", "class2"]  # Fallback

# Initialize model (customize for your architecture)
def create_model():
    model = timm.create_model('deit_tiny_distilled_patch16_224', pretrained=False)
    model.head = nn.Linear(model.head.in_features, NUM_CLASSES)
    model.head_dist = nn.Linear(model.head_dist.in_features, NUM_CLASSES)
    return model

# Load model
model = create_model()
model.load_state_dict(torch.load(MODEL_PATH, map_location=device, weights_only=False))
model.to(device)
model.eval()

# Preprocessing (match your training)
transform = Compose([
    Resize(224),
    CenterCrop(224),
    ToTensor(),
    Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),
])

# FastAPI app
app = FastAPI(title="Your ML Model API", description="API for your AI/ML model")

# CORS
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])

# Response model
class Prediction(BaseModel):
    filename: str
    predicted_class: str
    confidence: float
    top_3_predictions: list

# Preprocess function
def preprocess_image(image: Image.Image) -&amp;gt; torch.Tensor:
    image = image.convert("RGB")
    return transform(image).unsqueeze(0).to(device)

# Health check
@app.get("/")
async def root():
    return {"message": "API is running", "classes": len(class_names)}

# Prediction endpoint
@app.post("/predict", response_model=Prediction)
async def predict(file: UploadFile = File(...)):
    try:
        if not file.content_type.startswith('image/'):
            raise HTTPException(400, "Must be an image")
        image_data = await file.read()
        image = Image.open(io.BytesIO(image_data))
        input_tensor = preprocess_image(image)
        with torch.no_grad():
            outputs = model(input_tensor)
            probabilities = torch.nn.functional.softmax(outputs, dim=1)
            confidence, predicted_idx = torch.max(probabilities, 1)
            top_3_prob, top_3_idx = torch.topk(probabilities, 3, dim=1)
        predicted_class = class_names[predicted_idx.item()]
        top_3 = [{"class": class_names[top_3_idx[0][i].item()], "confidence": top_3_prob[0][i].item()} for i in range(3)]
        return Prediction(filename=file.filename, predicted_class=predicted_class, confidence=confidence.item(), top_3_predictions=top_3)
    except Exception as e:
        raise HTTPException(500, f"Error: {str(e)}")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For my fish example, this API takes an image upload and returns the species with confidence. Test it locally: Upload an image to /predict via tools like Postman or the Swagger UI at /docs&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagram: API Flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4fv78s019117zlgj6fh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4fv78s019117zlgj6fh.jpg" alt="User-Flow" width="800" height="114"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Dockerizing the API
&lt;/h2&gt;

&lt;p&gt;Containerize for easy deployment.&lt;br&gt;
&lt;strong&gt;General Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Dockerfile and requirements.txt (list deps like fastapi, torch, etc.).&lt;/li&gt;
&lt;li&gt;Build: docker build -t your-app .&lt;/li&gt;
&lt;li&gt;Run Locally: docker run -p 8000:8000 your-app&lt;/li&gt;
&lt;li&gt;Push to Registry: e.g., Docker Hub.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example Dockerfile:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3.9-slim

WORKDIR /app

RUN apt-get update &amp;amp;&amp;amp; apt-get install -y git curl &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir gdown

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Deploying to Render or Railway
&lt;/h2&gt;

&lt;p&gt;Both Render and Railway are excellent for deploying ML models due to their simplicity and free tiers. I’ll outline steps for both, as they’re similar but have slight differences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Diagram: Deployment Pipeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanvv0258u6w0w89bwd6p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanvv0258u6w0w89bwd6p.jpg" alt="Deploy-Flow" width="800" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This workflow makes deploying AI/ML models straightforward, letting you focus on research. For my fish classification, it turned a Kaggle notebook into a live API in hours. Adapt it to your project—swap models, datasets, or endpoints as needed. If you build something cool, share it!&lt;br&gt;
Questions? Drop a comment below. Happy deploying! 🚀&lt;/p&gt;

</description>
      <category>ai</category>
      <category>fastapi</category>
      <category>computervision</category>
      <category>deeplearning</category>
    </item>
    <item>
      <title>Setting Up a Backend with Prisma, Express, and PostgreSQL</title>
      <dc:creator>Ajor</dc:creator>
      <pubDate>Wed, 03 Jul 2024 19:03:33 +0000</pubDate>
      <link>https://dev.to/ajor-saha/setting-up-a-backend-with-prisma-express-and-postgresql-482e</link>
      <guid>https://dev.to/ajor-saha/setting-up-a-backend-with-prisma-express-and-postgresql-482e</guid>
      <description>&lt;p&gt;Hi,&lt;br&gt;
In this post, I will go through the steps of setting up a backend using Prisma, Express, and PostgreSQL. We will cover the installation, configuration, and implementation of a REST API and basic CRUD operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Node.js installed on your machine&lt;/li&gt;
&lt;li&gt;PostgreSQL installed and running&lt;/li&gt;
&lt;li&gt;Basic understanding of JavaScript and SQL&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Initialize the Project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, create a new directory for your project and navigate into it. Then, initialize a new Node.js project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir my-backend
cd my-backend
npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 2: Install Dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Install the necessary dependencies for Express and other packages&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express bcryptjs jsonwebtoken dotenv cookie-parser
npm install -D nodemon

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 3: Set Up Prisma&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install prisma --save-dev
npx prisma init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 4: Configure PostgreSQL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Update your .env file with your PostgreSQL database connection URL.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL="postgresql://postgres:jondoe@localhost:5432/backendprisma?schema=public"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Update the schema.prisma file to use PostgreSQL and define your models.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id         Int       @id @default(autoincrement())
  name       String?
  email      String    @unique
  password   String?
  post Post[]
  comment Comment[]
  created_at DateTime  @default(now())
}

model Post {
  id            Int       @id @default(autoincrement())
  user          User      @relation(fields: [user_id], references: [id], onDelete: Cascade)
  comment       Comment[]
  user_id       Int
  title         String
  description   String
  comment_count Int       @default(0)
  created_at    DateTime  @default(now())
}

model Comment {
  id         String   @id @default(uuid())
  post       Post     @relation(fields: [post_id], references: [id], onDelete: Cascade)
  post_id    Int
  user       User     @relation(fields: [user_id], references: [id], onDelete: Cascade)
  user_id    Int
  comment    String
  created_at DateTime @default(now())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 5: Migrate the Database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run the following command to create the database tables based on your Prisma schema.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx prisma migrate dev --name init

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 6: Install and generate Prisma Client&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @prisma/client

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;*&lt;em&gt;Step 7: Set Up Express Server&lt;br&gt;
*&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Create an server.js file for your Express server.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "dotenv/config";
import cookieParser from "cookie-parser";
import express from "express";


const app = express();
const PORT = process.env.PORT || 4000;

// * Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

app.get("/", (req, res) =&amp;gt; {
    return res.send("Hi Everyone.");
});

// * routes file
import userRouter from "./routes/userRoutes.js"
import postRouter from "./routes/postRoutes.js"
import commentRouter from "./routes/commentRoutes.js"

app.use("/api/user", userRouter);

app.listen(PORT, () =&amp;gt; console.log(`Server is running on PORT ${PORT}`));

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;*&lt;em&gt;Step 8: Implement User Authentication&lt;br&gt;
*&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Create authentication routes and controllers.&lt;/p&gt;

&lt;p&gt;routes/userRoutes.js&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Router } from "express";
import {
    createUser,
    deleteUser,
    loginUser,
    logoutUser,
    updateUser
} from "../controllers/userController.js";
import { verifyJWT } from "../middleware/auth.middleware.js";

const router = Router();

router.post("/adduser", createUser);
router.post("/login", loginUser);
router.post("/logout", verifyJWT, logoutUser);
router.put("/update", verifyJWT, updateUser);
router.delete("/delete", verifyJWT,  deleteUser);

export default router;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;controllers/userController.js&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import prisma from "../DB/db.config.js";
import { ApiResponse } from "../utils/ApiResponse.js";
import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";

export const createUser = async (req, res) =&amp;gt; {
  const { name, email, password } = req.body;

  try {
    // Validate that all fields are provided
    if (
      [name, email, password].some((field) =&amp;gt; !field || field.trim() === "")
    ) {
      return res
        .status(400)
        .json(new ApiResponse(false, 400, {}, "All fields are required"));
    }

    // Check if the user already exists
    const findUser = await prisma.user.findUnique({
      where: {
        email: email,
      },
    });

    if (findUser) {
      return res
        .status(400)
        .json(
          new ApiResponse(
            false,
            400,
            {},
            "Email already taken. Please use another email."
          )
        );
    }

    // Hash the password
    const hashedPassword = await bcrypt.hash(password, 10);

    // Create the new user
    const newUser = await prisma.user.create({
      data: {
        name: name,
        email: email,
        password: hashedPassword,
      },
    });

    // Exclude password from the response
    const { password: _, ...userWithoutPassword } = newUser;

    return res
      .status(201)
      .json(
        new ApiResponse(
          true,
          201,
          userWithoutPassword,
          "User registered successfully"
        )
      );
  } catch (error) {
    console.error(error);
    return res
      .status(500)
      .json(new ApiResponse(false, 500, null, "Internal Server Error"));
  }
};

export const loginUser = async (req, res) =&amp;gt; {
  const { email, password } = req.body;

  try {
    // Validate that all fields are provided
    if ([email, password].some((field) =&amp;gt; !field || field.trim() === "")) {
      return res
        .status(400)
        .json(
          new ApiResponse(false, 400, {}, "Email and password are required")
        );
    }

    // Check if the user exists
    const user = await prisma.user.findUnique({
      where: {
        email: email,
      },
    });

    if (!user) {
      return res
        .status(401)
        .json(new ApiResponse(false, 401, {}, "Invalid email or password"));
    }

    // Check if the password is correct
    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) {
      return res
        .status(401)
        .json(new ApiResponse(false, 401, {}, "Invalid email or password"));
    }

    // Generate JWT access token
    const accessToken = jwt.sign(
      { userId: user.id, email: user.email },
      process.env.JWT_SECRET,
      {
        expiresIn: "1d",
      }
    );

    // Exclude password from the response
    const { password: _, ...userWithoutPassword } = user;

    // Set the access token as a cookie
    res.cookie("accessToken", accessToken, {
      httpOnly: true,
      secure: true, // Ensure secure cookies
      maxAge: 24 * 60 * 60 * 1000, // 1 day
    });

    return res
      .status(200)
      .json(
        new ApiResponse(
          true,
          200,
          { user: userWithoutPassword, accessToken },
          "Login successful"
        )
      );
  } catch (error) {
    console.error(error);
    return res
      .status(500)
      .json(new ApiResponse(false, 500, null, "Internal Server Error"));
  }
};



// update the user
export const updateUser = async (req, res) =&amp;gt; {
  const { name, password } = req.body;

  try {
    const userId = req.user.id;

    if (!req.user) {
      return res
        .status(401)
        .json(new ApiResponse(false, 401, null, "Unauthorized request"));
    }

    const updateData = {};

    // Only add fields to updateData if they are provided
    if (name) {
      updateData.name = name;
    }

    if (password) {
      const hashedPassword = await bcrypt.hash(password, 10);
      updateData.password = hashedPassword;
    }

    if (Object.keys(updateData).length === 0) {
      return res
        .status(400)
        .json(
          new ApiResponse(false, 400, null, "No fields provided to update")
        );
    }

    const updatedUser = await prisma.user.update({
      where: {
        id: Number(userId),
      },
      data: updateData,
    });

    return res
      .status(200)
      .json(
        new ApiResponse(true, 200, updatedUser, "User updated successfully")
      );
  } catch (error) {
    console.error(error);
    return res
      .status(500)
      .json(new ApiResponse(false, 500, {}, "Internal Server Error"));
  }
};

// * Delete user
export const deleteUser = async (req, res) =&amp;gt; {
  try {
    const userId = req.user?.id;

    if (!req.user) {
      return res
        .status(401)
        .json(new ApiResponse(false, 401, null, "Unauthorized request"));
    }

    // Attempt to delete the user
    await prisma.user.delete({
      where: {
        id: Number(userId),
      },
    });

    return res
      .status(200)
      .json(new ApiResponse(true, 200, null, "User deleted successfully"));
  } catch (error) {
    console.error(error);
    return res
      .status(500)
      .json(new ApiResponse(false, 500, null, "Internal Server Error"));
  }
};

export const logoutUser = (req, res) =&amp;gt; {
  try {
    // Check if user is authenticated
    if (!req.user) {
      return res
        .status(401)
        .json(new ApiResponse(false, 401, null, "Unauthorized request"));
    }

    // Clear the cookie
    res.clearCookie("accessToken", {
      httpOnly: true,
      secure: false, // Set to true if using HTTPS in production
      sameSite: "strict",
    });

    return res
      .status(200)
      .json(new ApiResponse(true, 200, null, "User logged out successfully"));
  } catch (error) {
    console.error(error);
    return res
      .status(500)
      .json(new ApiResponse(false, 500, null, "Internal Server Error"));
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;middleware/authMiddleware.js&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import jwt from "jsonwebtoken";
import prisma from "../DB/db.config.js";
import { ApiResponse } from "../utils/ApiResponse.js";

export const verifyJWT = async (req, res, next) =&amp;gt; {
  try {
    const token =
      req.cookies?.accessToken ||
      req.header("Authorization")?.replace("Bearer ", "");

    if (!token) {
      return res
        .status(401)
        .json(new ApiResponse(false, 401, null, "Unauthorized request"));
    }

    const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
    const user = await prisma.user.findUnique({
      where: {
        id: decodedToken.userId,
      },
      select: {
        id: true,
        name: true,
        email: true,
        post: true,
        comment: true,
      },
    });

    if (!user) {
      return res
        .status(401)
        .json(new ApiResponse(false, 401, null, "Invalid Access Token"));
    }

    req.user = user;
    next();
  } catch (error) {
    return res
      .status(401)
      .json(
        new ApiResponse(
          false,
          401,
          null,
          error.message || "Invalid access token"
        )
      );
  }
};


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;'utils/ApiResponse.js'&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ApiResponse {
  constructor(success, status, data, message) {
    this.success = success;
    this.status = status;
    this.data = data;
    this.message = message;
  }
}

export { ApiResponse };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;Please note that there might be errors in this post and provided code, so refer to the official documentation, YouTube tutorials, and the GitHub repository for the complete and error-free version.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Prisma:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.prisma.io/docs/prisma-orm/quickstart/postgresql" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.prisma.io%2Fdocs%2Fog%2Fprisma-orm%2Fquickstart%2Fpostgresql%2Fimage.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.prisma.io/docs/prisma-orm/quickstart/postgresql" rel="noopener noreferrer" class="c-link"&gt;
            Quickstart: Prisma ORM with PostgreSQL (10 min) | Prisma Documentation
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Create a new TypeScript project from scratch by connecting Prisma ORM to PostgreSQL and generating a Prisma Client for database access.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.prisma.io%2Fdocs%2Ffavicon.ico%3Ffavicon.f8f1f26e.ico" width="32" height="32"&gt;
          prisma.io
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Youtube Tutorial: &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/GReoWKUnwAg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Sample-Code : &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Ajor-Saha" rel="noopener noreferrer"&gt;
        Ajor-Saha
      &lt;/a&gt; / &lt;a href="https://github.com/Ajor-Saha/prisma-express-postgresql" rel="noopener noreferrer"&gt;
        prisma-express-postgresql
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A backend and rest api set up using expressjs, prisma and postgresql database
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Prisma Express PostgreSQL API&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A RESTful API built with Express.js, Prisma ORM, and PostgreSQL for managing users, posts, and comments.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 Live Demo&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Base URL:&lt;/strong&gt; &lt;a href="https://prisma-express-postgresql.onrender.com/" rel="nofollow noopener noreferrer"&gt;Live Link&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important Notice:&lt;/strong&gt; This API is deployed on Render.com's free tier. The first request may take 30-60 seconds to respond due to cold start (server spin-up time). Subsequent requests will be faster.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;API is deployed on Render&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📚 API Documentation&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Authentication&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;This API uses JWT (JSON Web Tokens) for authentication. The JWT token is stored as an HTTP-only cookie named &lt;code&gt;accessToken&lt;/code&gt; and is automatically included in requests to protected routes.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;👤 User Management&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;1. Register User&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Endpoint:&lt;/strong&gt; &lt;code&gt;POST /api/user/adduser&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description:&lt;/strong&gt; Register a new user account&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication:&lt;/strong&gt; Not required&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Request Body:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-source-json notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;{
  &lt;span class="pl-ent"&gt;"name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;John Doe&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"email"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;john@example.com&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"password"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;securepassword123&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
}&lt;/pre&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Success Response (201):&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-source-json notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;{
  &lt;span class="pl-ent"&gt;"success"&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt;
  &lt;span class="pl-ent"&gt;"statusCode"&lt;/span&gt;: &lt;span class="pl-c1"&gt;201&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"data"&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Ajor-Saha/prisma-express-postgresql" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>javascript</category>
      <category>express</category>
      <category>prisma</category>
      <category>postgres</category>
    </item>
  </channel>
</rss>
