Fork me on GitHub
#ring-swagger
<
2017-07-04
>
lambder11:07:15

How compojure-api resource can accept text/plain in the body ?

ikitommi11:07:24

@lambder it's just a ring-handler, so if nothing is consuming the request body (e.g. no mappings in muuntaja for text/plain), you can slurp the :body and get the string. Adding :consumes ["text/plain"] also pushes that to swagger.

lambder11:07:42

can I have body binding to a the variable

lambder11:07:49

:parameters {:body-params  s/Str
                               :query-params {:version         s/Str
                                              :rule_name       s/Str
                                              :force_overwrite s/Str}}

lambder11:07:04

:handler (fn [{body :body-params {:keys [version rule_name]} :path-params}]

ikitommi11:07:53

That works if something handles the text/plain before the actual resource handlee. You can configure muuntaja to do that, either for api, subroutes or just for that resource. Here is the guide howto add new decoders: https://github.com/metosin/muuntaja/wiki/Creating-new-formats.

lambder11:07:59

@ikitommi when I create muuntaja config, how do i use it in compojure-api?

ikitommi11:07:05

There can be any number of muuntaja mws on the mw-chain, the first matching one does things, rest are ni-op.

lambder11:07:54

I can see the muuntaja/create result is stored in a var

lambder11:07:28

in https://github.com/metosin/muuntaja/wiki/Creating-new-formats there is:

(def m
  (muuntaja/create
    (assoc-in
      muuntaja/default-options
      [:formats "application/upper-json"]
      streaming-upper-case-json-format)))

(->> {:kikka 42}
     (muuntaja/encode m "application/json")
     (muuntaja/decode m "application/upper-json"))

lambder11:07:35

what do i do with m?

ikitommi11:07:42

you can pass it in to api under :formats

lambder11:07:45

do i put it onto :formats?

lambder11:07:50

😉 cool

ikitommi11:07:12

it takes either the new options map or a muuntaja instance

lambder11:07:16

@ikitommi is this correct:

lambder11:07:20

:formats    [(muuntaja/create
                                 (assoc-in
                                   muuntaja/default-options
                                   [:formats "application/upper-json"]
                                   streaming-upper-case-json-format))]

ikitommi11:07:59

we should spec all options...

lambder12:07:48

@ikitommi my resource is:

(resource
          {
           :post {
                  :parameters {:body-params  s/Str
                               :query-params {:version         s/Str
                                              :rule_name       s/Str
                                              :force_overwrite s/Str}}
                  :formats    (muuntaja/create
                                (assoc-in
                                  muuntaja/default-options
                                  [:formats "text/plain"]
                                  {:decoder identity}))
                  :consumes   ["text/plain"]
                  :responses  {http-status/created {:schema rest-schema/GenericResult}}
...

lambder12:07:59

but when I call it with

lambder12:07:21

POST /api/store_rule?rule_name=foo.logic&amp;force_overwrite=true&amp;version=1.1 HTTP/1.1
Host: localhost:7777
Content-Type: text/plain
Accept: application/json

TEXT

lambder12:07:34

i got

{
    "schema": "java.lang.String",
    "errors": "(not (instance? java.lang.String nil))",
    "type": "compojure.api.exception/request-validation",
    "coercion": "schema",
    "value": null,
    "in": [
        "request",
        "body-params"
    ]
}

ikitommi12:07:36

my bad, the :formats is currently only mapped to api. To use that in resource, you should use it via :middleware. something like: :middleware [[muuntaja.middleware/wrap-format options]]. And the :middleware is in the 2.0.0-alpha.

lambder12:07:42

i use [metosin/compojure-api "2.0.0-alpha3"]

ikitommi12:07:50

could integrate the :formats in, but after summer, or by someone else (PRs welcome)

ikitommi12:07:08

yes, should work with that

lambder12:07:27

:middleware [[muuntaja.middleware/wrap-format (muuntaja/create
                                                                  (assoc-in
                                                                    muuntaja/default-options
                                                                    [:formats "text/plain"]
                                                                    {:decoder identity}))]]

lambder12:07:39

@ikitommi what’s wrong?

ikitommi12:07:49

does not work? I think it's ok. Does that work as api :formats?

lambder12:07:57

my api is:

lambder12:07:33

(api
    {:swagger
               {:ui   "/"
                :spec "/swagger.json"



                :data {
                       

                }

     :coercion :schema

     :formats    (muuntaja/create
                   (assoc-in
                     muuntaja/default-options
                     [:formats "text/plain"]
                     {:decoder identity}))
     }

    (context "/api" []

      (context "/store_rule" []
        (resource
          {
           :post {

lambder12:07:54

it doesn’t work

lambder12:07:07

"errors": "(not (instance? java.lang.String nil))",

ikitommi12:07:10

ah, the decoder should be a function to create the decoder of opts

ikitommi12:07:26

(constantly identity)

ikitommi12:07:03

"with any options always decode with identity"

lambder12:07:30

same thing for

:formats    (muuntaja/create
                   (assoc-in
                     muuntaja/default-options
                     [:formats "text/plain"]
                     {:decoder (constantly identity)}))

lambder12:07:21

@ikitommi shouldn’t the value of :decoder be wrapped in a vector?

lambder12:07:03

same problem for :

:formats  (muuntaja/create
                 (assoc-in
                   muuntaja/default-options
                   [:formats "text/plain"]
                   {:decoder [(constantly identity)]}))

ikitommi12:07:58

If you add printing inside that, you should see what the decoder gets.

ikitommi12:07:01

it can be either a function or a duct-stylr vector. But ring passes in an InputStream, so (constantly slurp) to read it to string.

lambder12:07:35

@ikitommi I’m doing something fundamentally wrong

lambder12:07:41

even this is not working

lambder12:07:46

:formats  (muuntaja/create
                 (assoc-in
                   muuntaja/default-options
                   [:formats "text/plain"]
                   json-format/json-format))

lambder12:07:01

maybe I put `:formats’ in wrong place?

lambder12:07:25

should it be in the same level as the :coercion?

ikitommi12:07:14

I'm a week away from computer, can't test :( maybe @juhoteperi or @miikka could try to help

ikitommi12:07:20

yes, it should

lambder12:07:22

alright, thanks for your help @ikitommi

ikitommi12:07:41

oh, there is an example upper in this channel of formats.

lambder12:07:26

@ikitommi so this

:formats {:default-format "text/plain"
                :formats {"text/plain" streaming-upper-case-json-format
                          "application/json" streaming-upper-case-json-format
                          "application/vnd.api+json" streaming-upper-case-json-format}}
had the effect

lambder12:07:58

do you recon I can use (muuntaja/create in place of the data structure?

ikitommi12:07:13

yes, both should work.

lambder12:07:36

I try to upgrade version of compojure-api

lambder12:07:49

it doesn’t work with aplha3

lambder12:07:19

hmm, neither with alpha5

ikitommi12:07:29

oh, that's a bug then. Here's a guide how to use muuntaja with ring, should work the same with c-api

ikitommi12:07:39

Please write an issue out of that

lambder12:07:11

is there any fun which turns muuntaja into map?

ikitommi12:07:24

no, once created it a Record instance with lot's of internals for speed. But the create takes both options and records and returns an record.

lambder13:07:58

is it legel?

(context "/store_rule" []
        (resource
          {:post       {:middleware

lambder13:07:35

or it rather should be:

(context "/store_rule" []
        (resource
          {:middleware [...]
           :post       {

ikitommi13:07:54

both are ok. As the docs are far from good, you can look at the tests. The resource-test should cover most/all legal confifurations.

lambder13:07:06

this worked:

(def text-plain-format
  {:decoder [(fn make-json-decoder [options]
               (fn [x ^String charset]
                 (if (string? x)
                   x
                   (slurp (InputStreamReader. ^InputStream x charset)))))]

   :encoder [(fn make-json-encoder [options]
               (fn [data ^String charset]
                 (ByteArrayInputStream. (.getBytes data charset))))]})


        (resource {

                   :post {
                          :middleware [[muuntaja.middleware/wrap-format
                                        (muuntaja/create
                                          (assoc-in muuntaja/default-options
                                                    [:formats "text/plain"] text-plain-format))]]

...