oliyh / martian

The HTTP abstraction library for Clojure/script, supporting OpenAPI, Swagger, Schema, re-frame and more
MIT License
525 stars 42 forks source link

Adding custom encoder does not get chosen if there is a mix of reply contents that include at least one of the default encodings. #187

Open mmeroberts opened 10 months ago

mmeroberts commented 10 months ago

There is a function in the encoding namespace as follows:

(defn choose-content-type [encoders options]
  (some (set options) (keys encoders)))

By default this picks only one encoding even if options contains more that one possible.

Multiple Accept content types can occur when the response has multiple responses such as 200, and 400. Each of these might have different mime types.

In my swagger I have application/yaml as the happy path Accept content type. So I added a customer encoder:

(def yaml-encoder yaml/parse-string)
(def yaml-decoder yaml/generate-string)

(def encoders (into (linked/ordered-map {"application/yaml" {:encode yaml-encoder
                                                             :decode yaml-decoder
                                                             :as :yaml}}) (encoders/default-encoders)))

I then added this to my martian as follows:

(def m (martian-http/bootstrap-openapi "resources/api.yaml"
                                       {:interceptors
                                        (concat martian-http/default-interceptors
                                                [add-authentication-header
                                                 allow-insecure
                                                 (i/encode-body encoders)
                                                 (i/coerce-response encoders)
                                                 martian-http/perform-request] 
                                                )}))

However, when I run the request-for on a suitable end point I only see Accept application/json.

And when I run the response-for function I get a 415 as the response is yaml.

There appear to be a couple of options for fixing this: Change the choose-content-type to give a comma separated list this could be done using:

(defn choose-content-type [encoders options]
     (str/join ", " (filter (set options) (keys encoders)))

However as @oliyh points out this might change the existing behaviour. To get round this one option would be to enable users to define weights for their custom encodings and then the result list could include weights.

I think it would be fair to say that I don't know how many endpoints worry about the weights of responses, but clearly it is there for a purpose. My expectations would be that the weights would come into play on a single success response so that you could say that you wanted a choice of responses depending upon what the server could deliver - If that is the case would that not be indicated in the OpenAPI spec?