From 091f9002fcbaf2ad71852c4592a60f0f4b40ce25 Mon Sep 17 00:00:00 2001 From: Tormod Mathiesen Date: Wed, 30 Jan 2019 14:45:02 +0100 Subject: [PATCH] Create RESTful_form_methods.md After a short conversation on the clojurians slack, this is an example of how to do the "RESTful form method" pattern with reitit. --- doc/ring/RESTful_form_methods.md | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 doc/ring/RESTful_form_methods.md diff --git a/doc/ring/RESTful_form_methods.md b/doc/ring/RESTful_form_methods.md new file mode 100644 index 00000000..42185ade --- /dev/null +++ b/doc/ring/RESTful_form_methods.md @@ -0,0 +1,36 @@ +# RESTful form methods + +When designing RESTful applications you will be doing a lot of "PATCH" and "DELETE" request, but most browsers don't support methods other than "GET" and "POST" when it comes to submitting forms. + +There is a pattern to solve this (pioneered by Rails) using a hidden "_method" field in the form and swapping out the "POST" method for whatever is in that field. + +We can do this with middleware in reitit like this: +```clj +(defn- hidden-method + [request] + (keyword + (or (get-in request [:form-params "_method"]) ;; look for "_method" field in :form-params + (get-in request [:multipart-params "_method"])))) ;; or in :multipart-params + +(def wrap-hidden-method + {:name ::wrap-hidden-method + :wrap (fn [handler] + (fn [request] + (if-let [fm (and (= :post (:request-method request)) ;; if this is a :post request + (hidden-method request))] ;; and there is a "_method" field + (handler (assoc request :request-method fm)) ;; replace :request-method + (handler request))))}) +``` + +And apply the middleware like this: +```clj +(reitit.ring/ring-handler + (reitit.ring/router ...) + (reitit.ring/create-default-handler) + {:middleware + [reitit.ring.middleware.parameters/parameters-middleware ;; needed to have :form-params in the request map + reitit.ring.middleware.multipart/multipart-middleware ;; needed to have :multipart-params in the request map + wrap-hidden-method]}) ;; our hidden method wrapper +``` +(NOTE: This middleware must be placed here and not inside the route data given to `reitit.ring/handler`. +This is so that our middleware is applied before reitit matches the request with a spesific handler using the wrong method.)