Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास · पाठ

RESTful API बनाना

प्रमाणीकरण, सत्यापन और डेटा क्रमांकन सहित, शून्य से एक पूर्ण RESTful API बनाएँ

पाठ 1, कुल 4 में से12 चरण

RESTful API बनाना, CoddyKit पर Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास का एक निःशुल्क पाठ है। यह 4 में से 1वाँ पाठ है। आप नीचे पूरा पाठ निःशुल्क पढ़ सकते हैं—फिर अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर के साथ ब्राउज़र में इसका व्यावहारिक अभ्यास कर सकते हैं। यह Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

RESTful API क्या है

RESTful API (Representational State Transfer Application Programming Interface) कंप्यूटर सिस्टमों के लिए वेब पर संचार करने का एक मानक तरीका है।

यह संसाधनों पर कार्य करने के लिए मानक HTTP विधियों (जैसे GET, POST, PUT, DELETE) का उपयोग करता है। संसाधन डेटा या कार्यक्षमता के विशिष्ट भाग होते हैं।

मुख्य सिद्धांतों में शामिल हैं:

  • संसाधन: हर चीज़ एक संसाधन होती है (जैसे कोई उपयोगकर्ता या उत्पाद)।
  • स्टेटलेस होना: क्लाइंट से सर्वर को भेजे गए प्रत्येक अनुरोध में उस अनुरोध को समझने के लिए आवश्यक सारी जानकारी होनी चाहिए।
  • एकसमान इंटरफ़ेस: संसाधनों के साथ काम करने का एक सुसंगत तरीका।

हमारे कार्य प्रबंधक API का लक्ष्य

इस पाठ में हम एक सरल कार्य प्रबंधक API बनाएँगे। यह API हमें ये कार्य करने देगा:

  • नए कार्य बनाएँ।
  • सभी कार्यों की सूची बनाएँ।
  • किसी विशिष्ट कार्य को प्राप्त करें।
  • मौजूदा कार्य को अपडेट करें।
  • किसी कार्य को हटाएँ।

हम JSON डेटा को संभालने, मूल प्रमाणीकरण और इनपुट सत्यापन पर ध्यान देंगे।

अपना वेब सर्वर सेट अप करना

हम HTTP अमूर्तीकरण के लिए Ring और रूटिंग के लिए Compojure का उपयोग करेंगे। हमारे API सर्वर के लिए यह एक बुनियादी सेटअप है। हम अपने कार्य संसाधनों के लिए मार्ग परिभाषित करेंगे।

handler फ़ंक्शन अनुरोधों को संसाधित करेगा और run-jetty सर्वर शुरू करेगा।

(ns coddykit.api
  (:require [compojure.core :refer [defroutes GET POST PUT DELETE]]
            [compojure.route :as route]
            [ring.adapter.jetty :refer [run-jetty]]
            [ring.middleware.json :refer [wrap-json-response]]
            [ring.middleware.json :refer [wrap-json-body]])
  (:gen-class))

(defonce tasks (atom {}))

(defn create-task [task-data]
  (let [id (str (java.util.UUID/randomUUID))
        new-task (assoc task-data :id id)]
    (swap! tasks assoc id new-task)
    new-task))

(defroutes app-routes
  (GET "/tasks" [] {:status 200 :body (vals @tasks)})
  (POST "/tasks" req
    (let [task-data (:body req)
          new-task (create-task task-data)]
      {:status 201 :body new-task}))
  (route/not-found "Not Found"))

(defn wrap-api-middleware [handler]
  (-> handler
      (wrap-json-response)
      (wrap-json-body {:keywords? true :bigdec-enable? true})))

(def app (wrap-api-middleware app-routes))

(defn -main [& args]
  (println "Starting server on port 3000...")
  (run-jetty app {:port 3000 :join? false}))

JSON अनुरोध बॉडी को पार्स करना

जब क्लाइंट हमारे API को डेटा भेजते हैं (जैसे नया कार्य बनाने के लिए), तो वह अक्सर JSON प्रारूप में होता है। हमें इस JSON स्ट्रिंग को Clojure मैप में पार्स करना होगा।

ring.middleware.json/wrap-json-body मिडलवेयर यह काम हमारे लिए करता है। यह अनुरोध बॉडी को पार्स करके उससे बने Clojure मैप को (:body req) में रख देता है।

उदाहरण में, हमने JSON कुंजियों को Clojure कीवर्ड में अपने-आप बदलने के लिए (wrap-json-body {:keywords? true}) जोड़ा है।

