Hi, I'm looking at this doc https://github.com/metosin/reitit/blob/master/doc/ring/RESTful_form_methods.md Does this only work with middleware? I tried to do this with interceptor but doesn't work, the handler that it goes to is still the POST handler instead of DELETE. The reason i need this is because I'm working with hiccup and unpoly, and I wanted to use form to delete a resource.
it does run, as you see in the one with hidden delete, the :request-method is :delete
Reitit ring-handler only finds the match once using the initial path and request-method, it doesn't try try to check if an interceptor makes changes to those
Or well, the question is at which point the interceptors run.
Route-data middleware obviously run only after the match is available.
ring-handler middlware run before the match is chosen.
If you check reitit.http, you see the reitit.http/ring-handler interceptors option is implemented by adding those interceptors to route-data.
Those only run after the match is found
Here is the interceptor:
(defn- get-hidden-method
"Extract the override method from form or query parameters."
[request]
(some-> (or (get-in request [:form-params "_method"]) ; Look in form params
(get-in request [:multipart-params "_method"]) ; Or multipart params
(get-in request [:query-params "_method"]) ; Or query params
(get-in request [:params "_method"])) ; Or merged params
str/lower-case
keyword))
(defn method-override
"Interceptor that overrides the HTTP method based on _method parameter.
Only overrides POST requests to prevent security issues.
Usage:
Add this interceptor to your route configuration:
{:interceptors [(method-override)]}
In your HTML form:
<form method=\"POST\" action=\"/resource\">
<input type=\"hidden\" name=\"_method\" value=\"DELETE\">
<button type=\"submit\">Delete</button>
</form>
Docs:
- "
[]
{:name ::method-override
:enter
(fn [ctx]
(-> ctx
(update
:request
(fn [req]
(-> req
(medley/assoc-some
:request-method
(when-let [override-method
(and (= :post (-> req :request-method))
(get-hidden-method req))]
override-method)))))))}) so i suppose its not possible to do it currently unless i use pedestal or other library?
Is the interceptor running? When these things aren't working as I expect, I tend to put a line at the top of the interceptor (def ctx ctx) and start evaluating. Try that and make sure everything looks like you expect it.
I read pedestal's code about the method-param interceptor and how it was used.
It seems the router matching is done in an interceptor instead.
I see there is this reitit-http/routing-interceptor but no example or test written for it, can anyone give me an example on how to use it?
I can't think of a reason it wouldn't work in an interceptor. What exactly is going wrong and how are you using it?
Here is an example of what i did
(let [post-handler (fn [req]
(println "POST handler")
(pp req)
(http-resp/ok))
delete-handler (fn [req]
(println "DELETE handler")
(pp req)
(http-resp/ok))
routes
["/"
{:post {:handler post-handler}
:delete {:handler delete-handler}}]
ring-handler
(reitit.http/ring-handler
(reitit.http/router routes {})
{:executor reitit.interceptor.sieppari/executor
:inject-match? false
:inject-router? false
:data {}
:interceptors
[(reitit.http.interceptors.parameters/parameters-interceptor)
(muuntaja.interceptor/format-interceptor
(-> muuntaja/default-options
(assoc-in [:formats "application/json"] ginoco-ring/json-muuntaja-format)
muuntaja/create))
(reitit.http.coercion/coerce-exceptions-interceptor)
(reitit.http.coercion/coerce-response-interceptor)
(reitit.http.coercion/coerce-request-interceptor)
(reitit.http.interceptors.multipart/multipart-interceptor)
(gini.interceptor/method-override)]})]
(println "===== POST request =====")
(ring-handler (http-mock/request :post "/"))
(println "===== POST request with hidden DELETE =====")
(ring-handler (http-mock/request :post "/?_method=delete")))
===== POST request =====
POST handler
{:form-params {}
:headers {"host" "localhost"}
:params {}
:path-params {}
:protocol "HTTP/1.1"
:query-params {}
:remote-addr "127.0.0.1"
:request-method :post
:scheme :http
:server-name "localhost"
:server-port 80
:uri "/"
:muuntaja/request nil
:muuntaja/response #muuntaja.core.FormatAndCharset
{:charset "utf-8" :format "application/json" :raw-format nil}}
===== POST request with hidden DELETE =====
POST handler
{:form-params {}
:headers {"host" "localhost"}
:params {"_method" "delete"}
:path-params {}
:protocol "HTTP/1.1"
:query-params {"_method" "delete"}
:query-string "_method=delete"
:remote-addr "127.0.0.1"
:request-method :delete
:scheme :http
:server-name "localhost"
:server-port 80
:uri "/"
:muuntaja/request nil
:muuntaja/response #muuntaja.core.FormatAndCharset
{:charset "utf-8" :format "application/json" :raw-format nil}}I was expecting the second request which is the POST with hidden DELETE is going to hit the delete-handler, but it didn't