Haskell-OpenAPI-Code-Generator / Haskell-OpenAPI-Client-Code-Generator

Generate Haskell client code from an OpenAPI 3 specification
46 stars 19 forks source link

API spec with mime type application/vnd.xxx #105

Closed schoettl closed 3 months ago

schoettl commented 4 months ago

Another question: The Xentral ERP OpenAPI spec declares custom mime types like application/vnd.xxx+json.

…
        "operationId": "product.view",
        "summary": "View product",
        "description": "Returns details of a single product",
        "responses": {
          "200": {
            "description": "Operation completed successfully.",
            "content": {
              "application/vnd.xentral.default.v1+json": {

…

yields

data Product'viewResponse =
   Product'viewResponseError GHC.Base.String -- ^ Means either no matching case available or a parse error
  | Product'viewResponse200 -- ^ Operation completed successfully.
  | Product'viewResponse400 -- ^ IETF RFC 7807 Problem API compliant response
  …

with no actual response data type.

The custom vendor mime types seem to be generally OK but seem to be unsupported by this generator. It might make sense to change the parser to handle regex application/(vnd\.[\a\d]+\+)?json as JSON.

I just did search & replace with application/json, then types were generated.

The next problem is that the Xentral API server requires the exact mime type specified in their spec and it does not respond to requests with Accept: application/json. I think it's not a good design decision by Xentral. But this maybe should be considered when implementing support vendor mime types in this generator.

I now have to work around this... my plan is to use this config:

  let config = Configuration { configBaseURL = "https://xxx.xentral.biz"
                             , configSecurityScheme = addXentralAuthHeader "xxxx" . HS.addRequestHeader "Accept" "application/vnd.xentral.default.v1+json"
                             , configIncludeUserAgent = False
                             , configApplicationName = "xxx"
                             }

Though, even worse, Xentral declares different vendor mime types so I need to generate a map for looking up the specific mime type for each operation.

joel-bach commented 4 months ago

Hey @schoettl , currently we indeed only support application/json (optionally with a charset which is ignored). We could add the JSON API mime type but I am not sure I want to add the customized ones as well 🤔 I wonder if it would be better to make the JSON mime types configurable so anyone can define a mime type to be interpreted as JSON by the generator. What do you think?

Regarding Accept header: We do not send any Accept header atm (see https://github.com/Haskell-OpenAPI-Code-Generator/Haskell-OpenAPI-Client-Code-Generator/issues/98). While I think it would be great to have this as part of the generator, I do not think I will be able to implement this myself in the foreseeable future. If you want to open a PR with an implementation for this, I'd be happy to review it. If not, either doing it with the security scheme or with the way outlined in the referenced issue are the best ways to handle this atm.

schoettl commented 4 months ago

Thanks for the response!

I actually think that allowing all mime types with +json suffix and interpreting them as json might be better. Because as I understand the RFCs referenced here at Swagger media types with that suffix are syntactically json even though the semantics is more specific.

I guess there are many OpenAPI specs out there that declare these type of json media types and I don't see downsides of allowing them by default. On the other hand, users of this generator wouldn't need to modify the spec in dozens of places after they find out why no Haskell types are generated – or find all different custom media types to whitelist them via command line flags.

For example, in my spec – weather it's good or bad – there are:

$ grep -oE 'application/.*\+json' openapi/xentral-api.openapi-3.0.0.json | sort | uniq
application/problem+json
application/vnd.xentral.batch.v1+json
application/vnd.xentral.default.v1+json
application/vnd.xentral.default.v1-alpha+json
application/vnd.xentral.default.v1-beta+json
application/vnd.xentral.default.v2-beta+json
application/vnd.xentral.force.v1+json
application/vnd.xentral.fromreturn.v1-beta+json
application/vnd.xentral.fromsalesorder.v1-beta+json
application/vnd.xentral.hierarchy.v1+json
application/vnd.xentral.minimal.v1+json
application/vnd.xentral.minimal.v1-beta+json
application/vnd.xentral.password.v1+json
application/vnd.xentral.upsert.v1-beta+json
application/vnd.xentral.upsert.v2-beta+json
application/vnd.xentral.user-permissions.v1+json

And there are JSON specs like GeoSpec, JSON API, GitHub also uses their vnd types...

Regarding the Accept header: I think, for me the configuration security schema is the simplest way. I like your idea in that comment of adding a way to add headers. The most generic way however would be a function with the same type as the security schema which is kind of redundant.

joel-bach commented 3 months ago

Hey @schoettl I agree with you that all +json media types need to be interpreted as JSON, so I've merged a PR to make sure this is the case. Can you check if this does what it needs to for you and in case everything works, close this issue?

schoettl commented 3 months ago

Hi @joel-bach Just upgraded and tested – works great! Thank you!