<?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: Negin Saljooghi</title>
    <description>The latest articles on DEV Community by Negin Saljooghi (@negin).</description>
    <link>https://dev.to/negin</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%2F712566%2F4df52311-9931-49f6-8999-68f7bf6a7b04.jpg</url>
      <title>DEV Community: Negin Saljooghi</title>
      <link>https://dev.to/negin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/negin"/>
    <language>en</language>
    <item>
      <title>🚀 Mini Monitoring App in Go with Prometheus, Grafana &amp; CI/CD</title>
      <dc:creator>Negin Saljooghi</dc:creator>
      <pubDate>Sat, 06 Sep 2025 16:31:46 +0000</pubDate>
      <link>https://dev.to/negin/mini-monitoring-app-in-go-with-prometheus-grafana-cicd-f50</link>
      <guid>https://dev.to/negin/mini-monitoring-app-in-go-with-prometheus-grafana-cicd-f50</guid>
      <description>&lt;p&gt;In this tutorial, we’ll build a tiny, production-style Go service that you can deploy, observe, and ship via CI/CD.&lt;/p&gt;

&lt;h3&gt;
  
  
  💡 Why this project?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Real-world skills: &lt;strong&gt;containerization&lt;/strong&gt;, &lt;strong&gt;observability&lt;/strong&gt;, &lt;strong&gt;CI/CD&lt;/strong&gt;, and documentation.&lt;/li&gt;
&lt;li&gt;Interview-friendly: shows us understand &lt;strong&gt;build → ship → monitor&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Lightweight: a small &lt;strong&gt;Go&lt;/strong&gt; service with

&lt;code&gt;/health&lt;/code&gt;

and

&lt;code&gt;/metrics&lt;/code&gt;

that we can extend later.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🎯 What we’ll build
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A Go service exposing:&lt;br&gt;
&lt;code&gt;GET /health&lt;/code&gt; : returns {"status":"OK"}&lt;br&gt;
&lt;code&gt;GET /metrics&lt;/code&gt;: Prometheus metrics (custom counter &amp;amp; latency histogram)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Dockerized app pushed to &lt;strong&gt;DockerHub&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;strong&gt;Prometheus&lt;/strong&gt; + &lt;strong&gt;Grafana&lt;/strong&gt; stack to scrape &amp;amp; visualize metrics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;strong&gt;GitHub Actions&lt;/strong&gt; pipeline to test, build, and publish the image.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ⚙️ Prereqs:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Docker &amp;amp; Docker Compose.&lt;/li&gt;
&lt;li&gt;GitHub account (for CI/CD).&lt;/li&gt;
&lt;li&gt;DockerHub account (to publish the image).&lt;/li&gt;
&lt;li&gt;Go 1.24.x&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🧪 Run it now
&lt;/h3&gt;

