OpenApiSpex - OpenAPI / Swagger 3.0 for Plug APIs

Yes, plugs in a Phoenix controller are run before the controller action is run: Phoenix.Controller — Phoenix v1.7.10

1 Like

Version 3.9.0 is released!

This release comes with some new features and some bug fixes:

  • Feature: Generate example from schema (#266)
  • Feature: Allow SwaggerUI to be configured via Plug opts (#271)
  • Feature: Warn on invalid or missing operation specs (#273, #278)
  • Feature: Experimental alternative API for defining Operation specs (#265, #280)
  • Fix: Handle the same operation occurring at different routes (#272)
  • Fix: Casting header names that have upper-case letters in specs (#281)
  • Maint: Upgrade Elixir dependencies in example projects (#269)
  • Maint: Format project with Elixir Formatter (#279)

As always, a huge thank you to all the contributors and maintainers for keeping the project going :heart:

4 Likes

Hi. Is https://github.com/xerions/phoenix_swagger a similar project? What’s the relation to this lib? I see that @mbuhot has contributed to both. Is one preferred over the other? Which should I go with if starting from scratch?

@GenericJam the biggest difference is that PhoenixSwagger will generate swagger 2.0 API definitions, while OpenApiSpex generates OpenAPI (swagger 3.0) API definitions.

For new projects I’d recommend OpenApiSpex unless you are required to produce swagger 2.0 files for consumption by other tooling.

3 Likes

@mbuhot Thanks for the reply. Maybe the two should mention each other if you’re looking for the other one. As is on the surface it looks like they’re competing.

1 Like

Version 3.10.0 is released!

  • Feature: Support OAuth2 for swagger-ui (#217)
  • Feature: Support default response type in responses (#301)
  • Feature: Allow overriding x-struct in OpenApiSpex.schema/1 (#304)
  • Feature: Ability to specify deprecated in ControllerSpec operation (#296)
  • Feature: :struct? and :derive? options in OpenApiSpex.schema/1 (#312)
  • Feature: OpenApiSpex.add_schemas/2 (#314)
  • Enhancement: Remove api_spec data from Conn (#286)
  • Enhancement: More informative errors for bad schema (#288, #284, #287)
  • Fix: Convert :format value to atom when decoding schema file (#293)
  • Fix: Type spec in OpenApiSpex.Info
  • Fix: Elixir Formatter rules in published package (#306)
  • Docs: Fix spelling error in example code (#295)
  • Docs: Fix type in README (#297)
  • Docs: Fix links and punctuation in README (#298)
  • Docs: Promote ControlerSpecs as the preferred API for controller operations (#311)

As always, a huge thank you to all the contributors and maintainers for keeping the project going :heart:

6 Likes

What’s the plan/timeline for the next release?

Currently the 3.10.0 release is missing proper handling of write/read validations for readOnly and writeOnly json schema fields. I see in latest that that logic has been included.

Are there any examples for using your library in a pure plug environment? Or is phoenix always expected?

Yes there’s a sample plug application in the repo: open_api_spex/examples/plug_app at master · open-api-spex/open_api_spex · GitHub

The newer ControllerSpecs DSL should work with plain old plugs, but that example app was built with the original API where each plug exports an open_api_operation/1 callback to describe itself.

1 Like

Thanks! Sorry for bothering you instead of looking through your examples first. :drooling_face:

1 Like

Version 3.11.0 has been released!

  • Docs: Fix Application.spec/2 example in README #344
  • Docs: Misc doc changes (#355)
  • Docs: JsonApiErrorResponse vs JsonErrorResponse (#385)
  • Enhancement: Allow casting params where parameter.content schema is a Reference (#356)
  • Enhancement: external_docs via controller @doc and @moduledoc or ControllerSpecs DSL (#329)
  • Enhancement: Add optional header in opts to Operation.response (#332)
  • Enhancement: Add callback support to operation_spec (#345)
  • Enhancement: Adding helpers to OpenApiSpex.TestAssertions (#343)
  • Enhancement: Collect all errors occurred during cast properties (#354)
  • Enhancement: Add support for multiple specs for the same Phoenix router (#369)
  • Enhancement: updated swagger-ui to 3.34.0 (#378)
  • Fix casting additionalProperties (#386)
  • Fix JsonErrorResponse schema definition (#383)
  • Fix: test for cast of query parameters with style: form and explode: false (#364)
  • Fix: any_of cast for multiple schemas (#366)
  • Fix: Handle oneOf cast when there are multiple success along with failure (#362)
  • Fix: Casting of additionalProperties with references (#360)
  • Fix: Schema.example/1 for schema module (#358)
  • Fix: Stop circular dependency by injecting the schema into list of already processed schemas (#352)
  • Fix: Cast default for referenced schema (#337)
  • Fix: don’t json encode swagger-ui methods (#325)
  • Fix: relax requirement on poison preventing version conflicts in library usage (#322)
  • Fix: Allow top level security to apply to operations #321
  • Fix: return error tuple when discriminator cast fails (#393)
  • Infrastructure: Run Elixir CI with GitHub Actions (#347)

As always, a huge thank you to all the contributors and maintainers for keeping the project going :heart:

3 Likes

Hello,

I’ve got a question regarding the use of :minimum.

I’m using

   plug OpenApiSpex.Plug.CastAndValidate, json_render_error_v2: true

for implicit validation on my Phoenix requests.

If you happen to define a schema like in:

defmodule MyAppWeb.ApiSpec.Quantity do
  alias OpenApiSpex.Schema
  require OpenApiSpex

  OpenApiSpex.schema(%{
    type: :object,
    properties: %{
      quantity: %Schema{type: :integer, minimum: 1, description: "Quantity requested"}
    }
  })
end

you may get different types of error for say a request body containing %{quantity: 0} depending on how you use this schema.

E.g. While using :oneOf like in:

defmodule MyAppWeb.ApiSpec.Items do
  alias OpenApiSpex.Schema
  require OpenApiSpex

  OpenApiSpex.schema(%{
    type: :object,
    properties: %{
        items: %Schema{oneOf: [MyAppWeb.ApiSpec.Quantity, ...]}
    }
  })
end

you will get:

[%{“detail” => “Failed to cast value to one of: no schemas validate”, “source” => %{“pointer” => “/items”}, “title” => “Invalid value”}]

But if you try to use it directly, like in:

defmodule MyAppWeb.ApiSpec.Items do
  alias OpenApiSpex.Schema
  require OpenApiSpex

  OpenApiSpex.schema(%{
    type: :object,
    properties: %{
        items: MyAppWeb.ApiSpec.Quantity
    }
  })
end

then you will get a nicer message:

[%{“detail” => “0 is smaller than inclusive minimum 1”, “source” => %{“pointer” => “/items/quantity”}, “title” => “Invalid value”}]

So, if you have multiple schemas to check in your :oneOf, your request will basically fail because it won’t match, but you won’t know why.
Can this be avoided?

Thanks

Hi @jgallinari, this is a limitation of the way errors are calculated and represented for polymorphic types such as oneOf. OpenApiSpex will need to be enhanced to carry forward errors from the child type up through the parent type. Feel free to submit a feature request on the Github page: GitHub - open-api-spex/open_api_spex: Open API Specifications for Elixir Plug applications.