JSON प्रतिक्रियाएँ बनाना

हमारे API को आम तौर पर JSON के रूप में क्लाइंट को डेटा वापस भेजना होता है। इसमें Clojure मैप को JSON स्ट्रिंग में बदलना और सही Content-Type हेडर सेट करना शामिल है।

ring.middleware.json/wrap-json-response मिडलवेयर यह काम संभालता है। यदि आपकी प्रतिक्रिया का :body Clojure मैप या वेक्टर है, तो यह उसे अपने-आप JSON में बदलकर "Content-Type": "application/json" सेट कर देता है।

आइए, किसी एक कार्य के लिए GET मार्ग जोड़ें।

(ns coddykit.api
  (:require [compojure.core :refer [defroutes GET POST PUT DELETE]]
            [compojure.route :as route]
            [ring.adapter.jetty :refer [run-jetty]]
            [ring.middleware.json :refer [wrap-json-response]]
            [ring.middleware.json :refer [wrap-json-body]])
  (:gen-class))

(defonce tasks (atom {}))

(defn create-task [task-data]
  (let [id (str (java.util.UUID/randomUUID))
        new-task (assoc task-data :id id)]
    (swap! tasks assoc id new-task)
    new-task))

(defroutes app-routes
  (GET "/tasks" [] {:status 200 :body (vals @tasks)})

  (GET "/tasks/:id" [id]
    (if-let [task (get @tasks id)]
      {:status 200 :body task}
      {:status 404 :body {:message "Task not found"}}))

  (POST "/tasks" req
    (let [task-data (:body req)
          new-task (create-task task-data)]
      {:status 201 :body new-task}))

  (route/not-found "Not Found"))

(defn wrap-api-middleware [handler]
  (-> handler
      (wrap-json-response)
      (wrap-json-body {:keywords? true :bigdec-enable? true})))

(def app (wrap-api-middleware app-routes))

(defn -main [& args]
  (println "Starting server on port 3000...")
  (run-jetty app {:port 3000 :join? false}))

मूल प्रमाणीकरण लागू करना

प्रमाणीकरण क्लाइंट की पहचान की पुष्टि करता है। एक सरल API के लिए हम Authorization हेडर में टोकन का उपयोग कर सकते हैं।

हम एक ऐसा मिडलवेयर फ़ंक्शन बनाएँगे, जो किसी विशिष्ट API कुंजी की जाँच करेगा। यदि वह अनुपस्थित या अमान्य है, तो हम 401 Unauthorized स्थिति लौटाएँगे।

यह मिडलवेयर हमारे मुख्य application मार्गों को घेरता है, जिससे हर अनुरोध इसके माध्यम से गुज़रता है।

(ns coddykit.api
  (:require [compojure.core :refer [defroutes GET POST PUT DELETE]]
            [compojure.route :as route]
            [ring.adapter.jetty :refer [run-jetty]]
            [ring.middleware.json :refer [wrap-json-response]]
            [ring.middleware.json :refer [wrap-json-body]])
  (:gen-class))

(defonce tasks (atom {}))
(def api-key "my-secret-api-key") ; Example API key

(defn create-task [task-data]
  (let [id (str (java.util.UUID/randomUUID))
        new-task (assoc task-data :id id)]
    (swap! tasks assoc id new-task)
    new-task))

