guardrail icon indicating copy to clipboard operation
guardrail copied to clipboard

Only one response type is generated

Open sammy-da opened this issue 2 years ago • 1 comments

Hello! Thanks for this library.

I wanted to have a server endpoint return different response schemas depending on the media type, like so:


    "/login": {
        "post": {
            "description": "Mint token",
            "operationId": "mintAccountTokenFromSiteCredential",
            "responses": {
                "200": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/MintAccountTokenFromSiteCredentialResponse"
                            }
                        },
                        "text/plain": {
                            "schema": {
                                "$ref": "#/components/schemas/AccountToken"
                            }
                        }
                    },
                    "description": "account access token"
                }
            }
        }
    }

I see the generated code doesn't permit providing the text/plain response, as there's only code for providing the object response:

  case class MintAccountTokenFromSiteCredentialResponseOK(value: _root_.com.damlhub.openapi.definitions.MintAccountTokenFromSiteCredentialResponse) extends MintAccountTokenFromSiteCredentialResponse(StatusCodes.OK)

When removing the application/json and keeping only the text/plain response:

  case class MintAccountTokenFromSiteCredentialResponseOK(value: String) extends MintAccountTokenFromSiteCredentialResponse(StatusCodes.OK)

Also, I assume I would have to manually add the Accept header to the openapi definition to be able to decide which response Media Type to return in my handlers?

sammy-da avatar Sep 06 '22 19:09 sammy-da

This is a pretty significant change, and an unfortunate oversight in the initial structuring of the respond type.

I've been thinking the way forward is to extend the self-type with an additional content-type scope, like respond.ApplicationJson.Ok(...), maintaining the current functionality to some degree with @deprecation notices, but even then I think that the constructors to those responders should be call-by-name and total, so that no matter what Accepts is sent by the client we can correctly respond but also not waste compute.

To that end, it would probably end up looking more like respond.Ok(textPlain: => A, applicationJson: => B).

In the meantime, you can work around this by adding a parameter, in: header, name: Accept in order to get access to what's being requested by the client, as well as using the guardrail vendor extension x-server-raw-response: true inside the Operation (at the same level as operationId in your spec) in order to be able to emit the underlying datatype for whatever framework you are using.

Sorry you're running into this, and thanks for the report!

blast-hardcheese avatar Sep 06 '22 22:09 blast-hardcheese