Fork me on GitHub
#reitit
<
2022-08-21
>
vonadz11:08:36

I'm sending a form data POST request from Postman to an API I'm making, but I can't seem to get the form data key values to appear anywhere on the request object. What am I doing wrong? Below is the code

(ns vonadz.xpromo
  (:require [ring.adapter.jetty :as ring-jetty]
            [reitit.ring :as ring]
            [ring.util.response :as r]
            [muuntaja.core :as m]
            [reitit.ring.middleware.muuntaja :as muuntaja]
            [reitit.ring.middleware.parameters :as parameters] ;; needed to have :form-params in the request map
            [reitit.ring.middleware.multipart :as multipart]   ;; needed to have :multipart-params in the request map
            ))

(defn create-post
  [req]
  (clojure.pprint/pprint req)
  {:body "hello" :status 201})

(def app
  (ring/ring-handler
   (ring/router
    ["/"
     ["api/"
      ["create-post/" {:post create-post}]]
     ["" {:handler (fn [req] {:body "Create redirect screen" :status 200})}]]
    {:data {:muuntaja m/instance
            :middleware [muuntaja/format-middleware
                         parameters/parameters-middleware ;; needed to have :form-params in the request map
                         multipart/multipart-middleware   ;; needed to have :multipart-params in the request map
                         ]}})))

(defn start []
  (ring-jetty/run-jetty #'app {:port  3001
                               :join? false}))