&lt;p&gt;(Replace negin007 with your DockerHub username if you fork this.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker pull negin007/mini-monitoring-app:latest
docker run -d -p 8080:8080 negin007/mini-monitoring-app:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:8080/health
curl http://localhost:8080/metrics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🧭 Project structure
&lt;/h3&gt;

&lt;p&gt;mini-monitoring-app/&lt;br&gt;
├─ main.go&lt;br&gt;
├─ go.mod&lt;br&gt;
├─ Dockerfile&lt;br&gt;
├─ .dockerignore&lt;br&gt;
├─ docker-compose.yml&lt;br&gt;
├─ prometheus.yml&lt;br&gt;
├─ .github/&lt;br&gt;
│  └─ workflows/ci.yml&lt;br&gt;
└─ README.md&lt;/p&gt;


&lt;h3&gt;
  
  
  🪜 The Steps
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. Write Go service
&lt;/h4&gt;

&lt;p&gt;Minimal &lt;code&gt;main.go&lt;/code&gt; with &lt;code&gt;/health&lt;/code&gt; and &lt;code&gt;/metrics&lt;/code&gt;.(Full file: &lt;a href="https://github.com/NeginSal/Mini-Monitoring-App/blob/main/main.go" rel="noopener noreferrer"&gt;main.go&lt;/a&gt;)&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Instrumentation
&lt;/h4&gt;

&lt;p&gt;We expose two custom metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Counter &lt;code&gt;health_requests_total&lt;/code&gt; → ever-increasing count of health checks.&lt;/li&gt;
&lt;li&gt;Histogram &lt;code&gt;response_latency_seconds&lt;/code&gt; → measures latency in buckets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why a histogram? Because you can calculate percentiles like P95 using Prometheus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;histogram_quantile(0.95,sum(rate(response_latency_seconds_bucket[1m])) by (le)) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;-&lt;code&gt;rate(...[1m])&lt;/code&gt; → per-second rate over 1 minute&lt;/p&gt;

&lt;p&gt;-&lt;code&gt;sum(... ) by (le)&lt;/code&gt; → aggregate all instances by bucket(le = “less or equal”)&lt;/p&gt;

&lt;p&gt;-&lt;code&gt;histogram_quantile(0.95, ...)&lt;/code&gt; → compute the 95th percentile latency (P95).&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Dockerize the service
&lt;/h4&gt;

&lt;p&gt;Dockerfile: (Full file: &lt;a href="https://github.com/NeginSal/Mini-Monitoring-App/blob/main/Dockerfile" rel="noopener noreferrer"&gt;Dockerfile&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Build &amp;amp; run locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t yourname/mini-monitoring-app:local .
docker run -p 8080:8080 yourname/mini-monitoring-app:local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Validate endpoints locally:
&lt;/h4&gt;

&lt;p&gt;We should see {"status":"UP"}.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:8080/health
curl http://localhost:8080/metrics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Add Monitoring Stack (Prometheus + Grafana)
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;prometheus.yml&lt;/code&gt; config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;global:
  scrape_interval: 5s  

scrape_configs:
  - job_name: "mini-monitoring-app"
    static_configs:
      - targets: ["app:8080"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt; spins up app + Prometheus + Grafana.&lt;br&gt;
(Full files: &lt;a href="https://github.com/NeginSal/Mini-Monitoring-App/blob/main/prometheus.yml" rel="noopener noreferrer"&gt;prometheus.yml&lt;/a&gt; , &lt;a href="https://github.com/NeginSal/Mini-Monitoring-App/blob/main/docker-compose.yml" rel="noopener noreferrer"&gt;docker-compose.yml&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Run all services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;docker-compose up -d : App → &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Prometheus → &lt;a href="http://localhost:9090" rel="noopener noreferrer"&gt;http://localhost:9090&lt;/a&gt; (check Status → Targets)&lt;/li&gt;
&lt;li&gt;Grafana → &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; (login admin / admin)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  6. Build a Grafana dashboard
&lt;/h4&gt;

&lt;p&gt;Two common panel types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Graph/Time series → trends over time (great for latency/throughput)&lt;/li&gt;
&lt;li&gt;Gauge/Stat → current value or single number (great for “count now”)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example panels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stat: health_requests_total (total health checks)&lt;/li&gt;
&lt;li&gt;Time series (P95 latency):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;histogram_quantile(0.95, sum(rate(response_latency_seconds_bucket[1m])) by (le))

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  7. CI/CD with GitHub Actions
&lt;/h4&gt;

&lt;p&gt;Workflow &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs Go tests&lt;/li&gt;
&lt;li&gt;Builds Docker image&lt;/li&gt;
&lt;li&gt;Pushes image to DockerHub&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Required secrets(Repo → Settings → Secrets → Actions):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DOCKERHUB_USERNAME → your DockerHub username&lt;/li&gt;
&lt;li&gt;DOCKERHUB_TOKEN → DockerHub access token (Read/Write)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Full file:&lt;a href="https://github.com/NeginSal/Mini-Monitoring-App/blob/main/.github/workflows/ci.yml" rel="noopener noreferrer"&gt;ci.yml&lt;/a&gt;)&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ Conclusion
&lt;/h3&gt;

&lt;p&gt;This tiny monitoring app shows how a real-world service can be built, observed, and shipped with modern practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go for a lightweight service&lt;/li&gt;
&lt;li&gt;Prometheus + Grafana for observability&lt;/li&gt;
&lt;li&gt;Docker &amp;amp; GitHub Actions for CI/CD automation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Repo: &lt;a href="https://github.com/NeginSal/Mini-Monitoring-App" rel="noopener noreferrer"&gt;Mini-Monitoring-App&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading! 🍀&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>monitoring</category>
      <category>sre</category>
      <category>devops</category>
    </item>
    <item>
      <title>A CRUD API with Go, using the Gin framework and MongoDB.</title>
      <dc:creator>Negin Saljooghi</dc:creator>
      <pubDate>Thu, 15 May 2025 13:45:19 +0000</pubDate>
      <link>https://dev.to/negin/a-crud-api-with-go-using-the-gin-framework-and-mongodb-379e</link>
      <guid>https://dev.to/negin/a-crud-api-with-go-using-the-gin-framework-and-mongodb-379e</guid>
      <description>&lt;p&gt;Hi, here we want to create a simple and clean &lt;code&gt;RESTful API&lt;/code&gt; built with &lt;code&gt;Golang (Gin)&lt;/code&gt;, &lt;code&gt;MongoDB&lt;/code&gt;, and &lt;code&gt;JWT&lt;/code&gt; Authentication.&lt;br&gt;
This API allows you to register, log in, and perform user management operations securely.&lt;br&gt;
you can find the source code here : &lt;a href="https://github.com/NeginSal/go-crud-api" rel="noopener noreferrer"&gt;sourcecode&lt;/a&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%2F2byr2arp5vzeforld7f9.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%2F2byr2arp5vzeforld7f9.png" alt=" " width="348" height="145"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  📦 Features of Project
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🔑 User registration and login with secure password hashing&lt;/li&gt;
&lt;li&gt;🛡️ JWT-based authentication&lt;/li&gt;
&lt;li&gt;🔄 Full ‍‍CRUD operations for users&lt;/li&gt;
&lt;li&gt;✅ Input validation using go-playground/validator&lt;/li&gt;
&lt;li&gt;📚 Swagger documentation with swaggo/gin-swagger&lt;/li&gt;
&lt;li&gt;💾 MongoDB integration using mongo-driver&lt;/li&gt;
&lt;li&gt;🧪 Tests for core functionalities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;⚙️ Prerequisites&lt;/strong&gt;&lt;br&gt;
‌Befor starting make sure that you have these :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;latest version of go&lt;/li&gt;
&lt;li&gt;postman or curl for api testing&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  🔨 Initializing a Go project:
&lt;/h2&gt;

&lt;p&gt;First of all create a folder for 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 go-crud-api
cd go-crud-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For initializing a Go project we usually run this command : &lt;code&gt;go mod init&lt;/code&gt; . this command create a file (&lt;code&gt;go.mod&lt;/code&gt;) in your directory , this file is using for dependency management of your project. so open your terminal &amp;amp; run this command &lt;code&gt;go mod init&lt;/code&gt; then write this &lt;code&gt;go mod init github.com/yourusername/go-crud-api&lt;/code&gt; in the file if you doesn't create any repo for your project you can just write &lt;code&gt;go mod init my-project&lt;/code&gt; then change it to your repo address.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we use &lt;code&gt;Gin&lt;/code&gt; for creating api :&lt;code&gt;go get -u github.com/gin-gonic/gin&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📁 Project structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go-crud-api/
│
├── main.go
├── config/          ← Database settings and ...
│   └── db.go
├── controller/      ← Controllers (logic related to APIs)
│   └── user.go
├── model/           ← Data structures and models
│   └── user.go
├── middleware/      ← Middlewares (like auth)
│   └── authMiddleware.go
├── routes/          ← Routing
│   └── userRoutes.go
├── utils/           ← Helper functions (like ValidateToken)
│   └── jwt.go
├── go.mod / go.sum  ← Package information
└── README.md        ← Project description 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 Explain Code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. go-crud-api/main.go
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "crud-api-go/config"
    "crud-api-go/routes"
    "github.com/gin-gonic/gin"
)

func main() {
    config.ConnectDB()
    router := gin.Default()
    routes.UserRoutes(router)
    router.Run("localhost:8080")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; function is the entry point of our program.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;config.ConnectDB()&lt;/code&gt; : this line calls a function(&lt;code&gt;ConnectDB&lt;/code&gt;)from &lt;code&gt;config&lt;/code&gt; package. this function is responsible for establishing connection to your database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;router := gin.Default()&lt;/code&gt; : A router is a core of a web app , it determines how the app responds to different client request at different URL.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;routes.UserRoutes(router)&lt;/code&gt; : This line calls a function &lt;code&gt;userRoutes&lt;/code&gt; from the routes package,passing the &lt;code&gt;Gin router&lt;/code&gt; as an argument.this function is responsible for defining all the API routes related to users (like creating, reading, updating, and deleting users).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;router.Run("localhost:8080")&lt;/code&gt; : This line starts the &lt;code&gt;Gin&lt;/code&gt; web server makes it listen for incoming HTTP requests on the address &lt;code&gt;localhost:8080&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. go-crud-api/config/db.go
&lt;/h3&gt;

&lt;p&gt;Setting Up Our &lt;code&gt;MongoDB&lt;/code&gt; Connection in Go**&lt;/p&gt;

&lt;p&gt;Packages We Rely On:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;time&lt;/code&gt;, &lt;code&gt;context&lt;/code&gt;: Used for managing timeouts during the database connection process.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;os&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, &lt;code&gt;fmt&lt;/code&gt;: Essential for interacting with the operating system (reading environment variables), logging errors, and printing informational messages.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github.com/joho/godotenv&lt;/code&gt;: A library for loading environment variables from a &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;go.mongodb.org/mongo-driver/mongo&lt;/code&gt; &amp;amp; &lt;code&gt;go.mongodb.org/mongo-driver/mongo/options&lt;/code&gt;: The official Go driver for MongoDB.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;var DB *mongo.Database&lt;/code&gt; : Here, we declare a global variable &lt;code&gt;DB&lt;/code&gt; of type &lt;code&gt;*mongo.Database&lt;/code&gt;. This allows us to easily access the established database connection from anywhere in our Go application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;err := godotenv.Load()&lt;/code&gt; : We use the &lt;code&gt;godotenv.Load()&lt;/code&gt; function to read key-value pairs from our &lt;code&gt;.env&lt;/code&gt; file and make them available as environment variables within our application.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if err != nil {
    log.Fatal("❌ Error loading .env file")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the .env file failed to load the program execution will be halted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mongoURI := os.Getenv("MONGO_URI")
databaseName := os.Getenv("DB_NAME")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with &lt;code&gt;os.Getenv&lt;/code&gt; we get the environmental variable for connecting to database.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;clientOptions := options.Client().ApplyURI(mongoURI)&lt;/code&gt; : This line is using for  setup connection settings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A context is created with a 10-second timeout to prevent the connection from hanging indefinitely. The &lt;code&gt;defer cancel()&lt;/code&gt; ensures that the context's resources are released when the function exits.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;client, err := mongo.Connect(ctx, clientOptions)&lt;/code&gt; : Here, we attempt to establish a connection to our MongoDB instance using the configured clientOptions and the context we created. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;DB = client.Database(databaseName)&lt;/code&gt; : Finally we setup the database instance, so it's accessible through out the entire application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package config

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"

    "github.com/joho/godotenv"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

var DB *mongo.Database

func ConnectDB() {
    // Load environment variables
    err := godotenv.Load()
    if err != nil {
        log.Fatal("❌ Error loading .env file")
    }

    // Get URI and database name from .env file
    mongoURI := os.Getenv("MONGO_URI")
    databaseName := os.Getenv("DB_NAME")

    if mongoURI == "" {
        log.Fatal("❌ MONGO_URI is not set in .env")
    }
    if databaseName == "" {
        log.Fatal("❌ DB_NAME is not set in .env")
    }

    // Set up connection options
    clientOptions := options.Client().ApplyURI(mongoURI)

    // Create context with timeout
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    // Connect to MongoDB
    client, err := mongo.Connect(ctx, clientOptions)
    if err != nil {
        log.Fatal("❌ MongoDB connection error:", err)
    }

    // Ping the database to test connection
    err = client.Ping(ctx, nil)
    if err != nil {
        log.Fatal("❌ MongoDB ping error:", err)
    }

    fmt.Println("✅ Connected to MongoDB Atlas!")

    // Set the selected database
    DB = client.Database(databaseName)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. go-crud-api/routes/userRoutes.go
&lt;/h3&gt;

&lt;p&gt;This file is related to defining &lt;code&gt;HTTP&lt;/code&gt; routes.we define public routes such as signup &amp;amp; login then we created a group of routes that are connected to the authentication middleware and include CRUD operations on users.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package routes

import (
    "crud-api-go/controller"
    "crud-api-go/middleware"

    "github.com/gin-gonic/gin"
)

func UserRoutes(router *gin.Engine) {
    router.POST("/signup", controller.Signup)
    router.POST("/login", controller.Login)

    protected := router.Group("/")
    protected.Use(middleware.AuthMiddleware())
    {
        protected.GET("/users", controller.GetUsers)
        protected.GET("/users/:id", controller.GetUserByID)
        protected.POST("/users", controller.CreateUser)
        protected.PUT("/users/:id", controller.UpdateUser)
        protected.DELETE("/users/:id",controller.DeleteUser)
    }
}

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

&lt;/div&gt;



&lt;p&gt;we define a function named &lt;code&gt;UserRoutes&lt;/code&gt;.this function will be responsible for defining all the API endpoints related to the users. this function take a pointer to a &lt;code&gt;gin&lt;/code&gt; .Engine as an argument. the &lt;code&gt;gin.Engin&lt;/code&gt; is the main instance of the Gin router.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;protected := router.Group("/")&lt;/code&gt; : this line creates a new route group using the router.Group("/") method.The &lt;code&gt;/&lt;/code&gt; shows that all routes defined within this group will have a common base path.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;protected.Use(middleware.AuthMiddleware())&lt;/code&gt; : This means that for any request made to the routes defined within this group, the AuthMiddleware() function will be executed first.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. go-crud-api/model/user.go
&lt;/h3&gt;

&lt;p&gt;Model structures in this file are designed for three purposes: storing data in &lt;code&gt;MongoDB (User)&lt;/code&gt;, securely responding to clients (&lt;code&gt;UserResponse&lt;/code&gt; and &lt;code&gt;AuthResponse&lt;/code&gt;), and receiving input from clients for &lt;code&gt;registration&lt;/code&gt;, &lt;code&gt;login&lt;/code&gt;, or &lt;code&gt;editing&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package model

import "go.mongodb.org/mongo-driver/bson/primitive"

type User struct {
    ID       primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
    Name     string             `json:"name" bson:"name" validate:"required,min=2,max=50"`
    Email    string             `json:"email" bson:"email" validate:"required,email"`
    Password string             `json:"password,omitempty" bson:"password,omitempty" validate:"required,min=6"`
}

type UserResponse struct {
    ID    primitive.ObjectID `json:"id"`
    Name  string             `json:"name"`
    Email string             `json:"email"`
}

type AuthResponse struct {
    Token string       `json:"token"`
    User  UserResponse `json:"user"`
}

type SignupInput struct {
    Name     string `json:"name" validate:"required"`
    Email    string `json:"email" validate:"required,email"`
    Password string `json:"password" validate:"required"`
}

type LoginInput struct {
    Email    string `json:"email" validate:"required,email"`
    Password string `json:"password" validate:"required"`
}

type CreateUserInput struct {
    Name     string `json:"name" validate:"required"`
    Email    string `json:"email" validate:"required,email"`
    Password string `json:"password" validate:"required"`
}

type UpdateUserInput struct {
    Name  string `json:"name" validate:"required,min=2,max=50"`
    Email string `json:"email" validate:"required,email"`
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. go-crud-api/controller/user.go
&lt;/h3&gt;

&lt;p&gt;In this file we have 5 main controller functions for &lt;code&gt;CRUD&lt;/code&gt; operations on users, all written using &lt;code&gt;Gin&lt;/code&gt; and connected to the &lt;code&gt;MongoDB&lt;/code&gt; database. We utilize input validation, and all requests, except for signup and login, require &lt;code&gt;JWT&lt;/code&gt; authentication.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;First of all we import packages , these packages are for interacting with the &lt;code&gt;MongoDB&lt;/code&gt; database, managing time, performing validation, and the &lt;code&gt;Gin&lt;/code&gt; framework for handling &lt;code&gt;HTTP&lt;/code&gt; requests, &lt;code&gt;config&lt;/code&gt; for database access and &lt;code&gt;model&lt;/code&gt; for defining data structures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Helper Function and Validation&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func getUserCollection() *mongo.Collection {
    return config.DB.Collection("users")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function retrieves the &lt;code&gt;MongoDB&lt;/code&gt; collection named &lt;code&gt;users&lt;/code&gt; from the existing DB connection in the &lt;code&gt;config&lt;/code&gt; package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var validate = validator.New()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the 'validator' package to check user inputs (e.g., whether fields are required or the email structure is correct).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;GetUsers&lt;/code&gt; : The &lt;code&gt;GetUsers&lt;/code&gt; function retrieves a list of users from the database and responds in &lt;code&gt;JSON&lt;/code&gt; format.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;GetUserByID&lt;/code&gt; : Retrieving a specific user from the database by ID and responding in JSON format.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CreateUser&lt;/code&gt; : Creating a new user and saving it to &lt;code&gt;MongoDB&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;UpdateUser&lt;/code&gt; : Updating user information in the database based on the &lt;code&gt;ID&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DeleteUser&lt;/code&gt; : Deleting a user from the database based on the ID.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package controller

import (
    "context"
    "crud-api-go/config"
    "crud-api-go/model"
    "net/http"
    "time"

    "github.com/gin-gonic/gin"
    "github.com/go-playground/validator/v10"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
)

func getUserCollection() *mongo.Collection {
    return config.DB.Collection("users")
}

var validate = validator.New()

func GetUsers(c *gin.Context) {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    cursur, err := getUserCollection().Find(ctx, bson.M{})
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "error fetching users"})
        return
    }
    defer cursur.Close(ctx)

    var users []model.User
    if err := cursur.All(ctx, &amp;amp;users); err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "error parsing users"})
        return
    }

    var userslist []model.UserResponse
    for _, u := range users {
        userslist = append(userslist, model.UserResponse{
            ID:    u.ID,
            Name:  u.Name,
            Email: u.Email,
        })
    }
    c.JSON(http.StatusOK, userslist)

}

func GetUserByID(c *gin.Context) {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    idParam := c.Param("id")
    objectId, err := primitive.ObjectIDFromHex(idParam)

    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID Format"})
        return
    }

    var user model.User
    err = getUserCollection().FindOne(ctx, bson.M{"_id": objectId}).Decode(&amp;amp;user)
    if err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
        return
    }
    c.JSON(http.StatusOK, user)
}

