Fork me on GitHub
#ring-swagger
<
2018-08-14
>
stathissideris14:08:56

it seems like muuntaja doesn’t like this:

(GET "/echo" req
       :summary "foo"
       :return {:schema s/Any}
       (resp/ok req))

stathissideris14:08:15

I get:

<h2>HTTP ERROR: 500</h2>
<p>Problem accessing /api/echo. Reason:
<pre>    Malformed application/json in :muuntaja/encode</pre></p>
<hr /><i><small>Powered by Jetty://</small></i>

valtteri14:08:43

req contains probably stuff that can’t be serialized into JSON in a sensible way. Try returning (pr-str req) instead.

stathissideris14:08:30

progress, I now get this 500:

< HTTP/1.1 500 Server Error
< Date: Tue, 14 Aug 2018 14:41:30 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 2068
< Server: Jetty(9.2.24.v20180105)
<
* Connection #0 to host localhost left intact
{"schema":"{:schema Any}","errors":"(not (map? a-java.lang.String))","type":"compojure.api.exception/response-validation","coercion":"schema","value":"{:compojure.api.request/muuntaja <<Muuntaja>>, :compojure.api.request/coercion :schema, :compojure.api.request/swagger [{:consumes #{\"application/json\" \"application/transit+msgpack\" \"application/transit+json\" \"application/edn\"}, :produces #{\"application/json\" \"application/transit+msgpack\" \"application/transit+json\" \"application/edn\"}}], :ssl-client-cert nil, :protocol \"HTTP/1.1\", :compojure.api.request/paths {:paths #linked/map [[\"/api/foo\" {:get {:tags #{\"api\"}, :summary \"returns foo\"}}] [\"/api/echo\" {:get {:tags #{\"api\"}, :summary \"echoes the request\", :responses {200 {:schema {:schema Any}, :description \"\"}}}}] [\"/api/hello\" {:get {:tags #{\"api\"}, :parameters {:query {:name java.lang.String}}, :responses {200 {:schema {:message java.lang.String}}, 404 {}, 500 {:schema Any}}, :summary \"greets you\"}}]]}, :remote-addr \"0:0:0:0:0:0:0:1\", :ring.swagger.middleware/data {:info {:title \"Geniki Taxydromiki API\", :description \"\"}, :tags [{:name \"api\", :description \"some apis\"}]}, :params {}, :compojure.api.request/lookup {:compojure.api.swagger/swagger {\"/swagger.json\" {:method :get}}}, :route-handler #function[compojure.core/wrap-response/fn--16907], :route-params {}, :headers {\"user-agent\" \"curl/7.54.0\", \"accept\" \"*/*\", \"host\" \"localhost:8080\"}, :server-port 8080, :muuntaja/request nil, :content-length nil, :form-params {}, :compojure/route [:get \"/echo\"], :query-params {}, :content-type nil, :path-info \"/echo\", :character-encoding nil, :context \"/api\", :uri \"/api/echo\", :server-name \"localhost\", :query-string nil, :muuntaja/response #FormatAndCharset{:format \"application/json\", :charset \"utf-8\"}, :body #object[org.eclipse.jetty.server.HttpInputOverHTTP 0x6c72f437 \"HttpInputOverHTTP@6c72f437\"], :scheme :http, :request-method :get, :route-middleware #function[clojure.core/comp/fn--5529]}","in":["response","body"]}%

stathissideris14:08:03

I’m not sure how compojure.api decides what content-type to send…

valtteri14:08:02

And.. I think this definition

:return {:schema s/Any}
means that it’s expecting a map with key :schema and any value from the handler. I think you probably want to have just
:return s/Any

stathissideris14:08:03

correct! I do get a string now

valtteri14:08:12

No problem!

stathissideris14:08:39

but still. say I wanted this particular endpoint to return html, how would I do it?

valtteri14:08:03

Hmmm I don’t remember from top of my head but you could try returning something like this from the handler

{:status 200
 :body "<html><body><p>blabalbal</p></body></html>"
 :headers {"Content-Type" "text/html"}}

stathissideris14:08:32

(GET "/echo" req
       :summary "echoes the request"
       :return s/Any
       (-> (str "<pre>" (with-out-str (pp/pprint req)) "<pre>")
           resp/ok
           (resp/content-type "text/html")))

stathissideris14:08:01

this (which I suspect is equivalent to your solution) turns the body into a string first

stathissideris14:08:14

so it doesn’t render properly

stathissideris14:08:12

confirmed, the result looks the same as the map that you suggested

stathissideris14:08:45

I think there is something downstream which quotes my string

stathissideris14:08:13

(probably muuntaja?)

valtteri14:08:08

Hmmm maybe it works if you give it a stream instead of string?

valtteri15:08:05

I tested with reitit library which uses Muuntaja as well and returning a html string from handler with content-type text/html works as expected

valtteri15:08:31

You could try removing :return s/Any completely and see if that has any effect

valtteri15:08:26

How are you testing this btw?

stathissideris15:08:00

So I tried this (don’t really know what I’m doing but it didn’t work):

(api
 {...
  :formats {"text/html" {:decode identity
                         :encode identity}}}
 ...)

stathissideris15:08:15

for testing I’m just hitting

valtteri15:08:07

And you’re seeing extra quotes around html in http response?

stathissideris15:08:16

so it looks like it was serialized as a JSON string

stathissideris15:08:59

it’s not a huge deal, but I’m evaluating compojure-api and I’d like to understand what it does

valtteri15:08:14

It’s data driven compared to macros in c-api. Makes it easier to understand and use

stathissideris15:08:54

for a second it looked like bidi and I panicked 😄

valtteri15:08:14

However, I’ve had success with c-api in the past as well. 🙂 They’re both good libs but now my vote goes to reitit

stathissideris15:08:51

I like the more data-driven approach…

stathissideris15:08:04

and you do get swagger for free, right?

stathissideris15:08:21

my only qualm is -SNAPSHOT

stathissideris15:08:43

thanks, I’ll definitely check it out

stathissideris15:08:12

do you happen to have any inside info on when we could expect a non-snapshot release?

stathissideris15:08:50

@ikitommi ☝️ any info on when we could expect a non-snapshot release of reitit?

ikitommi16:08:34

@stathissideris for c-api, if you define a :return for an endpoint, it is an "api-response" and is always returned in the negotiated format, e.g. json. This enables returning primitives like Strings & Numbers. For html, just omit the :return.

stathissideris16:08:08

oh great, thanks!

stathissideris16:08:09

yeah, I guess that would be good too, I think when the user of the API sets their own header it’s like they’re assuming responsibility for formatting the content too, right?

ikitommi16:08:51

yes, think so too.

ikitommi16:08:44

the last stable release in reitit is 0.1.3, but the docs are eagerly promoting the next SNAPSHOT. Will try to push out in the next few days. Actually, the data-driven version of Muuntaja is the last thing to do.

stathissideris16:08:08

you know, I’ve been on a tour of liberator (a while ago), pedestal, yada, compojure etc, and I think reitit looks like the best fit for my brain. That’s why I’m so eager to use it (great work!)

ikitommi17:08:09

Thanks! It’s for people who like to be in control of things. No magic, no macros, no default middleware / interceptors. Syntax is “hiccup for routing”. Has been fun trying to make it as fast as possible.

stathissideris17:08:10

yes exactly, the “magic” is my main problem with the rest of the solutions out there… so about the maturity level of reitit, have you used it production yet? would you recommend it for such use? (I will not consider your reply legally binding 😄 )