(def server (start))
This is what my request looks like in /api/create-post/:
{:reitit.core/match
 {:template "/api/create-post/",
  :data
  {:muuntaja <<Muuntaja>>,
   :middleware
   [{:name :reitit.ring.middleware.muuntaja/format,
     :spec :reitit.ring.middleware.muuntaja/spec,
     :compile
     #object[reitit.ring.middleware.muuntaja$fn__5400 0x488c5670 "reitit.ring.middleware.muuntaja$fn__5400@488c5670"]}
    {:name :reitit.ring.middleware.parameters/parameters,
     :compile
     #object[reitit.ring.middleware.parameters$fn__9401 0x70d5b190 "reitit.ring.middleware.parameters$fn__9401@70d5b190"],
     :wrap
     #object[ring.middleware.params$wrap_params 0x53032f49 "ring.middleware.params$wrap_params@53032f49"]}
    {:name :reitit.ring.middleware.multipart/multipart,
     :compile
     #object[reitit.ring.middleware.multipart$compile$fn__10885 0x4bdc0c29 "reitit.ring.middleware.multipart$compile$fn__10885@4bdc0c29"]}],
   :post
   {:handler
    #object[vonadz.xpromo$create_post 0x797dbc01 "vonadz.xpromo$create_post@797dbc01"]}},
  :result
  {:get nil,
   :head nil,
   :post
   {:data
    {:muuntaja <<Muuntaja>>,
     :middleware
     [{:name :reitit.ring.middleware.muuntaja/format,
       :spec :reitit.ring.middleware.muuntaja/spec,
       :compile
       #object[reitit.ring.middleware.muuntaja$fn__5400 0x488c5670 "reitit.ring.middleware.muuntaja$fn__5400@488c5670"]}
      {:name :reitit.ring.middleware.parameters/parameters,
       :compile
       #object[reitit.ring.middleware.parameters$fn__9401 0x70d5b190 "reitit.ring.middleware.parameters$fn__9401@70d5b190"],
       :wrap
       #object[ring.middleware.params$wrap_params 0x53032f49 "ring.middleware.params$wrap_params@53032f49"]}
      {:name :reitit.ring.middleware.multipart/multipart,
       :compile
       #object[reitit.ring.middleware.multipart$compile$fn__10885 0x4bdc0c29 "reitit.ring.middleware.multipart$compile$fn__10885@4bdc0c29"]}],
     :handler
     #object[vonadz.xpromo$create_post 0x797dbc01 "vonadz.xpromo$create_post@797dbc01"]},
    :handler
    #object[muuntaja.middleware$wrap_format$fn__5365 0x162b5bb8 "muuntaja.middleware$wrap_format$fn__5365@162b5bb8"],
    :path "/api/create-post/",
    :method :post,
    :middleware
    [{:name :reitit.ring.middleware.muuntaja/format,
      :wrap
      #object[reitit.ring.middleware.muuntaja$fn__5400$fn__5402 0x7cc5406f "reitit.ring.middleware.muuntaja$fn__5400$fn__5402@7cc5406f"],
      :spec :reitit.ring.middleware.muuntaja/spec,
      :data
      {:swagger
       {:produces
        #{"application/json"
          "application/transit+msgpack"
          "application/transit+json"
          "application/edn"},
        :consumes
        #{"application/json"
          "application/transit+msgpack"
          "application/transit+json"
          "application/edn"}}}}
     {:name :reitit.ring.middleware.parameters/parameters,
      :wrap
      #object[ring.middleware.params$wrap_params 0x53032f49 "ring.middleware.params$wrap_params@53032f49"],
      :spec nil}]},
   :put nil,
   :delete nil,
   :connect nil,
   :options
   {:data
    {:muuntaja <<Muuntaja>>,
     :middleware
     [{:name :reitit.ring.middleware.muuntaja/format,
       :spec :reitit.ring.middleware.muuntaja/spec,
       :compile
       #object[reitit.ring.middleware.muuntaja$fn__5400 0x488c5670 "reitit.ring.middleware.muuntaja$fn__5400@488c5670"]}
      {:name :reitit.ring.middleware.parameters/parameters,
       :compile
       #object[reitit.ring.middleware.parameters$fn__9401 0x70d5b190 "reitit.ring.middleware.parameters$fn__9401@70d5b190"],
       :wrap
       #object[ring.middleware.params$wrap_params 0x53032f49 "ring.middleware.params$wrap_params@53032f49"]}
      {:name :reitit.ring.middleware.multipart/multipart,
       :compile
       #object[reitit.ring.middleware.multipart$compile$fn__10885 0x4bdc0c29 "reitit.ring.middleware.multipart$compile$fn__10885@4bdc0c29"]}],
     :no-doc true,
     :handler
     #object[reitit.ring$fn__4094$fn__4103 0x4548b90b "reitit.ring$fn__4094$fn__4103@4548b90b"]},
    :handler
    #object[muuntaja.middleware$wrap_format$fn__5365 0xe51115e "muuntaja.middleware$wrap_format$fn__5365@e51115e"],
    :path "/api/create-post/",
    :method :options,
    :middleware
    [{:name :reitit.ring.middleware.muuntaja/format,
      :wrap
      #object[reitit.ring.middleware.muuntaja$fn__5400$fn__5402 0x41daaba7 "reitit.ring.middleware.muuntaja$fn__5400$fn__5402@41daaba7"],
      :spec :reitit.ring.middleware.muuntaja/spec,
      :data
      {:swagger
       {:produces
        #{"application/json"
          "application/transit+msgpack"
          "application/transit+json"
          "application/edn"},
        :consumes
        #{"application/json"
          "application/transit+msgpack"
          "application/transit+json"
          "application/edn"}}}}
     {:name :reitit.ring.middleware.parameters/parameters,
      :wrap
      #object[ring.middleware.params$wrap_params 0x53032f49 "ring.middleware.params$wrap_params@53032f49"],
      :spec nil}]},
   :trace nil,
   :patch nil},
  :path-params {},
  :path "/api/create-post/"},
 :reitit.core/router
 #object[reitit.core$lookup_router$reify__3694 0x5d17d09f "reitit.core$lookup_router$reify__3694@5d17d09f"],
 :ssl-client-cert nil,
 :protocol "HTTP/1.1",
 :remote-addr "0:0:0:0:0:0:0:1",
 :params {},
 :headers
 {"accept" "*/*",
  "user-agent" "PostmanRuntime/7.28.4",
  "connection" "keep-alive",
  "postman-token" "097154cc-f13c-4837-8ccd-9d534bd38bc7",
  "host" "localhost:3001",
  "accept-encoding" "gzip, deflate, br",
  "content-length" "804",
  "content-type"
  "multipart/form-data; boundary=--------------------------315684979322398934625772"},
 :server-port 3001,
 :muuntaja/request
 {:format nil, :charset "utf-8", :raw-format "multipart/form-data"},
 :content-length 804,
 :form-params {},
 :query-params {},
 :content-type
 "multipart/form-data; boundary=--------------------------315684979322398934625772",
 :character-encoding nil,
 :uri "/api/create-post/",
 :server-name "localhost",
 :query-string nil,
 :path-params {},
 :muuntaja/response
 {:format "application/json", :charset "utf-8", :raw-format "*/*"},
 :body
 #object[org.eclipse.jetty.server.HttpInputOverHTTP 0x7491e3ca "HttpInputOverHTTP@7491e3ca[c=0,q=0,[0]=null,s=STREAM]"],
 :scheme :http,
 :request-method :post}

vonadz15:08:53

OK I was able to get the multipart-params showing by remove [reitit.ring.middleware.multipart :as multipart] and replacing it with [ring.middleware.multipart-params :as multipart] and using multipart/wrap-multipart-params

craftybones14:08:53

Is there a way to validate requests running through middleware? It would be great to be able to spec a middleware to enforce a request containing a key

ikitommi14:08:21

not at the moment. But would be easy to add such a thing, e.g. new key into Middleware map-definition to describe the request schema and using a middleware chain transformer to interleave a request-validation middleware between each mw. I would not use this is prod (slow), but for dev, might be useful. All can be done in user space already, see https://cljdoc.org/d/metosin/reitit/0.5.18/doc/ring/transforming-middleware-chain for examples

ikitommi16:08:26

I think such a thing could be merged into reitit itself. Optional batteries for the win 🙂

ikitommi16:08:14

looking forward to what you cook out of this.

craftybones14:08:12

this would help guarantee middleware chains are wired in the right order

vonadz15:08:05

Is there middleware that handles automatically changing multipart-params (and other params) key values to keywords instead of strings?

pppaul16:08:41

multipart uses a coercer, so it should support that

👍 1