func CreateUser(c *gin.Context) {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    var input model.CreateUserInput
    if err := c.BindJSON(&amp;amp;input); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
        return
    }

    if err := validate.Struct(input); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    newUser := model.User{
        ID:       primitive.NewObjectID(),
        Name:     input.Name,
        Email:    input.Email,
        Password: input.Password, 
    }

    _, err := getUserCollection().InsertOne(ctx, newUser)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create user"})
        return
    }

    c.JSON(http.StatusCreated, model.UserResponse{
        ID:    newUser.ID,
        Name:  newUser.Name,
        Email: newUser.Email,
    })
}

func UpdateUser(c *gin.Context) {
    idParam := c.Param("id")

    objectId, err := primitive.ObjectIDFromHex(idParam)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
        return
    }

    var updatedUser model.UpdateUserInput
    if err := c.BindJSON(&amp;amp;updatedUser); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON"})
        return
    }

    if err := validate.Struct(updatedUser); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    update := bson.M{
        "$set": bson.M{
            "name":  updatedUser.Name,
            "email": updatedUser.Email,
        },
    }

    res, err := getUserCollection().UpdateOne(ctx, bson.M{"_id": objectId}, update)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user"})
        return
    }

    if res.MatchedCount == 0 {
        c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
        return
    }

    c.JSON(http.StatusOK, gin.H{"message": "User updated successfully"})
}

func DeleteUser(c *gin.Context) {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    idParam := c.Param("id")
    objectId, err := primitive.ObjectIDFromHex(idParam)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID format"})
        return
    }

    res, err := getUserCollection().DeleteOne(ctx, bson.M{"_id": objectId})
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete user"})
        return
    }

    if res.DeletedCount == 0 {
        c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
        return
    }

    c.JSON(http.StatusOK, gin.H{"message": "User deleted"})
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. go-crud-api/controller/auth.go
&lt;/h3&gt;

&lt;p&gt;In this file, we have two functions: &lt;code&gt;Signup&lt;/code&gt; and &lt;code&gt;Login&lt;/code&gt;. &lt;code&gt;Signup&lt;/code&gt; registers a new user, hashes their password, and generates a &lt;code&gt;JWT&lt;/code&gt;. &lt;code&gt;Login&lt;/code&gt; verifies the user's email and password and, upon successful authentication, sends back a &lt;code&gt;JWT&lt;/code&gt;. This token is subsequently used by the middleware for authentication.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Signup&lt;/code&gt;: This function handles new user registration. It takes user information, checks if the email is not already taken, hashes the password, and saves the user to the database. Finally, it returns a &lt;code&gt;JWT&lt;/code&gt; token.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Login&lt;/code&gt;: This function is used for user login. It receives the email and password, and if they are valid, it generates a &lt;code&gt;JWT&lt;/code&gt; token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package controller

import (
    "context"
    "crud-api-go/model"
    "crud-api-go/utils"
    "net/http"
    "strings"
    "time"

    "github.com/gin-gonic/gin"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "golang.org/x/crypto/bcrypt"
)

func Signup(c *gin.Context) {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    var input model.SignupInput
    if err := c.ShouldBindJSON(&amp;amp;input); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
        return
    }

    var existingUser model.User
    err := getUserCollection().FindOne(ctx, bson.M{"email": input.Email}).Decode(&amp;amp;existingUser)
    if err == nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "User already exists"})
        return
    }

    hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
        return
    }

    newUser := model.User{
        ID:       primitive.NewObjectID(),
        Name:     input.Name,
        Email:    strings.ToLower(input.Email),
        Password: string(hashedPassword),
    }

    _, err = getUserCollection().InsertOne(ctx, newUser)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
        return
    }

    token, err := utils.GenerateJWT(newUser.Email)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create token"})
        return
    }

    c.JSON(http.StatusCreated, model.AuthResponse{
        Token: token,
        User: model.UserResponse{
            ID:    newUser.ID,
            Name:  newUser.Name,
            Email: newUser.Email,
        },
    })
}


