oliyh / martian

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

Automatically handle application/vnd.blah.foo+json custom content types #143

Closed bombaywalla closed 2 years ago

bombaywalla commented 2 years ago

Many OpenAPI documents appear to have custom vendored Content-Types that are of the form application/vnd.blah.foo+json. One such example can be found at Amazon Ads API Manager Account. These are all JSON but with extra constraints. See RFC 6839 for the +json specification.

Martian allows custom content types, but it is tedious to add all the custom types by hand. Is there a recommended way to handle this situation?

If not, I propose that martian provide an optional way to treat vendored custom content types ending in +json to be the same as application/json for the purposes of encoding and decoding. It might be good (but not required, IMO) to provide for a mechanism to override the encoders / decoders for specific +json content types if needed.

I am happy to work on a PR if this is deemed useful.

I can envision several approaches:

  1. Provide a function that will scan an existing martian instance and return a new one with the additional encoders/decoders. I don't know the martian code well enough, but it appears that no information is lost from the OpenAPI definition and so this should be doable without impacting the existing code. The downside is that there would be duplicate implementations for each custom content type.
  2. Similar to the one above, but the custom content type handlers are (optionally) added dynamically as needed - if there is an already existing compatible supported content type. So, for example, if vnd.foo+json is searched for and not found, then if application/json is supported, martian will add vnd.foo+json to the list of supported types, with the same implementation as application/json.
  3. Checking to see if a particular content type is currently supported assumes an exact match between the content type and one of the supported content types. If the supported content type were to be a regex, then one single encoder/decoder could handle multiple content types. This would be a change in the semantics of martian, but could be backwards compatible. There might be precedence issues when more than one regex matches.

Thoughts?

oliyh commented 2 years ago

Hi,

In this situation, which seems quite specific to the services being called, I'm inclined to think it's a problem for the user to solve rather than martian: if the encoding/decoding interceptor provided is not sufficient, you can just write your own interceptor and use it instead.

One possible enhancement that I would consider would be (3) for the existing interceptor to accept regex patterns to match a decoder, however this might then mess with the existing ability of martian to inspect the supported content types of the API vs what it can support itself and negotiate the "best" format (at the moment, it only prefers transit > edn > json).

What do you think?

bombaywalla commented 2 years ago

Hi

From my limited experience, content types of the form application/vnd.foo.blah+json seem to be common. So, it would be helpful, but not necessary, for martian to provide support for such content types - especially since it already provides the encoders and decoders needed for this, as part of the application/json support.

I am currently tinkering with a solution akin to (1). I don't have any suggestion / proposal at the moment, but will share when I do.

What I am currently trying is:

bombaywalla commented 2 years ago

See what you think of this PR.