সংক্ষিপ্ত বিবরণ (কিছু পরিমাণে)
বিশেষ দ্রষ্টব্য। আমি কমপোজার 0.4.1 এর সাথে কাজ করছি ( এখানে গিটহাবের 0.4.1 রিলিজ কমিট)।
কেন?
একেবারে শীর্ষে compojure/core.clj, কমপোজারের উদ্দেশ্যটির এই সহায়ক সংক্ষিপ্তসারটি রয়েছে:
রিং হ্যান্ডলারগুলি উত্পাদন করার জন্য একটি সংক্ষিপ্ত বাক্য গঠন।
একটি পৃষ্ঠের স্তরে, "কেন" প্রশ্নটিই এখানে রয়েছে। কিছুটা গভীরভাবে যেতে, আসুন এক ঝলক দেখি কীভাবে একটি রিং-স্টাইল অ্যাপ্লিকেশন কাজ করে:
একটি অনুরোধ উপস্থিত হয়েছে এবং রিং অনুমান অনুসারে ক্লোজার ম্যাপে রূপান্তরিত হয়েছে।
এই মানচিত্রটি একটি তথাকথিত "হ্যান্ডলার ফাংশন" হিসাবে সজ্জিত হয়েছে, যা প্রত্যাশা তৈরি করবে বলে আশা করা হচ্ছে (এটি ক্লোজার ম্যাপও)।
প্রতিক্রিয়া মানচিত্র একটি প্রকৃত HTTP প্রতিক্রিয়া রূপান্তরিত এবং ক্লায়েন্ট ফিরে পাঠানো হয়।
উপরের ২ য় ধাপটি সবচেয়ে আকর্ষণীয়, কারণ অনুরোধে ব্যবহৃত ইউআরআই পরীক্ষা করা, কোনও কুকিজ ইত্যাদি পরীক্ষা করা এবং শেষ পর্যন্ত উপযুক্ত প্রতিক্রিয়াতে পৌঁছানো হ্যান্ডলারের দায়িত্ব। স্পষ্টতই এটি প্রয়োজনীয় যে এই সমস্ত কাজটি সুসংজ্ঞায়িত টুকরোগুলির সংকলনে রূপান্তরিত করা উচিত; এগুলি সাধারণত একটি "বেস" হ্যান্ডলার ফাংশন এবং এটি মোড়ানো মিডওয়্যার ফাংশনগুলির একটি সংগ্রহ। কমপোজারের উদ্দেশ্যটি বেস হ্যান্ডলার ফাংশনের প্রজন্মকে সহজতর করা।
কিভাবে?
"রুট" ধারণার চারপাশে কমপেজ তৈরি করা হয়েছে। এগুলি আসলে ক্লাউট গ্রন্থাগার দ্বারা গভীর স্তরে প্রয়োগ করা হয়েছে (কমপোজার প্রকল্পের একটি স্পিনফ - 0.3.x -> 0.4.x স্থানান্তরে অনেকগুলি পৃথক গ্রন্থাগারে স্থানান্তরিত করা হয়েছিল)। একটি রুট (1) একটি HTTP পদ্ধতি (জিইটি, পুট, হেড ...) দ্বারা সংজ্ঞায়িত করা হয়েছে, (২) একটি ইউআরআই প্যাটার্ন (সিনট্যাক্সের সাথে নির্দিষ্ট করা হবে যা সম্ভবত ওয়েববি রুবিবাদীদের সাথে পরিচিত হবে), (3) একটি কাঠামোগত ফর্ম ব্যবহৃত অনুরোধের মানচিত্রের অংশগুলি শরীরে উপলব্ধ নামগুলিতে আবদ্ধ করা (4) এমন একটি ভাবের সংশ্লেষ যা একটি বৈধ রিং প্রতিক্রিয়া তৈরি করতে পারে (অ-তুচ্ছ ক্ষেত্রে এটি সাধারণত একটি পৃথক ফাংশনটির জন্য কেবল একটি কল)।
সাধারণ উদাহরণটি দেখার জন্য এটি ভাল পয়েন্ট হতে পারে:
(def example-route (GET "/" [] "<html>...</html>"))
আসুন এটি আরইপিএলে পরীক্ষা করুন (নীচের অনুরোধের মানচিত্রটি সর্বনিম্ন বৈধ রিংয়ের অনুরোধ মানচিত্রটি):
user> (example-route {:server-port 80
:server-name "127.0.0.1"
:remote-addr "127.0.0.1"
:uri "/"
:scheme :http
:headers {}
:request-method :get})
{:status 200,
:headers {"Content-Type" "text/html"},
:body "<html>...</html>"}
তাহলে :request-methodছিল :headপরিবর্তে, প্রতিক্রিয়া হবে nil। আমরা nilএক মিনিটে এখানে কী বোঝাতে চাইছি তার প্রশ্নে ফিরে আসব (তবে লক্ষ্য করুন যে এটি কোনও বৈধ রিং রিসোস নয়!)।
যেমন এই উদাহরণ থেকে স্পষ্ট, example-routeকেবল একটি ফাংশন, এবং এটি একটি খুব সহজ একটি; এটি অনুরোধটির দিকে নজর দেয়, এটি পরিচালনা করতে আগ্রহী কিনা তা নির্ধারণ করে (পরীক্ষা করে :request-methodএবং :uri) এবং যদি তাই হয় তবে একটি প্রাথমিক প্রতিক্রিয়ার মানচিত্র ফেরত দেয়।
যা স্পষ্ট তা হল যে রুটের মূল অংশটি সঠিক প্রতিক্রিয়ার মানচিত্রে মূল্যায়ন করার প্রয়োজন নেই; কমপোজার স্ট্রিংগুলির জন্য বুদ্ধিমান ডিফল্ট হ্যান্ডলিং সরবরাহ করে (উপরে দেখানো হয়েছে) এবং অন্যান্য অবজেক্টের বিভিন্ন ধরণের; দেখতে compojure.response/renderবিস্তারিত জানার জন্য multimethod (কোড সম্পূর্ণভাবে স্বয়ংসম্পূর্ণ দলিল এখানে)।
আসুন defroutesএখন ব্যবহার করার চেষ্টা করুন :
(defroutes example-routes
(GET "/" [] "get")
(HEAD "/" [] "head"))
উপরে প্রদর্শিত উদাহরণ অনুরোধের প্রতিক্রিয়া এবং এর বৈকল্পিকের সাথে :request-method :headপ্রত্যাশার মতো।
এর অভ্যন্তরীণ কাজগুলি example-routesএমন যে প্রতিটি রুটের পরিবর্তে চেষ্টা করা হয়; যত তাড়াতাড়ি তাদের মধ্যে একটি nilপ্রতিক্রিয়া ফিরিয়ে দেয় , সেই প্রতিক্রিয়া পুরো example-routesহ্যান্ডলারের রিটার্ন মান হয়ে যায় । একটি অতিরিক্ত সুবিধা হিসাবে, - defroutesসংজ্ঞায়িত হ্যান্ডলারগুলি মোড়ানো wrap-paramsএবং wrap-cookiesঅন্তর্নিহিতভাবে।
আরও জটিল রুটের উদাহরণ এখানে:
(def echo-typed-url-route
(GET "*" {:keys [scheme server-name server-port uri]}
(str (name scheme) "://" server-name ":" server-port uri)))
পূর্বে ব্যবহৃত খালি ভেক্টরের জায়গায় ধ্বংসাত্মক ফর্মটি নোট করুন। এখানে মূল ধারণাটি হ'ল রুটের মূল অংশটি অনুরোধ সম্পর্কে কিছু তথ্যে আগ্রহী হতে পারে; যেহেতু এটি সর্বদা একটি মানচিত্রের আকারে আসে তাই অনুরোধ থেকে তথ্য বের করতে এবং স্থানীয় ভেরিয়েবলগুলিতে বাঁধতে একটি সহযোগী ডেস্ট্রাকচারিং ফর্ম সরবরাহ করা যেতে পারে যা রুটের শিবিরের ফাঁকে থাকবে।
উপরের একটি পরীক্ষা:
user> (echo-typed-url-route {:server-port 80
:server-name "127.0.0.1"
:remote-addr "127.0.0.1"
:uri "/foo/bar"
:scheme :http
:headers {}
:request-method :get})
{:status 200,
:headers {"Content-Type" "text/html"},
:body "http://127.0.0.1:80/foo/bar"}
উপরের উজ্জ্বল ফলো-আপ ধারণাটি হ'ল আরও জটিল রুটগুলি assocমিলের পর্যায়ে অনুরোধের উপরে অতিরিক্ত তথ্য পেতে পারে:
(def echo-first-path-component-route
(GET "/:fst/*" [fst] fst))
এই সঙ্গে প্রতিক্রিয়াশীল :bodyএর "foo"পূর্ববর্তী উদাহরণ থেকে অনুরোধ করতে পারি।
দুটি জিনিস এই সর্বশেষ উদাহরণ সম্পর্কে নতুন আছেন: "/:fst/*"এবং অ খালি বাঁধাই ভেক্টর [fst]। প্রথমটি ইউআরআই নিদর্শনগুলির জন্য উল্লিখিত রেলস এবং সিনট্রা জাতীয় সিনট্যাক্স। এটি ইউআরআই বিভাগগুলিতে রিজেক্স সীমাবদ্ধতার উপরোক্ত উদাহরণ থেকে যা দৃশ্যমান তার চেয়ে কিছুটা পরিশীলিত (উদাহরণস্বরূপ উপরের সমস্ত অংকের ["/:fst/*" :fst #"[0-9]+"]মানগুলি রুটটিকে গ্রহণ করার জন্য সরবরাহ করা যেতে পারে :fst)। দ্বিতীয়টি :paramsঅনুরোধ মানচিত্রে প্রবেশের সাথে মিলের সহজতর উপায় , যা নিজেই একটি মানচিত্র; এটি অনুরোধ, ক্যোরি স্ট্রিং প্যারামিটার এবং ফর্ম পরামিতিগুলি থেকে ইউআরআই বিভাগগুলি উত্তোলনের জন্য দরকারী। পরবর্তী দৃষ্টান্তটি বর্ণনা করার জন্য একটি উদাহরণ:
(defroutes echo-params
(GET "/" [& more]
(str more)))
user> (echo-params
{:server-port 80
:server-name "127.0.0.1"
:remote-addr "127.0.0.1"
:uri "/"
:query-string "foo=1"
:scheme :http
:headers {}
:request-method :get})
{:status 200,
:headers {"Content-Type" "text/html"},
:body "{\"foo\" \"1\"}"}
প্রশ্নের পাঠ্য থেকে উদাহরণটি দেখার জন্য এটি ভাল সময় হবে:
(defroutes main-routes
(GET "/" [] (workbench))
(POST "/save" {form-params :form-params} (str form-params))
(GET "/test" [& more] (str "<pre>" more "</pre>"))
(GET ["/:filename" :filename #".*"] [filename]
(response/file-response filename {:root "./static"}))
(ANY "*" [] "<h1>Page not found.</h1>"))
আসুন পরিবর্তে প্রতিটি রুট বিশ্লেষণ করুন:
(GET "/" [] (workbench))- যখন কোনও GETঅনুরোধের সাথে ডিল করার সময় :uri "/", ফাংশনটি কল করুন workbenchএবং যা প্রতিক্রিয়া মানচিত্রে ফিরে আসে তা রেন্ডার করুন। (মনে রাখবেন যে ফেরতের মান মানচিত্র হতে পারে তবে একটি স্ট্রিং ইত্যাদিও থাকতে পারে)
(POST "/save" {form-params :form-params} (str form-params))- মিডওয়্যারের :form-paramsদ্বারা সরবরাহিত অনুরোধ মানচিত্রে একটি প্রবেশিকা wrap-params(এটি প্রত্যক্ষভাবে অন্তর্ভুক্ত করা হয়েছে তা প্রত্যাহার করুন defroutes)। প্রতিক্রিয়া মান হতে হবে {:status 200 :headers {"Content-Type" "text/html"} :body ...}সঙ্গে (str form-params)প্রতিস্থাপিত ...। (কিছুটা অস্বাভাবিক POSTহ্যান্ডলার, এটি ...)
(GET "/test" [& more] (str "<pre> more "</pre>"))- এটি উদাহরণস্বরূপ মানচিত্রের স্ট্রিং উপস্থাপনাটিকে প্রতিধ্বনিত করবে {"foo" "1"}যদি ব্যবহারকারী এজেন্ট জিজ্ঞাসা করে "/test?foo=1"।
(GET ["/:filename" :filename #".*"] [filename] ...)- :filename #".*"অংশটি কিছুই করে না (যেহেতু #".*"সবসময় মেলে)। এটি ring.util.response/file-responseতার প্রতিক্রিয়া তৈরি করতে রিং ইউটিলিটি ফাংশনটিকে কল করে ; {:root "./static"}অংশ বলা হয়েছে যে সব যেখানে ফাইলের জন্য দেখুন।
(ANY "*" [] ...)- একটি ক্যাচ-অল রুট। নিয়মিতভাবে defroutesসংজ্ঞায়িত হ্যান্ডলারটি একটি বৈধ রিং প্রতিক্রিয়া মানচিত্র ফেরত দেয় তা নিশ্চিত করার জন্য (ফর্মের সাথে ব্যর্থতার ফলস্বরূপ কোনও রুট মিলে যায় nil) তা নিশ্চিত করার জন্য ফর্মের শেষে এই জাতীয় রুট অন্তর্ভুক্ত করা সর্বদা ভাল অনুশীলন অনুশীলন ।
কেন এভাবে?
রিং মিডলওয়্যারের একটি উদ্দেশ্য হল অনুরোধের মানচিত্রে তথ্য যুক্ত করা; এইভাবে কুকি-হ্যান্ডলিং মিডলওয়্যার :cookiesঅনুরোধটিতে একটি কী wrap-paramsযুক্ত করে, :query-paramsএবং যোগ করে এবং / অথবা:form-paramsযদি কোনও কোয়েরি স্ট্রিং / ফর্ম ডেটা উপস্থিত থাকে এবং ততক্ষণ। (কড়া কথায় বলতে গেলে মিডলওয়্যারের ফাংশনগুলি যুক্ত করা সমস্ত তথ্য ইতিমধ্যে অনুরোধের মানচিত্রে উপস্থিত থাকতে হবে, যেহেতু তারা এগুলি পাস হয়; তাদের কাজ হ'ল তাদের মোড়ানো হ্যান্ডলারের সাথে কাজ করা আরও সুবিধাজনক হওয়ার জন্য তাদের কাজটি এটি রূপান্তর করা)) শেষ পর্যন্ত "সমৃদ্ধ" অনুরোধটি বেস হ্যান্ডলারের কাছে প্রেরণ করা হয়েছে, যা মিডওয়্যার দ্বারা যুক্ত সমস্ত প্রিপ্রোসেসড তথ্য সহ অনুরোধের মানচিত্রটি পরীক্ষা করে এবং একটি প্রতিক্রিয়া তৈরি করে। (মিডলওয়্যার এর চেয়ে জটিল জিনিসগুলি করতে পারে - যেমন বেশ কয়েকটি "অভ্যন্তরীণ" হ্যান্ডলার মোড়ানো এবং তাদের মধ্যে বেছে নেওয়া, মোড়ক হ্যান্ডলার (গুলি) কে আদৌ কল করতে হবে কিনা তা সিদ্ধান্ত নেওয়া ইত্যাদি That এটি অবশ্য এই উত্তরের বাইরে নয় outside)
বেস হ্যান্ডলারটি ঘুরে দেখা যায় সাধারণত (অ-তুচ্ছ ঘটনাগুলিতে) এমন একটি ফাংশন যা অনুরোধ সম্পর্কে কেবল কয়েকটি মুষ্টিমেয় আইটেমের প্রয়োজন হয়। (উদাহরণস্বরূপ ring.util.response/file-responseবেশিরভাগ অনুরোধের যত্ন নেই; এটির জন্য কেবল একটি ফাইলের নাম প্রয়োজন)) সুতরাং একটি রিংয়ের অনুরোধের কেবলমাত্র প্রাসঙ্গিক অংশগুলি বের করার একটি সহজ পদ্ধতির প্রয়োজন। কমপোজোর লক্ষ্য ছিল একটি বিশেষ-উদ্দেশ্য প্যাটার্ন মেলানো ইঞ্জিন সরবরাহ করা, যেমনটি ছিল, যা কেবল এটি করে।