func Login(c *gin.Context) {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    var input model.LoginInput
    if err := c.ShouldBindJSON(&amp;amp;input); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
        return
    }

    var foundUser model.User
    err := getUserCollection().FindOne(ctx, bson.M{"email": input.Email}).Decode(&amp;amp;foundUser)
    if err != nil {
        c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid email or password"})
        return
    }

    err = bcrypt.CompareHashAndPassword([]byte(foundUser.Password), []byte(input.Password))
    if err != nil {
        c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials. Please check your email and password"})
        return
    }

    token, err := utils.GenerateJWT(foundUser.Email)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create token"})
        return
    }

    c.JSON(http.StatusOK, model.AuthResponse{
        Token: token,
        User: model.UserResponse{
            ID:    foundUser.ID,
            Name:  foundUser.Name,
            Email: foundUser.Email,
        },
    })
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. go-crud-api/middleware/authMiddleware.go
&lt;/h3&gt;

&lt;p&gt;Here we createa  middleware to protect sensitive routes that require authentication, using JWT tokens.&lt;br&gt;
This middleware (&lt;code&gt;AuthMiddleware()&lt;/code&gt;) checks the Authorization header. If it's in the &lt;code&gt;Bearer &amp;lt;token&amp;gt;&lt;/code&gt; format, it extracts the token, validates it using the JWT secret, and if valid, adds the user's email to the context for subsequent use. If there's an issue, the request is aborted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package middleware

import (
    "crud-api-go/utils"
    "net/http"
    "strings"
    "github.com/gin-gonic/gin"
)

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        authHeader := c.GetHeader("Authorization")
        if authHeader == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header missing"})
            c.Abort()
            return
        }
        const bearerPrefix = "Bearer "
        if !strings.HasPrefix(authHeader, bearerPrefix) {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid Authorization header format"})
            c.Abort()
            return
        }
        tokenString := strings.TrimPrefix(authHeader, bearerPrefix)
        claims, err := utils.ValidateToken(tokenString)
        if err != nil {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
            c.Abort()
            return
        }
        c.Set("userEmail", claims.Email)
        c.Next()
    }
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. ‍‍go-crud-api/utils/jwt.go
&lt;/h3&gt;

&lt;p&gt;This file contains two key functions for working with &lt;code&gt;JWT tokens&lt;/code&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GenerateJWT&lt;/code&gt; is used to create a token with the user's email and a 24-hour expiration time.
‍&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ValidateToken&lt;/code&gt; is used to verify the token's validity and retrieve the information it contains. The &lt;code&gt;HS256 algorithm&lt;/code&gt; and an environment variable are used for signing to enhance security.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package utils

import (
    "os"
    "time"

    "github.com/golang-jwt/jwt/v5"
)

var jwtKey = []byte(os.Getenv("JWT_SECRET"))

type Claims struct {
    Email string `json:"email"`
    jwt.RegisteredClaims
}

// Generate token
func GenerateJWT(email string) (string, error) {
    expirationTime := time.Now().Add(24 * time.Hour)

    claims := &amp;amp;Claims{
        Email: email,
        RegisteredClaims: jwt.RegisteredClaims{
            ExpiresAt: jwt.NewNumericDate(expirationTime),
        },
    }

    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    tokenString, err := token.SignedString(jwtKey)
    if err != nil {
        return "", err
    }

    return tokenString, nil
}

// validate Token
func ValidateToken(tokenString string) (*Claims, error) {
    claims := &amp;amp;Claims{}

    token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
        return jwtKey, nil
    })

    if err != nil {
        return nil, err
    }

    if !token.Valid {
        return nil, jwt.ErrTokenInvalidClaims
    }

    return claims, nil
}

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

&lt;/div&gt;






&lt;p&gt;Now We've reached the end of this tutorial! I hope this guide has been helpful for you in building a simple and secure API with Go, Gin, MongoDB, and JWT.&lt;br&gt;
&lt;a href="https://github.com/NeginSal/go-crud-api/tree/master" rel="noopener noreferrer"&gt;go-crud-api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading! 🍀&lt;/p&gt;

</description>
      <category>go</category>
      <category>gin</category>
      <category>mongodb</category>
      <category>crudapi</category>
    </item>
    <item>
      <title>Vue3 crud app with json-server and axios</title>
      <dc:creator>Negin Saljooghi</dc:creator>
      <pubDate>Tue, 12 Sep 2023 14:28:47 +0000</pubDate>
      <link>https://dev.to/negin/vue3-crud-app-with-json-server-and-axios-5haf</link>
      <guid>https://dev.to/negin/vue3-crud-app-with-json-server-and-axios-5haf</guid>
      <description>&lt;p&gt;Hi, here we want to make a simple crud app with &lt;code&gt;Vue.js&lt;/code&gt; by using &lt;code&gt;json-server&lt;/code&gt;, &lt;code&gt;axios&lt;/code&gt; and &lt;code&gt;Tailwind CSS&lt;/code&gt; for styling.&lt;br&gt;
In this app we have two fields: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;username&lt;/code&gt; with three default values that we can edit, delete them or add a new one.&lt;br&gt;
You can find source code here: &lt;a href="https://github.com/NeginSal/CRUD-Vue3" rel="noopener noreferrer"&gt;source code&lt;/a&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%2Fq9cmthelg23kogllots8.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%2Fq9cmthelg23kogllots8.png" alt=" " width="637" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;let's start this project together step by step:&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;1. Setup project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;vue create vue-crud-app&lt;/code&gt; to create a new app. Open the project and run &lt;code&gt;npm run serve&lt;/code&gt; to see the project in your browser and then open a new terminal and run this command to start &lt;code&gt;json-server&lt;/code&gt; :&lt;code&gt;npx json-server --watch data/data.json --port 8000&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;2. Files &amp;amp; Folder&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;we just need &lt;code&gt;App.vue&lt;/code&gt; file and delete other files. Then create two folders: components &amp;amp; data.&lt;/p&gt;
&lt;h4&gt;
  
  
  Components :
&lt;/h4&gt;