(defn authenticate [handler]
  (fn [request]
    (let [auth-header (get-in request [:headers "authorization"])
          [_ token] (re-matches #"Bearer (.*)" auth-header)]
      (if (= token api-key)
        (handler request)
        {:status 401 :body {:message "Unauthorized"}}))))

(defroutes app-routes
  (GET "/tasks" [] {:status 200 :body (vals @tasks)})

  (GET "/tasks/:id" [id]
    (if-let [task (get @tasks id)]
      {:status 200 :body task}
      {:status 404 :body {:message "Task not found"}}))

  (POST "/tasks" req
    (let [task-data (:body req)
          new-task (create-task task-data)]
      {:status 201 :body new-task}))

  (route/not-found "Not Found"))

(defn wrap-api-middleware [handler]
  (-> handler
      (authenticate) ; Apply authentication first
      (wrap-json-response)
      (wrap-json-body {:keywords? true :bigdec-enable? true})))

(def app (wrap-api-middleware app-routes))

(defn -main [& args]
  (println "Starting server on port 3000...")
  (run-jetty app {:port 3000 :join? false}))

कार्यों के लिए इनपुट सत्यापन

सत्यापन यह सुनिश्चित करता है कि क्लाइंट से प्राप्त डेटा को संसाधित करने से पहले वह सही और पूरा हो। इससे त्रुटियाँ रुकती हैं और डेटा की अखंडता बनी रहती है।

हमारे कार्यों के लिए, आइए सुनिश्चित करें कि किसी कार्य को बनाते या अपडेट करते समय :title और :description हमेशा दिए गए हों।

यदि सत्यापन विफल होता है, तो हम उपयोगी त्रुटि संदेश के साथ 400 Bad Request लौटाएँगे।

(ns coddykit.api
  (:require [compojure.core :refer [defroutes GET POST PUT DELETE]]
            [compojure.route :as route]
            [ring.adapter.jetty :refer [run-jetty]]
            [ring.middleware.json :refer [wrap-json-response]]
            [ring.middleware.json :refer [wrap-json-body]])
  (:gen-class))

(defonce tasks (atom {}))
(def api-key "my-secret-api-key")

(defn create-task [task-data]
  (let [id (str (java.util.UUID/randomUUID))
        new-task (assoc task-data :id id)]
    (swap! tasks assoc id new-task)
    new-task))

(defn authenticate [handler]
  (fn [request]
    (let [auth-header (get-in request [:headers "authorization"])
          [_ token] (re-matches #"Bearer (.*)" auth-header)]
      (if (= token api-key)
        (handler request)
        {:status 401 :body {:message "Unauthorized"}}))))

(defn validate-task [task]
  (cond
    (nil? (:title task)) {:valid false :error "Title is required"}
    (nil? (:description task)) {:valid false :error "Description is required"}
    :else {:valid true}))

(defroutes app-routes
  (GET "/tasks" [] {:status 200 :body (vals @tasks)})

  (GET "/tasks/:id" [id]
    (if-let [task (get @tasks id)]
      {:status 200 :body task}
      {:status 404 :body {:message "Task not found"}}))

  (POST "/tasks" req
    (let [task-data (:body req)
          validation (validate-task task-data)]
      (if (:valid validation)
        (let [new-task (create-task task-data)]
          {:status 201 :body new-task})
        {:status 400 :body {:message (:error validation)}})))

  (route/not-found "Not Found"))

(defn wrap-api-middleware [handler]
  (-> handler
      (authenticate)
      (wrap-json-response)
      (wrap-json-body {:keywords? true :bigdec-enable? true})))

(def app (wrap-api-middleware app-routes))

(defn -main [& args]
  (println "Starting server on port 3000...")
  (run-jetty app {:port 3000 :join? false}))

संसाधनों को अपडेट करना और हटाना

अपने CRUD (Create, Read, Update, Delete) कार्य पूरे करने के लिए हमें PUT और DELETE मार्गों की आवश्यकता है। ये आम तौर पर उसके ID से पहचाने गए किसी विशिष्ट संसाधन पर काम करते हैं।

PUT अनुरोध किसी मौजूदा कार्य को अपडेट करता है, जबकि DELETE अनुरोध उसे हमारे tasks एटम से हटा देता है।

(ns coddykit.api
  (:require [compojure.core :refer [defroutes GET POST PUT DELETE]]
            [compojure.route :as route]
            [ring.adapter.jetty :refer [run-jetty]]
            [ring.middleware.json :refer [wrap-json-response]]
            [ring.middleware.json :refer [wrap-json-body]])
  (:gen-class))

(defonce tasks (atom {}))
(def api-key "my-secret-api-key")

(defn create-task [task-data]
  (let [id (str (java.util.UUID/randomUUID))
        new-task (assoc task-data :id id)]
    (swap! tasks assoc id new-task)
    new-task))

(defn authenticate [handler]
  (fn [request]
    (let [auth-header (get-in request [:headers "authorization"])
          [_ token] (re-matches #"Bearer (.*)" auth-header)]
      (if (= token api-key)
        (handler request)
        {:status 401 :body {:message "Unauthorized"}}))))

(defn validate-task [task]
  (cond
    (nil? (:title task)) {:valid false :error "Title is required"}
    (nil? (:description task)) {:valid false :error "Description is required"}
    :else {:valid true}))

(defroutes app-routes
  (GET "/tasks" [] {:status 200 :body (vals @tasks)})

  (GET "/tasks/:id" [id]
    (if-let [task (get @tasks id)]
      {:status 200 :body task}
      {:status 404 :body {:message "Task not found"}}))

  (POST "/tasks" req
    (let [task-data (:body req)
          validation (validate-task task-data)]
      (if (:valid validation)
        (let [new-task (create-task task-data)]
          {:status 201 :body new-task})
        {:status 400 :body {:message (:error validation)}})))

  (PUT "/tasks/:id" [id req]
    (let [updated-data (:body req)
          validation (validate-task updated-data)]
      (if (:valid validation)
        (if (get @tasks id)
          (do
            (swap! tasks update id merge updated-data)
            {:status 200 :body (get @tasks id)})
          {:status 404 :body {:message "Task not found"}})
        {:status 400 :body {:message (:error validation)}})))

  (DELETE "/tasks/:id" [id]
    (if (get @tasks id)
      (do
        (swap! tasks dissoc id)
        {:status 204 :body nil}) ; 204 No Content for successful deletion
      {:status 404 :body {:message "Task not found"}}))

  (route/not-found "Not Found"))

(defn wrap-api-middleware [handler]
  (-> handler
      (authenticate)
      (wrap-json-response)
      (wrap-json-body {:keywords? true :bigdec-enable? true})))

(def app (wrap-api-middleware app-routes))

(defn -main [& args]
  (println "Starting server on port 3000...")
  (run-jetty app {:port 3000 :join? false}))

आउटपुट के लिए डेटा सीरियलाइज़ेशन

कभी-कभी आपके डेटा के आंतरिक रूप में ऐसे फ़ील्ड हो सकते हैं, जिन्हें आप अपने API उत्तरों में सीधे दिखाना नहीं चाहते (जैसे आंतरिक ID, पासवर्ड या टाइमस्टैम्प)।

सीरियलाइज़ेशन आंतरिक डेटा संरचनाओं को API उत्तर के लिए उपयुक्त प्रारूप में बदलने की प्रक्रिया है। उदाहरण के लिए, हम यह सुनिश्चित करना चाह सकते हैं कि :created-at टाइमस्टैम्प किसी विशिष्ट स्ट्रिंग प्रारूप में हो।

JSON के रूप में भेजे जाने से पहले डेटा को 'साफ़' या फ़ॉर्मैट करने के लिए हम सहायक फ़ंक्शन बना सकते हैं।

(ns coddykit.api
  (:require [compojure.core :refer [defroutes GET POST PUT DELETE]]
            [compojure.route :as route]
            [ring.adapter.jetty :refer [run-jetty]]
            [ring.middleware.json :refer [wrap-json-response]]
            [ring.middleware.json :refer [wrap-json-body]])
  (:gen-class))

(defonce tasks (atom {}))
(def api-key "my-secret-api-key")

(defn create-task [task-data]
  (let [id (str (java.util.UUID/randomUUID))
        new-task (assoc task-data :id id :created-at (java.time.Instant/now))]
    (swap! tasks assoc id new-task)
    new-task))

(defn format-task-for-api [task]
  (-> task
      (update :created-at str) ; Convert Instant to string
      (dissoc :internal-field) ; Remove any internal fields
      ))

(defn authenticate [handler]
  (fn [request]
    (let [auth-header (get-in request [:headers "authorization"])
          [_ token] (re-matches #"Bearer (.*)" auth-header)]
      (if (= token api-key)
        (handler request)
        {:status 401 :body {:message "Unauthorized"}}))))

(defn validate-task [task]
  (cond
    (nil? (:title task)) {:valid false :error "Title is required"}
    (nil? (:description task)) {:valid false :error "Description is required"}
    :else {:valid true}))

(defroutes app-routes
  (GET "/tasks" [] {:status 200 :body (map format-task-for-api (vals @tasks))})

  (GET "/tasks/:id" [id]
    (if-let [task (get @tasks id)]
      {:status 200 :body (format-task-for-api task)}
      {:status 404 :body {:message "Task not found"}}))

  (POST "/tasks" req
    (let [task-data (:body req)
          validation (validate-task task-data)]
      (if (:valid validation)
        (let [new-task (create-task task-data)]
          {:status 201 :body (format-task-for-api new-task)})
        {:status 400 :body {:message (:error validation)}})))

  (PUT "/tasks/:id" [id req]
    (let [updated-data (:body req)
          validation (validate-task updated-data)]
      (if (:valid validation)
        (if (get @tasks id)
          (do
            (swap! tasks update id merge updated-data)
            {:status 200 :body (format-task-for-api (get @tasks id))})
          {:status 404 :body {:message "Task not found"}})
        {:status 400 :body {:message (:error validation)}})))

  (DELETE "/tasks/:id" [id]
    (if (get @tasks id)
      (do
        (swap! tasks dissoc id)
        {:status 204 :body nil})
      {:status 404 :body {:message "Task not found"}}))

  (route/not-found "Not Found"))

(defn wrap-api-middleware [handler]
  (-> handler
      (authenticate)
      (wrap-json-response)
      (wrap-json-body {:keywords? true :bigdec-enable? true})))

(def app (wrap-api-middleware app-routes))

(defn -main [& args]
  (println "Starting server on port 3000...")
  (run-jetty app {:port 3000 :join? false}))

API त्रुटियों को सुचारु रूप से संभालना

एक अच्छी तरह काम करने वाले API को समस्या आने पर हमेशा स्पष्ट त्रुटि संदेश और उपयुक्त HTTP स्थिति कोड देने चाहिए।

हम 401 Unauthorized, 404 Not Found और 400 Bad Request पहले ही देख चुके हैं। सर्वर की अप्रत्याशित समस्याओं के लिए 500 Internal Server Error मानक है।

आप वैश्विक त्रुटि-प्रबंधन मिडलवेयर या अपने मार्ग हैंडलर के भीतर विशिष्ट त्रुटि उत्तरों का उपयोग कर सकते हैं।

API निर्माण की त्वरित जाँच

API एंडपॉइंट के लिए निम्नलिखित Clojure हैंडलर फ़ंक्शन पर विचार करें:

(defn create-user-handler [request]
  (let [user-data (:body request)
        username (:username user-data)]
    (if (nil? username)
      {:status 400 :body {:message "Username is required"}}
      {:status 201 :body {:message (str "User " username " created!")}})))

यदि कोई क्लाइंट खाली बॉडी (या ऐसी गैर-JSON बॉडी, जिसके कारण (:body request) का मान nil हो) के साथ POST अनुरोध भेजता है, तो wrap-json-body और wrap-json-response मिडलवेयर सक्रिय होने पर यह हैंडलर कौन-सा HTTP स्थिति कोड और बॉडी लौटाएगा?

पुनरावलोकन: RESTful API बनाना

इस पाठ में आपने Clojure, Ring और Compojure का उपयोग करके RESTful API बनाने की मूल अवधारणाएँ सीखीं।

  • हमने संसाधनों को परिभाषित किया और HTTP विधियों को कार्यों से जोड़ा।
  • आपने आने वाले JSON अनुरोधों को पार्स करना और JSON प्रतिक्रियाएँ बनाना देखा।
  • हमने मिडलवेयर का उपयोग करके मूल प्रमाणीकरण लागू किया।
  • आपने डेटा की अखंडता सुनिश्चित करने के लिए इनपुट सत्यापन के बारे में सीखा।
  • अंत में, हमने डेटा सीरियलाइज़ेशन और प्रभावी त्रुटि प्रबंधन पर संक्षेप में चर्चा की।

ये किसी भी मजबूत बैकएंड सिस्टम के मूलभूत निर्माण खंड हैं!

शुरुआत निःशुल्क

एआई शिक्षक के साथ Clojure सीखें — निःशुल्क

अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।

पाठ्यक्रम
12
पाठ
48

अक्सर पूछे जाने वाले प्रश्न

क्या “RESTful API बनाना” पाठ निःशुल्क है?

हाँ—“RESTful API बनाना” का पूरा पाठ यहाँ वेब पर निःशुल्क पढ़ा जा सकता है। इंटरैक्टिव अभ्यास (अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर) करने और Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास पाठ्यक्रम का बाकी हिस्सा अनलॉक करने के लिए CoddyKit PRO लें। Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

“RESTful API बनाना” में मैं क्या सीखूँगा?

प्रमाणीकरण, सत्यापन और डेटा क्रमांकन सहित, शून्य से एक पूर्ण RESTful API बनाएँ आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

क्या Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?

पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 1वाँ पाठ है।

“RESTful API बनाना” पाठ पूरा करने में कितना समय लगता है?

CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।

क्या मैं इस Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास पाठ में कोड लिख और चला सकता हूँ?

हाँ। हर Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।

इस पाठ्यक्रम के सभी पाठ

  1. RESTful API बनाना
  2. इवेंट-आधारित आर्किटेक्चर
  3. सिस्टम डिज़ाइन और स्केलेबिलिटी पैटर्न
  4. प्रमाणीकरण और प्राधिकरण
← Clojure में कार्यात्मक प्रोग्रामिंग और JVM बैकएंड विकास पर वापस जाएँ