smithy-lang / smithy

Smithy is a protocol-agnostic interface definition language and set of tools for generating clients, servers, and documentation for any programming language.
https://smithy.io
Apache License 2.0
1.77k stars 208 forks source link

open-api plugin does not obey "effective documentation" precedence for member structures #2400

Open nated0g opened 1 week ago

nated0g commented 1 week ago

There appears to be a bug in the open-api plugin that leads to incorrectly applied documentation. This is causing some friction for us, requiring refactoring of our model to display documentation correctly. If the plugin behaved according to the documentation here: Effective documentation, we would not have any issue.

To repro:

model.smithy

$version: "2"

namespace example

use aws.api#service
use aws.protocols#restJson1

/// Cutting edge foo barring service, now with AI
@service(sdkId: "Foo")
@restJson1
service FooService {
    version: "2006-03-01"
    operations: [
        BarOperation
    ]
}

/// Performs a bar operation.
@http(uri: "/bar", method: "POST")
operation BarOperation {
    input: BarInput
    output: BarOutput
}

@documentation("It's a Quux")
structure Quux {
    quux: String
}

/// Input for the BarOperation.
structure BarInput {
    @required
    @documentation("It's a Bar")
    bar: Quux
}

/// Output for the BarOperation.
structure BarOutput {
    /// The result of the bar operation.
    result: String
}

smithy-build.json

{
  "version": "1.0",
  "maven": {
    "dependencies": [
      "software.amazon.smithy:smithy-aws-traits:1.51.0",
      "software.amazon.smithy:smithy-openapi:1.51.0"
    ]
  },
  "sources": ["model.smithy"],
  "plugins": {
    "openapi": {
      "service": "example#FooService",
      "protocol": "aws.protocols#restJson1"
    }
  }
}

This produces a model.json that correctly contains "It's a Bar" for the member's documentation:

 "example#BarInput": {
            "type": "structure",
            "members": {
                "bar": {
                    "target": "example#Quux",
                    "traits": {
                        "smithy.api#documentation": "It's a Bar", <-- correct
                        "smithy.api#required": {}
                    }
                }
            },
            "traits": {
                "smithy.api#documentation": "Input for the BarOperation."
            }
        },

however, the generated FooService.openapi.json contains a schema that looks like this:

{
        "schemas": {
            "BarOperationRequestContent": {
                "type": "object",
                "description": "Input for the BarOperation.",
                "properties": {
                    "bar": {
                        "$ref": "#/components/schemas/Quux" <-- missing "description"
                    }
                },
                "required": [
                    "bar"
                ]
            },
            "BarOperationResponseContent": {
                "type": "object",
                "description": "Output for the BarOperation.",
                "properties": {
                    "result": {
                        "type": "string",
                        "description": "The result of the bar operation."
                    }
                }
            },
            "Quux": {
                "type": "object",
                "description": "It's a Quux",
                "properties": {
                    "quux": {
                        "type": "string"
                    }
                }
            }
        }
    }

I expect to see:

                "properties": {
                    "bar": {
                        "$ref": "#/components/schemas/Quux",
                        "description": "It's a Bar" <--
                    }
                }
nated0g commented 1 week ago

The example from https://smithy.io/2.0/spec/documentation-traits.html#effective-documentation works correctly. This appears to specifically affect structure members.