&lt;p&gt;In the &lt;code&gt;src&lt;/code&gt; folder, create a components folder to put all of our files inside it. We have five components inside this folder :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AddUser.vue&lt;/code&gt;: to add a user.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EditUser.vue&lt;/code&gt;: to edit a user.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;UserList.vue&lt;/code&gt;: to show all users.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Home.vue&lt;/code&gt;: it is our homepage,where we show &lt;code&gt;UserList.vue&lt;/code&gt; &amp;amp; &lt;code&gt;AddUser.vue&lt;/code&gt; components.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;UserDetail.vue&lt;/code&gt;: to show user detail.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;data:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;It is in the root folder. Inside this folder create a file and called it &lt;code&gt;data.json&lt;/code&gt; and put all of our data inside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "users":[
    {
      "name":"Negin",
      "username":"negin007",
      "id":1
    },
    {
      "name":"Craig",
      "username":"benisphere",
      "id":2
    },
    {
      "name":"Ben",
      "username":"siliconeidolon",
      "id":3
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;3.Code&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;router.js&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/router.js&lt;/code&gt; .&lt;/li&gt;
&lt;li&gt;It is used to define and configure the router for our application &amp;amp;  allowing you to navigate between different pages or components based on the URL.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const routes = [
  {
    path: "/",
    name: "users",
    component: () =&amp;gt; import("./components/Home")
  },
  {
    path: "/user/:id",
    name: "editUser",
    component: () =&amp;gt; import("./components/EditUser")
    // props: true
  },
  {
    path: "/addUser",
    name: "addUser",
    component: () =&amp;gt; import("./components/AddUser")
  },
  {
    path: "/users/:id",
    name: "userDetail",
    component: () =&amp;gt; import("./components/UserDetail")
  }
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;App.vue&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/App.vue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It has &lt;code&gt;blockquote&lt;/code&gt; tag and &lt;code&gt;&amp;lt;router-view/&amp;gt;&lt;/code&gt; to display the content of your different pages.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;blockquote class="text-2xl font-semibold italic text-center text-blue-500 my-10"&amp;gt;
    &amp;lt;span
      class="mx-2 before:block before:absolute before:-inset-1 before:-skew-y-3 before:bg-pink-400 relative inline-block"&amp;gt;
      &amp;lt;span class="relative text-white "&amp;gt; CRUD App &amp;lt;/span&amp;gt;
    &amp;lt;/span&amp;gt;
    with Vue.js
  &amp;lt;/blockquote&amp;gt;
  &amp;lt;router-view /&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Home.vue&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;src/components/Home.vue&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It contains &lt;code&gt;UserList&lt;/code&gt; and &lt;code&gt;AddUser&lt;/code&gt; components.we fetch users here and then pass it as props to these components.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class="max-w-xl pb-8 mx-auto px-5 bg-slate-100"&amp;gt;
    &amp;lt;UserList :users="users" @userDeleted="handleUserDeleted" /&amp;gt;
    &amp;lt;AddUser :users="users" /&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import UserList from "./UserList.vue";
import AddUser from "./AddUser.vue";
import axios from 'axios';

export default {
  components: {
    UserList,
    AddUser,
  },
  data() {
    return {
      users: []
    }
  },
  mounted() {
    this.fetchUsers();
  },
  methods: {
    fetchUsers() {
      axios
        .get('http://localhost:8000/users')
        .then((res) =&amp;gt; { this.users = res.data })
        .catch(err =&amp;gt; console.log(err))
    },
    handleUserDeleted(userId) {
      this.users = this.users.filter((user) =&amp;gt; user.id !== userId);
    }
  }
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;UserList&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/components/UserList.vue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It shows list of users with two buttons for edit and delete each user.By click on name you can see user detail.&lt;/li&gt;
&lt;li&gt;we have two methods:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;deleteUser&lt;/code&gt; : for delete each user.&lt;br&gt;
&lt;code&gt;updateUser&lt;/code&gt; : for navigate to edit page and then edit name &amp;amp; username.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div v-if="users.length" class='py-5'&amp;gt;
    &amp;lt;div v-for="user in  users " :key="user.id" class='flex justify-between border-b-4'&amp;gt;
      &amp;lt;div class="flex "&amp;gt;
        &amp;lt;router-link :to="'/users/' + user.id"&amp;gt;
          &amp;lt;p class='my-3 px-3'&amp;gt;{{ user.name }}&amp;lt;/p&amp;gt;
        &amp;lt;/router-link&amp;gt;
        &amp;lt;p class='my-3 px-3'&amp;gt;{{ user.username }}&amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="flex "&amp;gt;
        &amp;lt;p @click="updateUser(user.id)" class='mx-2 my-3 px-2 py-1 text-green-800
     hover:bg-green-400 hover:rounded-md hover:border hover:border-green-800'&amp;gt;EDIT&amp;lt;/p&amp;gt;
        &amp;lt;p @click="deleteUser(user.id)" class='my-3 px-2 py-1 text-red-800 
     hover:bg-red-400 hover:rounded-md hover:border hover:border-red-800'&amp;gt;DELETE&amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import axios from 'axios';
import UserDetail from './UserDetail.vue';

export default {
  components: {
    UserDetail,
  },

  props: ['users'],
  methods: {
    deleteUser(id) {
      axios
        .delete(`http://localhost:8000/users/${id}`)
        .then(() =&amp;gt; {
          this.$emit('userDeleted', id)
        })
        .catch((error) =&amp;gt; { console.log(error) })
    },
    updateUser(id) {
      this.$router.push(`/user/${id}`)
    }
  }
}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;EditUser&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/components/EditUser.vue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We have two input fields for showing name &amp;amp; username.&lt;/li&gt;
&lt;li&gt;Two methods for updating user and cancel editing and back to home page.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class="flex items-center justify-center"&amp;gt;
    &amp;lt;form @submit.prevent="handleSubmit"&amp;gt;
      &amp;lt;div class='flex flex-col justify-center items-center bg-slate-100 p-10 mt-10 rounded-md'&amp;gt;
        &amp;lt;input v-model="name" class='my-2 px-5 py-1 rounded-full border border-gray-600' /&amp;gt;
        &amp;lt;input v-model="username" class='my-2 px-5 py-1 rounded-full border border-gray-600' /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="flex my-2 mx-20"&amp;gt;
        &amp;lt;button class='text-white mx-1 px-5 py-1 rounded-full bg-blue-500 hover:bg-blue-700'&amp;gt;Update User&amp;lt;/button&amp;gt;
        &amp;lt;button class='text-white mx-1 px-5 py-1 rounded-full bg-blue-500 hover:bg-blue-700'
          @click="backToHome"&amp;gt;Cancel&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;

    &amp;lt;/form&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import axios from 'axios';

export default {
  data() {
    return {
      id: this.$route.params.id,
      name: "",
      username: ""
    }
  },
  mounted() {
    axios
      .get('http://localhost:8000/users/' + this.id)
      .then((user) =&amp;gt; {
        this.name = user.data.name;
        this.username = user.data.username;
      })
  },
  methods: {
    handleSubmit() {
      axios
        .put('http://localhost:8000/users/' + this.id, {
          name: this.name,
          username: this.username,
        })
        .then(() =&amp;gt; {
          this.$router.push("/");
        })
    },
    backToHome() {
      this.$router.push('/')
    }
  },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;UserDetail&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/components/UserDetail.vue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To see user detail,here: name &amp;amp; username.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class="max-w-xl pb-8 mx-auto px-5 bg-slate-100"&amp;gt;
    &amp;lt;div class="flex flex-col text-center py-5 "&amp;gt;
      &amp;lt;p class='px-3 py-3 border-b-4'&amp;gt;Name : {{ user ? user.name : '' }}&amp;lt;/p&amp;gt;
      &amp;lt;p class='px-3 py-3'&amp;gt;UserName : {{ user ? user.username : '' }}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import axios from 'axios';

export default {
  data() {
    return {
      user: null,
      id: this.$route.params.id
    }
  },
  mounted() {
    this.fetchUser();
  },
  methods: {
    fetchUser() {
      axios
        .get('http://localhost:8000/users/' + this.id)
        .then((res) =&amp;gt; { this.user = res.data })
        .catch(err =&amp;gt; console.log(err))
    }
  }
}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;AddUser&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/components/AddUser.vue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It has two fields for add &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;username&lt;/code&gt; &amp;amp; a &lt;code&gt;handleSubmit&lt;/code&gt; method to add user to list of users.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;form @submit.prevent="handleSubmit"&amp;gt;
    &amp;lt;div class='flex flex-col justify-center items-center '&amp;gt;
      &amp;lt;div class='mb-2'&amp;gt;
        &amp;lt;input class='px-3 py-1 rounded-full border border-gray-600' v-model="name" placeholder="Name" /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class='mb-2'&amp;gt;
        &amp;lt;input class='px-3 py-1 rounded-full border border-gray-600' v-model="username" placeholder="UserName" /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class='mb-2'&amp;gt;
        &amp;lt;button class="bg-blue-500 hover:bg-blue-700 text-white py-1 px-3 rounded-full"&amp;gt;
          Add
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import axios from 'axios';

export default {
  props: ['users'],
  data() {
    return {
      name: '',
      username: ''
    }
  },
  methods: {
    handleSubmit() {
      axios
        .post("http://localhost:8000/users", {
          name: this.name,
          username: this.username,
        })
        .then((response) =&amp;gt; {
          const data = response.data;
          this.users.push(data);
          this.name = "";
          this.username = "";
        });
    },
  }
}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Now here we go! We created a simple crud app with &lt;code&gt;Vue.js&lt;/code&gt;, &lt;code&gt;json-server&lt;/code&gt;, &lt;code&gt;axios&lt;/code&gt; and &lt;code&gt;Tailwind CSS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading! 🍀&lt;/p&gt;

</description>
      <category>vue</category>
      <category>crud</category>
      <category>axios</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>React + GraphQL CRUD</title>
      <dc:creator>Negin Saljooghi</dc:creator>
      <pubDate>Mon, 28 Aug 2023 12:26:54 +0000</pubDate>
      <link>https://dev.to/negin/react-graphql-crud-1ma8</link>
      <guid>https://dev.to/negin/react-graphql-crud-1ma8</guid>
      <description>&lt;p&gt;Here we want to create a simple &lt;code&gt;CRUD&lt;/code&gt; app with &lt;code&gt;react&lt;/code&gt;, &lt;code&gt;GraphQL&lt;/code&gt;, &lt;code&gt;Node.js&lt;/code&gt; and &lt;code&gt;MongoDB&lt;/code&gt;- &lt;strong&gt;part 1&lt;/strong&gt;, let's go:&lt;br&gt;
You can find source code here: &lt;a href="https://github.com/NeginSal/CRUD-react-graphql" rel="noopener noreferrer"&gt;source code&lt;/a&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%2F5wf0lpgtc1hpyossfe3w.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%2F5wf0lpgtc1hpyossfe3w.png" alt=" " width="746" height="420"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Project Overview&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This project has two folders, server and client. In this post we just work on the server(Backend) and for the next post we will work on the client(Frontend).&lt;/p&gt;
&lt;h5&gt;
  
  
  &lt;strong&gt;Backend:&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;We make a &lt;code&gt;GraphQL&lt;/code&gt; server on &lt;code&gt;node.js&lt;/code&gt; by using &lt;code&gt;Express&lt;/code&gt;. This is where we describe how our Graph looks like, different types of data on our Graph, relationship between these data types, setting up different entry points (where we can query and retrieve information) to our Graph. And then we use &lt;code&gt;MongoDB&lt;/code&gt; to store our data.&lt;/p&gt;
&lt;h5&gt;
  
  
  &lt;strong&gt;Frontend:&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;For the client side we use &lt;code&gt;React&lt;/code&gt;, and also we use &lt;br&gt;
&lt;code&gt;Apollo&lt;/code&gt;, it allows us to use &lt;code&gt;GraphQL&lt;/code&gt; on the frontend and inside &lt;code&gt;react&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, we have &lt;code&gt;GraphiQL&lt;/code&gt; it is like a frontend application that allows us to make a request to &lt;code&gt;GraphQL&lt;/code&gt; and retrieve data back.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Start working on project&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Initialize a node project : &lt;code&gt;npm init&lt;/code&gt;&lt;br&gt;
Inside the project folder, run this command, and it is going to create a &lt;code&gt;package.json&lt;/code&gt; file for us.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Inside project folder we should create a folder and call it to server, all of our server side code will be inside this folder.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Create an express application: &lt;code&gt;npm install express&lt;/code&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Create index.js file&lt;/p&gt;

&lt;p&gt;Inside this file we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up our &lt;code&gt;express app&lt;/code&gt; and listen to a specific port(5000).&lt;/li&gt;
&lt;li&gt;Set up our &lt;code&gt;GraphQL&lt;/code&gt;.we need to install two package: &lt;code&gt;npm install graphql express-graphql&lt;/code&gt;.first one is the main &lt;code&gt;graphql&lt;/code&gt; package which is a &lt;code&gt;JavaScript&lt;/code&gt; implantation of &lt;code&gt;GraphQL&lt;/code&gt;, the second one is a package that help our express app to interact with &lt;code&gt;GraphQL&lt;/code&gt; because&lt;code&gt;express&lt;/code&gt; doesn't understand &lt;code&gt;GraphQL&lt;/code&gt;(require &lt;code&gt;express-graphql&lt;/code&gt; module(&lt;code&gt;grapqlHTTP&lt;/code&gt;)).&lt;/li&gt;
&lt;li&gt;Setup some middleware. 
The way that we do that in express is by using app.use(). Like this one :
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use('/graphql', graphqlHTTP({
   schema,
  graphiql: true
}));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here we say the route that we gonna use on this middleware is &lt;code&gt;/graphql&lt;/code&gt; and then fire a function. when a request to&lt;code&gt;/graphql&lt;/code&gt; comes in and this function going to handle our &lt;code&gt;GraphQL&lt;/code&gt; requests, and it takes some options inside an object. We have to pass &lt;code&gt;schema&lt;/code&gt; and &lt;code&gt;graphiql: true&lt;/code&gt; as a property to this middleware.&lt;br&gt;
&lt;code&gt;Schema&lt;/code&gt;, going to tell &lt;code&gt;express graphql&lt;/code&gt; about our data and how graph will looks like.it says what data types are in the graph and relationship between them.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Create Schema.js file&lt;/p&gt;

&lt;p&gt;&lt;code&gt;schema&lt;/code&gt; has three responsibility:&lt;br&gt;
define &lt;code&gt;Object Type&lt;/code&gt;, define relationship between &lt;code&gt;Object Type&lt;/code&gt;, define &lt;code&gt;rootQuery&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;Schema&lt;/code&gt; to describe how the data in our graph will looks like, inside this file we're going to define our schema.&lt;br&gt;
&lt;code&gt;Schema&lt;/code&gt; describe the &lt;code&gt;object type&lt;/code&gt; and the relations between these &lt;code&gt;object types&lt;/code&gt;, how we can read data and interact with them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Require the &lt;code&gt;GraphQL&lt;/code&gt;. We install this package before.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We define &lt;code&gt;ObjectType&lt;/code&gt; and define what this &lt;code&gt;ObjectType&lt;/code&gt; is about (define name &amp;amp; fields)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here, we just define one object type:&lt;code&gt;TodoType&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const TodoType = new GraphQLObjectType({
  name: 'Todo',
  fields: () =&amp;gt; ({
    id: { type: GraphQLID },
    title: { type: GraphQLString }
  })
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;GraphQLObjectType&lt;/code&gt; is a function and takes in an object and this object going to define what this &lt;code&gt;TodoType&lt;/code&gt; is all about.&lt;br&gt;
&lt;code&gt;name&lt;/code&gt;: a name for our object type.&lt;br&gt;
&lt;code&gt;fields&lt;/code&gt;:it is a function that returns an object, it's define the fields on this &lt;code&gt;TodoType&lt;/code&gt; and then say what type is our fields.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; Create RootQuery&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;RootQeury&lt;/code&gt;:it is our entry point to the graph. How we describe, a user can initially jump to the graph and grab data. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We define &lt;code&gt;fields&lt;/code&gt; of this &lt;code&gt;Root Query&lt;/code&gt;and each of this fields going to be a type of &lt;code&gt;RootQuery&lt;/code&gt;.first one is going to be a query for list of &lt;code&gt;todos&lt;/code&gt; and the second is for one &lt;code&gt;todo&lt;/code&gt; and the argument that we expected to get along with this query is &lt;code&gt;id&lt;/code&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Also, we have type and resolve function for each field.&lt;br&gt;
&lt;code&gt;resolve&lt;/code&gt; function : how to get data when someone requested.it is for grabbing data and return what is needed. &lt;br&gt;
this resolve function takes two parameters :&lt;code&gt;parent&lt;/code&gt; &amp;amp; &lt;code&gt;args&lt;/code&gt;. &lt;code&gt;parent&lt;/code&gt; coming to play when we start relationship between data.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const RootQuery = new GraphQLObjectType({
  name: 'RootQueryType',
  fields: () =&amp;gt; ({
    todos: {
      type: new GraphQLList(TodoType),
      resolve(parent, args) {
        return Todo.find();
      }
    },
    todo: {
      type: TodoType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        return Todo.findById(args.id);
      }
    }
  })
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;strong&gt;7.&lt;/strong&gt; Connect to database&lt;/p&gt;

&lt;p&gt;To connect to the database, create a folder called &lt;code&gt;config&lt;/code&gt; and then create &lt;code&gt;db.js&lt;/code&gt; file inside it: &lt;code&gt;server/config/db.js&lt;/code&gt;.&lt;br&gt;
inside &lt;code&gt;db.js&lt;/code&gt; file, first we bring mongoose to connect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second we have an async function called &lt;code&gt;connectDB&lt;/code&gt; (because mongoose functions return promises) and then on the &lt;code&gt;connect&lt;/code&gt; we pass our mongoose URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const connectDB = async () =&amp;gt; {
const conn = await mongoose.connect('');
console.log(`mongoDB connected : ${conn.connection.host}`);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we call this &lt;code&gt;connectDB&lt;/code&gt; function inside &lt;code&gt;index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//connect to database
connectDB();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;8.&lt;/strong&gt; Mongoose Model&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;models&lt;/code&gt; folder and then inside it create&lt;code&gt;Todo.js&lt;/code&gt; file :&lt;code&gt;server/models/Todo.js&lt;/code&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Here we're going to store our &lt;code&gt;mongoose models&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This &lt;code&gt;model&lt;/code&gt; represents different types of collection in our &lt;code&gt;MongoDB&lt;/code&gt; instance.&lt;code&gt;Mongoose schema&lt;/code&gt;, going to define the data that actually being stored in &lt;code&gt;MongoDB&lt;/code&gt; and this is going to take an object with the fields that we want.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In our code, we use &lt;code&gt;Todo&lt;/code&gt; model.this &lt;code&gt;Todo model&lt;/code&gt; means how we interact with the todo collection then we use a method on it:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return Todo.find();
return Todo.findById(args.id);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;9.&lt;/strong&gt; Mutations&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It allows us to change or mutate data like add, delete, edit data. We define our &lt;code&gt;mutation&lt;/code&gt; in &lt;code&gt;schema.js&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Setting-up a mutation is like setting-up our &lt;code&gt;RootQuery&lt;/code&gt;. We pass throw an object to &lt;code&gt;GraphQLObjectType&lt;/code&gt; and this is going to have two property:  &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;fields&lt;/code&gt;.&lt;br&gt;
This fields property let us store different kind of mutations that we want to make like &lt;code&gt;addTodo&lt;/code&gt;, &lt;code&gt;editTodo&lt;/code&gt;, &lt;code&gt;deleteTodo&lt;/code&gt;, ....&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // Add todo
    addTodo: {
      type: TodoType,
      args: {
        title: { type: GraphQLNonNull(GraphQLString) },
      },
      resolve(parent, args) {
        const todo = new Todo({
          title: args.title
        });
        return todo.save();
      }
    },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example: this &lt;code&gt;addTodo&lt;/code&gt; property is going to be an &lt;code&gt;object&lt;/code&gt; and takes these properties:&lt;code&gt;type&lt;/code&gt; and &lt;code&gt;args&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;args&lt;/code&gt;: when a user makes a mutation from the frontend, then we expect them to send some kind of data or arguments.&lt;br&gt;
Here, if a user wants to add a &lt;code&gt;todo&lt;/code&gt; they're going to need send the &lt;code&gt;todo&lt;/code&gt; title.(the fields that we want to add)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resolve&lt;/code&gt;: this function is where we take the argument that they send along the query. By using &lt;code&gt;Todo model&lt;/code&gt; that, we import it before We make a new instance of todo and save it to the database.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Code:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;index.js&lt;/strong&gt; - server/index.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const schema = require('./schema/schema');
const app = express();
const connectDB = require('./config/db');
const cors = require('cors');

//connect to database
connectDB();

app.use(cors());

app.use('/graphql', graphqlHTTP({
  schema,
  graphiql: true
}));

app.listen(5000, () =&amp;gt; {
  console.log('now listening for requests on port 5000');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;schema.js&lt;/strong&gt; - server/schema/schema.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const {
  GraphQLObjectType,
  GraphQLID,
  GraphQLString,
  GraphQLSchema,
  GraphQLList,
  GraphQLNonNull
} = require('graphql');

//Mongoose models
const Todo = require('../models/Todo.js')

//todos Typeo
const TodoType = new GraphQLObjectType({
  name: 'Todo',
  fields: () =&amp;gt; ({
    id: { type: GraphQLID },
    title: { type: GraphQLString }
  })
});

const RootQuery = new GraphQLObjectType({
  name: 'RootQueryType',
  fields: () =&amp;gt; ({
    todos: {
      type: new GraphQLList(TodoType),
      resolve(parent, args) {
        return Todo.find();
      }
    },
    todo: {
      type: TodoType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        return Todo.findById(args.id);
      }
    }
  })
});

// Mutations
const mutation = new GraphQLObjectType({
  name: 'Mutation',
  fields: {
    // Add todo
    addTodo: {
      type: TodoType,
      args: {
        title: { type: GraphQLNonNull(GraphQLString) },
      },
      resolve(parent, args) {
        const todo = new Todo({
          title: args.title
        });
        return todo.save();
      }
    },
    // Delete Todo
    deleteTodo: {
      type: TodoType,
      args: {
        id: { type: GraphQLNonNull(GraphQLID) },
      },
      resolve(parent, args) {
        return Todo.findByIdAndRemove(args.id)
      }
    },
    // Edit Todo
    editTodo: {
      type: TodoType,
      args: {
        id: { type: GraphQLNonNull(GraphQLID) },
        title: { type: GraphQLString },
      },
      resolve(parent, args) {
        return Todo.findByIdAndUpdate(
          args.id,
          {
            $set: {
              title: args.title,
            },
          },
          { new: true }
        );
      },
    },
  }
})

module.exports = new GraphQLSchema({
  query: RootQuery,
  mutation
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Todo.js&lt;/strong&gt;- server/models/Todo.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');

const TodoSchema = new mongoose.Schema({
  title: {
    type: String,
  }
});

module.exports = mongoose.model('Todo', TodoSchema);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;db.js&lt;/strong&gt; - server/config/db.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');

const connectDB = async () =&amp;gt; {
const conn = await mongoose.connect('');
console.log(`mongoDB connected : ${conn.connection.host}`);
};

module.exports = connectDB;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Now here we go! We created a simple &lt;code&gt;CRUD&lt;/code&gt; app with &lt;code&gt;react&lt;/code&gt;, &lt;code&gt;GraphQL&lt;/code&gt;, &lt;code&gt;Node.js&lt;/code&gt; and &lt;code&gt;MongoDB&lt;/code&gt;. In the below I put links that are helpful for me to create this project:&lt;br&gt;
By the way The link to the front end section will be posted here soon!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.google.com/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=2ahUKEwiz9OO1-vyAAxW4UKQEHTr2AO4QwqsBegQIDRAF&amp;amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DY0lDGjwRYKw&amp;amp;usg=AOvVaw0ePBhWrvcC9ki2k9jy_CeP&amp;amp;opi=89978449" rel="noopener noreferrer"&gt;The GraphQL tutorial playlist on The Net Ninja YouTube channel.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.google.com/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=2ahUKEwj-wcL9-vyAAxVQsKQKHbK2C_IQwqsBegQIDRAF&amp;amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DBcLNfwF04Kw&amp;amp;usg=AOvVaw1eGn_RxD8L386s1UIHAt9-&amp;amp;opi=89978449" rel="noopener noreferrer"&gt;Full stack GraphQL, Express &amp;amp; React app - Traversy Media&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading! 🍀&lt;/p&gt;

</description>
      <category>react</category>
      <category>graphql</category>
      <category>node</category>
      <category>crud</category>
    </item>
    <item>
      <title>Crud-react-app with json-server and axios</title>
      <dc:creator>Negin Saljooghi</dc:creator>
      <pubDate>Sat, 12 Aug 2023 14:02:29 +0000</pubDate>
      <link>https://dev.to/negin/crud-react-app-with-json-server-and-axios-142c</link>
      <guid>https://dev.to/negin/crud-react-app-with-json-server-and-axios-142c</guid>
      <description>&lt;p&gt;Hi, here we want to make a simple crud app with &lt;code&gt;react hooks&lt;/code&gt; by using &lt;code&gt;json-server&lt;/code&gt;, &lt;code&gt;axios&lt;/code&gt; and &lt;code&gt;Tailwind CSS&lt;/code&gt; for styling.&lt;br&gt;
In this app we have two fields: &lt;strong&gt;name&lt;/strong&gt;, &lt;strong&gt;username&lt;/strong&gt; with three default values that we can edit, delete them or add a new one.&lt;br&gt;
You can find source code here: &lt;a href="https://github.com/NeginSal/React-Hook-CRUD" rel="noopener noreferrer"&gt;source code&lt;/a&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%2Fygr2b3y2fyvrvqq7gx7j.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%2Fygr2b3y2fyvrvqq7gx7j.png" alt="project home page" width="735" height="496"&gt;&lt;/a&gt;&lt;br&gt;
let's start this project together step by step:&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;1. Setup project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npx create-react-app react-crud-app&lt;/code&gt; to create a new app. Open the project and run &lt;code&gt;npm start&lt;/code&gt; to see the project in your browser and then open a new terminal and run this command to start json-server :&lt;code&gt;npx json-server --watch data/data.json --port 8000&lt;/code&gt;  &lt;/p&gt;



&lt;p&gt;&lt;strong&gt;2. Files &amp;amp; Folder&lt;/strong&gt;&lt;br&gt;
we just need App.js file and delete other files. Then create two folders: &lt;code&gt;components&lt;/code&gt; &amp;amp; &lt;code&gt;data&lt;/code&gt;.&lt;/p&gt;
&lt;h6&gt;
  
  
  &lt;strong&gt;Components&lt;/strong&gt; :
&lt;/h6&gt;

&lt;p&gt;In the &lt;code&gt;src&lt;/code&gt; folder, create a &lt;code&gt;components&lt;/code&gt; folder to put all of our files inside it. We have four components inside this folder :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AddUser.js&lt;/code&gt;: to add a user&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EditUser.js&lt;/code&gt;: to edit a user&lt;/p&gt;

&lt;p&gt;&lt;code&gt;UserList.js&lt;/code&gt;: to show all users&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Home.js&lt;/code&gt;: it is our homepage&lt;/p&gt;
&lt;h6&gt;
  
  
  &lt;strong&gt;data&lt;/strong&gt;:
&lt;/h6&gt;

&lt;p&gt;It is in the root folder. Inside this folder create a file and called it &lt;code&gt;data.json&lt;/code&gt; and put all of our data inside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "users":[
    {
      "name":"Negin",
      "username":"negin007",
      "id":1
    },
    {
      "name":"Craig",
      "username":"benisphere",
      "id":2
    },
    {
      "name":"Ben",
      "username":"siliconeidolon",
      "id":3
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;3. Code&lt;/strong&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;App.js&lt;/strong&gt;:
&lt;/h5&gt;

&lt;p&gt;add path for components by using &lt;code&gt;react-router-dom&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Routes, Route } from "react-router-dom";
import Home from './components/Home';
import EditUser from './components/EditUser';
import AddUser from './components/AddUser';

const App = () =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Routes&amp;gt;
        &amp;lt;Route path='/' element={&amp;lt;Home /&amp;gt;} /&amp;gt;
        &amp;lt;Route path='/edit/:id' element={&amp;lt;EditUser /&amp;gt;} /&amp;gt;
        &amp;lt;Route path='/create' element={&amp;lt; AddUser /&amp;gt;} /&amp;gt;
      &amp;lt;/Routes&amp;gt;
    &amp;lt;/&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;h5&gt;
  
  
  &lt;strong&gt;Home.js&lt;/strong&gt;:
&lt;/h5&gt;

&lt;p&gt;This is your home component, where you can see a list of users (&lt;code&gt;UserList.js&lt;/code&gt;) and add a new user(&lt;code&gt;AddUser&lt;/code&gt;).&lt;br&gt;
Also, here we have a &lt;code&gt;useEffect&lt;/code&gt; to fetch all users and a function(&lt;code&gt;deleteUser&lt;/code&gt;) for deleting a user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from "axios";
import { useEffect, useState } from "react";
import UserList from "./UserList";
import AddUser from "./AddUser";

const Home = () =&amp;gt; {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() =&amp;gt; {
    setLoading(true)
    axios.get("http://localhost:8000/users")
      .then(response =&amp;gt; {
        setUsers(response.data)
      })
    setLoading(false)
  }, [])

  const deleteUser = (id) =&amp;gt; {
    axios.delete(`http://localhost:8000/users/${id}`).then((response) =&amp;gt; {
      const newUser = users.filter((user) =&amp;gt; user.id !== id);
      console.log(response)
      setUsers(newUser);
    }).catch(error =&amp;gt; {
      console.log(error)
    });
  }

  return (
    &amp;lt;div className="max-w-xl pb-8 mx-auto px-5 bg-slate-100"&amp;gt;
      &amp;lt;UserList
        users={users}
        loading={loading}
        deleteUser={deleteUser}
      /&amp;gt;
      &amp;lt;AddUser
        users={users}
        setUsers={setUsers}
      /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;h5&gt;
  
  
  &lt;strong&gt;UserList.js&lt;/strong&gt;:
&lt;/h5&gt;

&lt;p&gt;A component for showing list of users.&lt;/p&gt;

&lt;p&gt;Here we're passing &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;loading&lt;/code&gt;, &lt;code&gt;deleteUser&lt;/code&gt; as props to this component: &lt;code&gt;users&lt;/code&gt;: list of users, &lt;code&gt;loading&lt;/code&gt;: for the time before user loaded on the page and &lt;code&gt;deleteUser&lt;/code&gt; function for deleting a user.&lt;/p&gt;

&lt;p&gt;Another important thing in this component is edit button:&lt;br&gt;
we wrap it inside a &lt;code&gt;Link&lt;/code&gt; component and then when user click on this button it navigates to &lt;code&gt;EditUser&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Link } from "react-router-dom";

const UserList = ({ users, loading, deleteUser }) =&amp;gt; {

  return (
    &amp;lt;div className='py-5'&amp;gt;
      {loading &amp;amp;&amp;amp; &amp;lt;p&amp;gt;loading ...&amp;lt;/p&amp;gt;}
      {users &amp;amp;&amp;amp;
        &amp;lt;ul&amp;gt;
          {(users.map((user) =&amp;gt;
            &amp;lt;li className='flex justify-between border-b-4' key={user.id}&amp;gt;
              &amp;lt;div className="flex "&amp;gt;
                &amp;lt;p className='my-3 px-3'&amp;gt;{user.name}&amp;lt;/p&amp;gt;
                &amp;lt;p className='my-3 px-3'&amp;gt;{user.username}&amp;lt;/p&amp;gt;
              &amp;lt;/div&amp;gt;
              &amp;lt;div&amp;gt;
                &amp;lt;Link to={`/edit/${user.id}`}&amp;gt;
                  &amp;lt;button
                    className='mx-2 my-3 px-2 py-1 text-green-800
                       hover:bg-green-400 hover:rounded-md hover:border hover:border-green-800'
                  &amp;gt;EDIT&amp;lt;/button&amp;gt;
                &amp;lt;/Link&amp;gt;
                &amp;lt;button
                  className='my-3 px-2 py-1 text-red-800 
                        hover:bg-red-400 hover:rounded-md hover:border hover:border-red-800'
                  onClick={() =&amp;gt; deleteUser(user.id)}
                &amp;gt;Delete&amp;lt;/button&amp;gt;
              &amp;lt;/div&amp;gt;
            &amp;lt;/li&amp;gt;
          ))}
        &amp;lt;/ul &amp;gt;
      }
    &amp;lt;/div &amp;gt;
  )
}

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

&lt;/div&gt;



&lt;h5&gt;
  
  
  &lt;strong&gt;AddUser.js&lt;/strong&gt;:
&lt;/h5&gt;

&lt;p&gt;It is a form with two input fields (name &amp;amp; username)  and a button to submit a new user. Here we pass &lt;code&gt;setUsers&lt;/code&gt;, &lt;code&gt;users&lt;/code&gt;  as props to this component.&lt;/p&gt;

&lt;p&gt;For submitting a new user we have &lt;code&gt;handleSubmit&lt;/code&gt; function and inside this function we make a post request to post new name and username and the pass it to &lt;code&gt;setUsers&lt;/code&gt; and then make the fields empty.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from 'react';
import axios from "axios";

const AddUser = ({ setUsers, users }) =&amp;gt; {
    const [name, setName] = useState("")
    const [username, setUserName] = useState("")

    const handleSubmit = (e) =&amp;gt; {
        e.preventDefault();
        axios
            .post(`http://localhost:8000/users`, { name, username })
            .then((res) =&amp;gt; {
                setUsers([...users, res.data])
                setName('');
                setUserName('');
            });
    };

    return (
            &amp;lt;form onSubmit={handleSubmit}&amp;gt;
                &amp;lt;div className='flex flex-col justify-center items-center sm:flex-row sm:justify-evenly'&amp;gt;
                    &amp;lt;div className='mb-2'&amp;gt;
                        &amp;lt;input
                            className='px-3 py-1 rounded-full border border-gray-600'
                            value={name} onChange={(e) =&amp;gt; setName(e.target.value)} required
                            type="text" placeholder="Name" /&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;div className='mb-2'&amp;gt;
                        &amp;lt;input
                            className='px-3 py-1 rounded-full border border-gray-600'
                            value={username} onChange={(e) =&amp;gt; setUserName(e.target.value)} required
                            type="text" placeholder="UserName" /&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;div className='mb-2'&amp;gt;
                        &amp;lt;button className="bg-blue-500 hover:bg-blue-700 text-white py-1 px-3 rounded-full"&amp;gt;
                            Add
                        &amp;lt;/button&amp;gt;
                    &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
            &amp;lt;/form&amp;gt;
    );
}

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

&lt;/div&gt;



&lt;h5&gt;
  
  
  &lt;strong&gt;EditUser.js&lt;/strong&gt;:
&lt;/h5&gt;

&lt;p&gt;This component is for editing each user, after click on edit button then we navigate to this component. Here we have a &lt;code&gt;useEffect&lt;/code&gt; for loading the data that we want to edit and then a &lt;code&gt;handleSubmit&lt;/code&gt; function for submitting the edited item.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from "axios";
import { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router";

const EditUser = () =&amp;gt; {
  const [data, setData] = useState([])
  const [name, setName] = useState('');
  const [username, setUserName] = useState('');

  const { id } = useParams();
  const navigate = useNavigate()

  useEffect(() =&amp;gt; {
    axios.get("http://localhost:8000/users/" + id)
      .then(response =&amp;gt; {
        const data = response.data;
        setName(data.name);
        setUserName(data.username);
      })
      .catch(error =&amp;gt; console.log(error))
  }, [id])

  const handleSubmit = (e) =&amp;gt; {
    e.preventDefault()
    axios.put("http://localhost:8000/users/" + id, {
      name,
      username
    })
      .then(response =&amp;gt; {
        setData(response.data);
        navigate('/')
      })
  }

  const goHome = () =&amp;gt; {
    navigate('/')
  }

  return (
    &amp;lt;div className="flex items-center justify-center"&amp;gt;
      &amp;lt;form onSubmit={handleSubmit}&amp;gt;
        &amp;lt;div className='flex flex-col justify-center items-center bg-slate-100 p-10 mt-10 rounded-md'&amp;gt;
          &amp;lt;input
            className='my-2 px-5 py-1 rounded-full border border-gray-600'
            type="text" placeholder="Name"
            value={name}
            onChange={(e) =&amp;gt; setName(e.target.value)}
          /&amp;gt;
          &amp;lt;input
            className='my-2 px-5 py-1 rounded-full border border-gray-600'
            type="text" placeholder="UserName"
            value={username}
            onChange={(e) =&amp;gt; setUserName(e.target.value)}
          /&amp;gt;
          &amp;lt;div className="flex my-2"&amp;gt;
            &amp;lt;button
              className='text-white mx-1 px-5 py-1 rounded-full bg-blue-500 hover:bg-blue-700'&amp;gt;
              EDIT
            &amp;lt;/button&amp;gt;
            &amp;lt;button
              onClick={goHome}
              className='text-white mx-1 px-5 py-1 rounded-full bg-blue-500 hover:bg-blue-700'
            &amp;gt;
              CANCEL
            &amp;lt;/button&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;

  );
}

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

&lt;/div&gt;






&lt;p&gt;Now here we go! We created a simple &lt;code&gt;crud app&lt;/code&gt; with &lt;code&gt;react-hook&lt;/code&gt;, &lt;code&gt;json-server&lt;/code&gt;, &lt;code&gt;Axios&lt;/code&gt; and &lt;code&gt;Tailwind CSS&lt;/code&gt;. In the below I put links that are helpful for me to create this project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.taniarascia.com/crud-app-in-react-with-hooks/" rel="noopener noreferrer"&gt;Build a CRUD App in React with Hooks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading! 🍀&lt;/p&gt;

</description>
      <category>react</category>
      <category>crud</category>
      <category>axios</category>
      <category>tailwindcss</category>
    </item>
  </channel>
</rss>
