Skip to content

Custom description for schema #388

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
vinibrsl opened this issue Oct 25, 2021 · 2 comments
Open

Custom description for schema #388

vinibrsl opened this issue Oct 25, 2021 · 2 comments

Comments

@vinibrsl
Copy link

vinibrsl commented Oct 25, 2021

Hello, y'all! 👋

Thank you for building open_api_spex. This is helping us to build well documented APIs in Elixir.

I have a Money schema used in other schemas. I would like to have the option to define a custom description when using Money. For example:

# lib/my_app/open_api/money.ex
defmodule MyApp.OpenApi.Money do
  require OpenApiSpex

  @example %{currency: "USD", amount: 182.32}
  def example, do: @example

  OpenApiSpex.schema(%{
    description: "Schema defining monetary amount in given currency",
    type: :object,
    example: @example,
    properties: %{
      currency: %OpenApiSpex.Schema{type: :string, description: "ISO 4217 alphabetic currency code", pattern: ~r/[A-Z]{3}/},
      amount: %OpenApiSpex.Schema{type: :number, description: "Monetary amount"}
    }
  })
end
# lib/my_app/open_api/order.ex
defmodule MyApp.OpenApi.Order do
  require OpenApiSpex

  @example %{
    "id" => 123_891,
    "subtotal" => MyApp.OpenApi.Money.example(),
    "total" => MyApp.OpenApi.Money.example(),
    "shipping_price" => MyApp.OpenApi.Money.example(),
  }
  def example, do: @example

  OpenApiSpex.schema(%{
    type: :object,
    example: @example,
    properties: %{
      id: %OpenApiSpex.Schema{type: :integer},
      subtotal: %OpenApiSpex.Schema{type: MyApp.OpenApi.Money, description: "Specific description about this field"},
      total: %OpenApiSpex.Schema{type: MyApp.OpenApi.Money, description: "Specific description about this field"},
      shipping_price: %OpenApiSpex.Schema{type: MyApp.OpenApi.Money, description: "Specific description about this field"}
    }
  })
end

I tried the above, defining type: MyApp.OpenApi.Money, but this seems to be invalid. If I use field: MyApp.OpenApi.Money, I can't define the description.

Is there a solution for this?

@mbuhot
Copy link
Collaborator

mbuhot commented Oct 26, 2021

Hi @vinibrsl 👋, glad to hear OpenApiSpex is helping you 👍

For your Order schema, I think you'll need to use a combination of $ref and description.
I think it may be supported in latest Open API specification (OAI/OpenAPI-Specification#556), but OpenApiSpex doesn't have a syntax to allow it conveniently.

You could try to approximate it with something like:

  OpenApiSpex.schema(%{
    type: :object,
    example: @example,
    properties: %{
      id: %OpenApiSpex.Schema{type: :integer},
      subtotal: %OpenApiSpex.Schema{
        allOf: [
          MyApp.OpenApi.Money, 
          %OpenApiSpex.Schema{description: "Specific description about this field"},
        ]
       },
      total: %OpenApiSpex.Schema{
        allOf: [
          MyApp.OpenApi.Money, 
          %OpenApiSpex.Schema{description: "Specific description about this field"}
        ]
      },
      shipping_price: %OpenApiSpex.Schema{
        allOf: [
          MyApp.OpenApi.Money, 
          %OpenApiSpex.Schema{description: "Specific description about this field"}
        ]
      }
    }
  })

@mbuhot
Copy link
Collaborator

mbuhot commented Oct 26, 2021

If you're up for sending a PR to OpenApiSpex, I think the fix would be to add summary and description fields to the %Reference{} struct, as per: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#reference-object.

Your example then becomes:

  OpenApiSpex.schema(%{
    type: :object,
    example: @example,
    properties: %{
      id: %OpenApiSpex.Schema{type: :integer},
      subtotal: %OpenApiSpex.Reference{
        "$ref": "/components/schema/MyApp.OpenApi.Money", 
        description: "Specific description about this field",
      },
      total: %OpenApiSpex.Reference{
        "$ref": "/components/schema/MyApp.OpenApi.Money", 
        description: "Specific description about this field",
      },
      shipping_price: %OpenApiSpex.Reference{
        "$ref": "/components/schema/MyApp.OpenApi.Money", 
        description: "Specific description about this field",
      }
    }
  })

We could also add a helper function to clear it up a bit, something like:

OpenApiSpex.schema(%{
  type: :object,
  example: @example,
  properties: %{
    id: %OpenApiSpex.Schema{type: :integer},
    subtotal: OpenApiSpex.reference(MyApp.OpenApi.Money, description: "Specific description about this field"),
    total: OpenApiSpex.reference(MyApp.OpenApi.Money, description: "Specific description about this field"),
    shipping_price: OpenApiSpex.reference(MyApp.OpenApi.Money, description: "Specific description about this field")
  }
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants