Fork me on GitHub
#reitit
<
2021-12-29
>
dharrigan07:12:43

Hi Janet, did you get your problem resolved?

Janet A. Carr14:12:17

I did not. 😛

dharrigan14:12:35

I didn't seem to have a problem when I used the route on my setup, but let me delve further.

dharrigan14:12:28

❯ http --verbose :8080/plain/plus x=10 y=20
POST /plain/plus HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 22
Content-Type: application/json
Host: localhost:8080
User-Agent: HTTPie/2.6.0

{
    "x": "10",
    "y": "20"
}


HTTP/1.1 200 OK
Content-Length: 12
Content-Type: application/json;charset=utf-8

{
    "total": 30
}

dharrigan14:12:25

So, apart from one change, works for me.

dharrigan14:12:49

What problem are you experiencing btw?

Janet A. Carr14:12:14

Null pointer exception. The body-params are nil by the time they reach the handler.

Janet A. Carr14:12:35

well, :body-params in the request is nil

dharrigan14:12:11

Right, well, I don't get that 🙂

dharrigan14:12:19

how are you posting the data?

Janet A. Carr14:12:32

postman and curl. I thought it might be my POST. I thought it was interesting that you tried strings of integers instead of actual integers in your json, but that didn't work for me either.

dharrigan14:12:31

Right, since the default is to assume textual data (without context)

dharrigan14:12:57

So, I just changed one bit

dharrigan14:12:59

(def janet-router
  (ring/ring-handler
   (ring/router
    [["/plain"
      ["/plus" {:get (fn [{{:strs [x y]} :query-params :as req}]
                       {:status 200
                        :body {:total (+ (Long/parseLong x) (Long/parseLong y))}})
                :post (fn blah [{{:keys [x y]} :body-params}]
                        {:status 200
                         :body {:total (+ (Long/parseLong x) (Long/parseLong y))}})}]]]
    {:data {:coercion reitit.coercion.spec/coercion
            :muuntaja m/instance
            :middleware [parameters/parameters-middleware
                         muuntaja/format-middleware
                         coercion/coerce-exceptions-middleware
                         coercion/coerce-request-middleware
                         coercion/coerce-response-middleware]}})
   (ring/create-default-handler)))

dharrigan14:12:22

since, no "spec" was defined for the input data, reitit won't coerece the data for you

dharrigan14:12:30

(personally, I use malli)

Janet A. Carr14:12:32

so spec worked, that's nice. This also means the examples in the reitit repo are wrong, so I might be making a PR soon. While I have you, I'm going to try malli because I was using it before and also got stuck.

dharrigan14:12:54

(def ::x int?)
(def ::y int?)
(def ::post-params (s/keys :req-un [::x ::y]))

(def janet-router
  (ring/ring-handler
   (ring/router
    [["/plain"
      ["/plus" {:get (fn [{{:strs [x y]} :query-params :as req}]
                       {:status 200
                        :body {:total (+ (Long/parseLong x) (Long/parseLong y))}})
                :post {:handler (fn blah [{{:keys [x y]} :body-params}]
                        {:status 200
                         :body {:total (+ x y)})
                      :parameters {:body ::post-params}})}]]]
    {:data {:coercion reitit.coercion.spec/coercion
            :muuntaja m/instance
            :middleware [parameters/parameters-middleware
                         muuntaja/format-middleware
                         coercion/coerce-exceptions-middleware
                         coercion/coerce-request-middleware
                         coercion/coerce-response-middleware]}})
   (ring/create-default-handler)))

dharrigan14:12:17

❯ http --verbose :8080/plain/plus x:=10 y:=20
POST /plain/plus HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 18
Content-Type: application/json
Host: localhost:8080
User-Agent: HTTPie/2.6.0

{
    "x": 10,
    "y": 20
}


HTTP/1.1 200 OK
Content-Length: 12
Content-Type: application/json;charset=utf-8
Date: Wed, 29 Dec 2021 14:29:33 GMT
Server: Jetty(9.4.42.v20210604)

{
    "total": 30
}

dharrigan14:12:27

I have an example of using malli here:

dharrigan14:12:00

(I must bring that project up-to-date)

Janet A. Carr14:12:21

have you ever tried in-router data specs?

dharrigan14:12:26

what do you mean?

dharrigan14:12:42

Can you elaborate further?

dharrigan14:12:05

Sure, I've used that too

dharrigan14:12:37

(def janet-router
  (ring/ring-handler
   (ring/router
    [["/plain"
      ["/plus" {:get (fn [{{:strs [x y]} :query-params :as req}]
                       {:status 200
                        :body {:total (+ (Long/parseLong x) (Long/parseLong y))}})
                :post {:handler (fn blah [{{:keys [x y]} :body-params}]
                                   {:status 200
                                    :body {:total (+ x y)}})
                       :parameters {:body {:x int? :y int?}}}}]]]
    {:data {:coercion reitit.coercion.spec/coercion
            :muuntaja m/instance
            :middleware [parameters/parameters-middleware
                         muuntaja/format-middleware
                         coercion/coerce-exceptions-middleware
                         coercion/coerce-request-middleware
                         coercion/coerce-response-middleware]}})
   (ring/create-default-handler)))

dharrigan14:12:48

❯ http --verbose :8080/plain/plus x:=10 y=20 
POST /plain/plus HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 20
Content-Type: application/json
Host: localhost:8080
User-Agent: HTTPie/2.6.0

{
    "x": 10,
    "y": "20"
}


HTTP/1.1 400 Bad Request
Content-Length: 348
Content-Type: application/json;charset=utf-8
Date: Wed, 29 Dec 2021 14:48:59 GMT
Server: Jetty(9.4.42.v20210604)

{
    "coercion": "spec",
    "in": [
        "request",
        "body-params"
    ],
    "problems": [
        {
            "in": [
                "y"
            ],
            "path": [
                "y"
            ],
            "pred": "clojure.core/int?",
            "val": "20",
            "via": [
                "spec$44271/y"
            ]
        }
    ],
    "spec": "(spec-tools.core/spec {:spec (clojure.spec.alpha/keys :req-un [:spec$44271/x :spec$44271/y]), :type :map, :leaf? false})",
    "type": "reitit.coercion/request-coercion",
    "value": {
        "x": 10,
        "y": "20"
    }
}

dharrigan14:12:11

and with the right data being sent...

dharrigan14:12:13

❯ http --verbose :8080/plain/plus x:=10 y:=20
POST /plain/plus HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 18
Content-Type: application/json
Host: localhost:8080
User-Agent: HTTPie/2.6.0

{
    "x": 10,
    "y": 20
}


HTTP/1.1 200 OK
Content-Length: 12
Content-Type: application/json;charset=utf-8
Date: Wed, 29 Dec 2021 14:49:58 GMT
Server: Jetty(9.4.42.v20210604)

{
    "total": 30
}

tami523:12:46

I have the similar issue to @janetacarr, but In my case I'm trying to get :parameters, however, only when adding coercion middleware on the route it self, I get paramters.

{:summary "Plus with body-params"
   :parameters {:body {:x int?, :y int?}}
   :handler (fn [{{{:keys [x y]} :body} :parameters :as req}]
              (spy (keys req)) ;; no parameters
              {:status 200
               :body {:total (+ x y)}})}

1
tami501:12:59

nvm, I passed :data key value, instead of hash-map with :data key